Получить содержимое расширенного выражения, переданного eval, через внутренние компоненты Bash

Я пишу некоторые функции оболочки, которые позволяют печатать трассировку стека при возникновении ошибок. Для этого я использую массив BASH_LINENO, который содержит номер строки для каждого кадра. Затем я извлекаю строку из файла, используя массив BASH_SOURCE и подпроцесс, например line = "$(tail -n+$lineno "$file" | head -n1)".

В любом случае, это работает хорошо, за исключением случаев, когда ошибка возникает внутри eval. Проблема в том, что номер строки соответствует строке после, выражение, данное eval, было расширено. Поэтому, когда я получаю строку с головой и хвостом, очевидно, что это не та строка, или это вообще не строка (lineno превосходит количество строк в файле).

Поэтому мне интересно, как я мог получить фактическую расширенную строку. Я просмотрел переменные, предоставленные Bash, но в этом случае, похоже, ничего не помогает.

Пример, script1.sh:

#!/usr/bin/env bash
eval "$(./script2.sh)"

script2.ш:

#!/usr/bin/env bash
echo
echo
echo
echo false

Когда я нажимаю строку false при выполнении script1.sh, номер строки, который я получаю, равен 4, а источник файла, который я получаю, — script1.sh, так что это неправильно.

Когда строка отсутствует в файле, я мог бы обнаружить это и вместо этого напечатать первую предыдущую строку eval, но это очень сложно, и я уверен, что есть несколько разных случаев, которые нужно обработать. А если строка внутри файла, то я даже не могу знать, правильная она или нет.

eval это ад :'(

В идеале BASH_COMMAND также должен быть массивом, и я мог бы извлекать из него команды вместо чтения файлов.

Еще одна идея, которую я только что придумал, заключалась в том, чтобы заставить пользователя передать результат выражения в команду, которая будет сжимать его в одну строку. Любые идеи, как или программы для этого? Простое соединение на ";" кажется наивным (опять же, много крайних случаев).

P.S.: извините за название, мне трудно дать осмысленное название этому :/

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
33
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В конце концов я нашел обходной путь: переопределив команду eval своей собственной функцией, я смог изменить способ печати трассировки стека для ошибок, возникающих в операторах eval.

eval() {
    # pre eval logic
    command eval "$@"
    # post eval logic
}

В любом случае, пожалуйста, не используйте eval, а если используете, используйте аргументы только в одну строку:

# GOOD: "easy" to deal with
for i in ...; do
    eval "$(some command)"
done

# BAD: this will mess up your line numbers
eval "$(for i in ...; do
    some command $i
done)"

Другие вопросы по теме