- Вопрос или проблема
- Ответ или решение
- Симуляция выполнения команд с перенаправлениями в Korn Shell: Элегантные решения для разработки скриптов
- Проблема с перенаправлениями
- Элегантное решение через функции и псевдонимы
- Пример 1: Использование функции
- Пример 2: Использование псевдонимов
- Альтернативный подход: Чтение и выполнение команд
- Заключение
Вопрос или проблема
Моя оболочка — это 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, применение функций и псевдонимов предоставляет более изящные и управляемые решения. Выбор наиболее подходящего подхода зависит от конкретных требований вашего сценария. Применив предложенные методы, вы сможете улучшить читаемость вашего кода и снизить шансы на возникновение ошибок при выполнении команд в процессе разработки.