Как выводить команды в сценарии оболочки bash, но не выполнять их?

11

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

Допустим, у меня есть скрипт, удаляющий файл, имя которого хранится в переменной:

#!/bin/bash
set -v
FN="filename"
rm -f ${FN}

Добавление set -vбудет повторять следующие команды перед выполнением:

$ ./scr.sh
FN="filename"
rm -f ${FN}

Теперь я хочу увидеть поток этого скрипта без фактического удаления файла. Я хочу предотвратить любое влияние на внешнюю среду и файловую систему. Это возможно?

Я мог бы обернуть все команды с помощью echoкоманды, но это утомительно для длинного сценария.

ysap
источник
Я не эксперт по bash-скриптингу, но если бы я написал это на другом языке программирования, я бы сохранил все команды в массиве. таким образом, должно быть легко выполнить цикл и либо выполнить команды, либо распечатать.
Уго дер Хангриге

Ответы:

8

Нет способа пройтись по сценарию, чтобы увидеть, как он будет выполняться без этого. В вашем примере нет ifоператоров или циклов. Но в реальных сценариях часто встречается много условных операторов. Какая ветвь будет получена, часто зависит от того, что произошло, когда оболочка выполнила предыдущую команду. Если она не запускает команду, оболочка не может узнать, какой вывод она сгенерировала или какой код возврата был бы, от чего могла бы зависеть следующая условная ветвь или оператор присваивания.

Если дело в том, что вы хотите изучить скрипт и знать, что он делает, прежде чем запускать его, это неплохая идея. Но на самом деле, лучший способ сделать это - просто просмотреть файл с помощью lessили viили что-то подобное.

добавленной

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

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

Николь Гамильтон
источник
Спасибо. Меня удивит, если найдется способ, именно по той причине, о которой вы упомянули, но я все равно решил попробовать. Причина этого заключается в том, что я разрабатываю сценарий, который перемещает файлы на множество компьютеров в сети и выполняет некоторые действия на удаленных хостах. Я хотел бы увидеть поток сценария до фактической фиксации изменений в файловой системе (ах). Было бы так же утомительно
пройтись
1
Дополнение: для пошагового выполнения сценария вы можете запустить сценарий, с помощью trap read debugкоторого будет выполняться чтение после каждой выполненной строки, а затем можно медленно выполнить его, нажав клавишу ввода (это полезно, если у вас очень длинный сценарий и вы хотите проверить это в первый раз).
netigger
8

Я думаю, что вам придется повторить - однако, если вы поместите команду в переменную, вы можете включить и выключить ее. Кроме того, команда может быть функцией и настолько сложной, насколько вы хотите.

#!/bin/bash
echo 'Debug'
  D=echo
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy
echo $'\n\nLive'
  D=
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy

!$ > ./conditional.sh
Debug
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
rm -f testy
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy

Live -rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy ls: cannot access testy: No such file or directory

user191016
источник
Мне потребовались кавычки в командах echo / not-echo, а затем пришлось использовать D=evalв живой части. Но хороший ответ!
Джаспер
5

Вы отслеживаете поток, используя опцию -x для bash, но это все равно будет выполнять команды.

Лучшее, что вы можете сделать, это просто поставить echo или закомментировать команды, которые имеют внешние эффекты, такие как rm. По крайней мере, вам не нужно менять каждую строку.

parkydr
источник
Спасибо. Я упомянул этот вариант в своем вопросе, но он не решает мою проблему.
ysap
Извините, я думал, что вы хотели повторить каждую строку, -x уменьшит это до нескольких команд и покажет вам оценки.
parkydr
4

Я не знаю какого-либо конкретного метода для пробного запуска, но мы можем использовать некоторые меры предосторожности для понимания неизвестного сценария.

  1. Используйте среду chroot для запуска вашего сценария отладки. Он будет действовать как песочница и обеспечит защиту от удаления / изменения основных системных файлов.
  2. Используйте bash -n <script>для проверки синтаксиса . Из руководства gnu bash https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html

-n Read commands but do not execute them; this may be used to check a script for syntax errors. This option is ignored by interactive shells.

  1. Прочитайте сценарий хотя бы один раз. Вы можете использовать оператор echo для отладки, как указано в ответе пользователя191016 .
    • Обращайте внимание на подозрительный или опасный код.
    • например, связанные с rm, команды, влияющие на / dev / sda и т. д.
  2. Всегда старайтесь запускать сценарии от имени обычного пользователя, избегайте запуска неизвестных сценариев от имени пользователя root.
  3. Вы можете определить псевдоним для команды make, которая может изменять файлы как интерактивные при запуске вашего скрипта. Пример alias rm="rm -i" alias cp="cp -i" alias mv="mv -i" Для потоковых редакторов, таких как sed sed -i(-i изменяет файл на месте без -i, он выполняет пробный запуск для sed, проверьте страницу man для получения подробной информации). можно скопировать полную команду и запустить. Непосредственно перед самой командой будет отображаться вывод на экране, а затем используется команда для ожидания продолжения ввода пользователя. Пример sed -i <pattern> Заменить на sed <pattern> read -p "Press any key..." sed -i <pattern>

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

Рохит Радж Мишра
источник
3

Сделайте set –nили добавьте nк своей существующей set –vкоманде. Но так как это заставляет оболочку не оценивать какие-либо команды, даже не ifили while, вы можете не получить слишком хорошего представления о рабочем процессе.

Скотт
источник
Спасибо. Это хорошее начало, но, как вы упомянули, оно не позволяет мне увидеть реальный поток - где в моем реальном скрипте у меня есть цикл по списку удаленных хостов.
августа
3

Вот небольшая конструкция, которую я люблю использовать:

#!/bin/sh

verbose=false
really=true

# parse arguments
while [ $# -ge 1 ]
do
  case "$1" in
    -v) verbose=true ;;
    -n) really=false; verbose=true ;;
  esac
  shift
done

doCmd() {
  if $verbose; then echo "$@"; fi
  if $really; then "$@"; fi
}

doCmd make foo
doCmd rm -rf /tmp/installdir
doCmd mkdir /tmp/installdir
doCmd whatever
doCmd blah blah
Эдвард Фальк
источник
2

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

sudo -u nobody ./scr.sh

В вашем примере это будет выполнено FN="filename"как обычно. Хотя она технически выполняет и эту команду rm -f ${FN}, ничего не произойдет, если никто не имеет необходимых прав для удаления файла.

Конечно, это вызовет проблемы с условным рабочим процессом. Тот факт, что rmкоманда не выполнена, может повлиять на дальнейшие части сценария.

Деннис
источник
Вещи, которые мы никогда не поймем: почему root требуется для запуска как никто ...
mjohnsonengr
Пользователь "nobody" не относится к ОС, но вы можете добавить в файл sudoers запись, которая разрешает sudo без пароля для "nobody".
Деннис
Я не знаю. Кажется, что сценарий будет завершен из-за той или иной ошибки, прежде чем он завершится.
Эдвард Фальк