Симулированное выполнение перенаправлений

Вопрос или проблема

Моя оболочка — это Korn Shell, но я думаю, что проблема (и ее возможное решение) касается и других оболочек.

Обычно я встраиваю “режим симуляции” в свои скрипты, чтобы протестировать потенциально разрушительные/изменяющие состояние команды заранее. Вот так:

# export SIMULATE='print -'
[...]
$SIMULATE /path/to/hazardous_command

Когда первая строка не закомментирована, команда не выполняется, а только выводится.

Проблема, с которой я столкнулся, заключается в том, что если команда включает в себя перенаправление, это не сработает:

$SIMULATE /path/to/hazardous_command > /path/to/file 2>/path/to/other_file

Есть ли какое-нибудь элегантное(!) решение, о котором я не подумал? Я знаю, что мог бы сделать:

if [ -n "$SIMULATE" ] ; then
    $SIMULATE "/path/to/hazardous_command > /path/to/file 2>/path/to/other_file"
else
    /path/to/hazardous_command > /path/to/file 2>/path/to/other_file
fi

но это не делает код более понятным, и я предпочел бы какое-то “плагинное” решение, хотя до сих пор мне это не удалось.

Я также думал о (раскомментируйте одно из операторов export):

# export SIMULATE='eval '
# export SIMULATE='print -'
[...]
$SIMULATE "/path/to/hazardous_command >/path/to/file 2>/path/to/other_file"

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

Итак, есть ли у кого-то идеи, как это преодолеть?

В основном, вам нужно сказать оболочке, чтобы она не выполняла код.

Вы можете сделать что-то вроде

alias start_simulate= end_simulate=
# alias start_simulate="cat<<"end_simulate""

start_simulate
/path/to/hazardous_command >/path/to/file 2>/path/to/other_file
end_simulate

Обратите внимание, что после start_simulate ничего не должно следовать, а end_simulate должно быть на своей строке.

Или:

if simulating; then
  alias 'simulate_eval=print -r --'
else
  alias simulate_eval=eval
fi
simulate_eval '/path/to/hazardous_command >/path/to/file 2>/path/to/other_file'

Ваш $SIMULATE имеет несколько проблем:

  • print по умолчанию расширяет \ символы escape, вам нужен -r, чтобы этого избежать.
  • export предназначен для передачи переменной в окружение выполняемых команд, это мало имеет смысла здесь, если только вы не выполняете другие ksh команды, которые будут интерпретировать код, использующий $SIMULATE.
  • $SIMULATE при отсутствии кавычек в контексте списка подвержен разделению+глобу, поэтому его поведение зависит от текущего значения $IFS. Чтобы переменная хранила более одного элемента, вы используете массив (установленный с помощью set -A simulate print -r -- в ksh88, также simulte=(print -r --) в ksh93 а-ля zsh, а затем использованного как "${simulate[@]}" (обратите внимание на кавычки, которые важны для предотвращения разделения+глоба). Здесь функция или псевдоним имели бы больше смысла, чем переменная.

Я решаю эту проблему так:

вместо использования $SIMULATE, печатайте команды, которые нужно выполнить, вместо этого;
затем считайте команды, и если они вам нравятся, снова их напечатайте,
но перенаправьте их в sh…

Итак,

измените это,

if [ -n "$SIMULATE" ] ; then
    $SIMULATE "/path/to/hazardous_command > /path/to/file 2>/path/to/other_file"
else
    /path/to/hazardous_command > /path/to/file 2>/path/to/other_file
fi

На это,

    ## печатайте команды перед их запуском
    #
    cmd {
      echo  '/path/to/haz_command > /path/to/o2 2>/path/to/o3'  > /dev/stdout
    }

      >> ./cmd    
печатает>> /path/to/haz_command > /path/to/o2 2>/path/to/o3
      >> ./cmd | sh

запускает haz_command с выводом сюда туда...

Хотя, попробовав аналогичный подход, шаблон дизайна ‘долларовый знак $DEBUG’, я рекомендую печатать и просматривать команды перед их передачей в оболочку, потому что это позволяет легко проверить специальные символы, экранирования и т. д.

Эндрю

Ответ или решение

Симуляция выполнения команд с перенаправлениями в Korn Shell: Элегантные решения для разработки скриптов

Вам необходимо реализовать "симуляцию" выполнения команды в среде Korn Shell (ksh), чтобы избежать потенциального выполнения разрушительных команд. Однако сложности возникают, когда команда включает перенаправления (например, результаты выполнения команды должны записываться в файл). В этом ответе мы рассмотрим несколько элегантных решений для этой проблемы, предложим альтернативные подходы и обратим внимание на некоторые мелкие детали, которые могут сыграть важную роль.

Проблема с перенаправлениями

Проблемы, с которыми вы сталкиваетесь при использовании переменной SIMULATE, заключаются в том, что при попытке вывести команду с перенаправлениями, shell не экранирует их должным образом. Например:

$SIMULATE /path/to/hazardous_command > /path/to/file 2>/path/to/other_file

Вместо желаемого вывода, эти перенаправления будут интерпретированы shell и могут привести к нежелательным эффектам.

Элегантное решение через функции и псевдонимы

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

Пример 1: Использование функции

Вместо переменной SIMULATE, создайте функцию, которая будет обрабатывать команды:

simulate_command() {
    if [ -n "$SIMULATE" ]; then
        echo "$@"
    else
        "$@"
    fi
}

# Настройка симуляции
export SIMULATE='true'

# Использование функции
simulate_command /path/to/hazardous_command > /path/to/file 2>/path/to/other_file

В данном примере, если SIMULATE установлено в true, команда будет напечатана вместо выполнения. В противном случае будет выполнена настоящая команда с перенаправлениями.

Пример 2: Использование псевдонимов

Еще один подход заключается в использовании псевдонимов для более управляемого вывода:

alias simulate_eval='print -r --'

# Использование псевдонима
if [ -n "$SIMULATE" ]; then
    simulate_eval "/path/to/hazardous_command > /path/to/file 2> /path/to/other_file"
else
    /path/to/hazardous_command > /path/to/file 2>/path/to/other_file
fi

Псевдоним simulate_eval будет использовать print -r --, который предотвращает интерпретацию специальных символов.

Альтернативный подход: Чтение и выполнение команд

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

log_command() {
    echo "$@" >> /dev/stdout
    if [ -z "$SIMULATE" ]; then
        "$@"
    fi
}

# Пример использования
log_command /path/to/hazardous_command > /path/to/file 2> /path/to/other_file

Этот метод позволяет вам видеть, какие команды будут выполнены, прежде чем они будут по-настоящему вызваны.

Заключение

В результате, для эффективной симуляции выполнения команд с перенаправлениями в Korn Shell, применение функций и псевдонимов предоставляет более изящные и управляемые решения. Выбор наиболее подходящего подхода зависит от конкретных требований вашего сценария. Применив предложенные методы, вы сможете улучшить читаемость вашего кода и снизить шансы на возникновение ошибок при выполнении команд в процессе разработки.

Оцените материал
Добавить комментарий

Капча загружается...