Как отобразить команды оболочки при их выполнении - PullRequest
740 голосов
/ 18 мая 2010

Как в сценарии оболочки отобразить все вызванные команды оболочки и развернуть имена любых переменных?

Например, с учетом следующей строки:

ls $DIRNAME

Я бы хотел, чтобы скрипт запускал команду и отображал следующее

ls /full/path/to/some/dir

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

Ответы [ 14 ]

837 голосов
/ 18 мая 2010

set -x или set -o xtrace расширяет переменные и печатает маленький знак + перед строкой.

set -v или set -o verbose не расширяет переменные перед печатью.

Используйте set +x и set +v для отключения вышеуказанных настроек.

В первой строке скрипта можно поставить #!/bin/sh -x (или -v), чтобы иметь тот же эффект, что и set -x (или -v) позже в скрипте.

Выше также работает с /bin/sh.

См. Вики bash-hackers в set атрибутах и в отладке .

$ cat shl
#!/bin/bash                                                                     

DIR=/tmp/so
ls $DIR

$ bash -x shl 
+ DIR=/tmp/so
+ ls /tmp/so
$
275 голосов
/ 18 мая 2010

set -x даст вам то, что вы хотите.

Вот пример сценария оболочки для демонстрации:

#!/bin/bash
set -x #echo on

ls $PWD

Это расширяет все переменные и печатает полные команды перед выводом команды.

выход:

+ ls /home/user/
file1.txt file2.txt
81 голосов
/ 05 декабря 2012

Вы также можете переключать это для выбранных строк в вашем скрипте, заключая их в set -x и set +x например,

#!/bin/bash
...
if [[ ! -e $OUT_FILE ]];
then
   echo "grabbing $URL"
   set -x
   curl --fail --noproxy $SERV -s -S $URL -o $OUT_FILE
   set +x
fi
71 голосов
/ 28 апреля 2014

Я использую функцию для вывода, затем запускаю команду

#!/bin/bash
#function to display commands
exe() { echo "\$ $@" ; "$@" ; }

exe echo hello world

Какие выходы

$ echo hello world
hello world

Edit:

Для более сложных командных каналов и т. Д. Вы можете использовать eval:

#!/bin/bash
#function to display commands
exe() { echo "\$ ${@/eval/}" ; "$@" ; }

exe eval "echo 'Hello World' | cut -d ' ' -f1"

Какие выходы

$  echo 'Hello World' | cut -d ' ' -f1
Hello
47 голосов
/ 16 октября 2013

ответ shuckc на вывод выбранных строк имеет несколько недостатков: в конечном итоге вы также получаете эхом команду set +x и теряете возможность тестировать код выхода с помощью $?, поскольку он перезаписывается set +x.

Другой вариант - запустить команду в подоболочке:

echo "getting URL..."
( set -x ; curl -s --fail $URL -o $OUTFILE )

if [ $? -eq 0 ] ; then
    echo "curl failed"
    exit 1
fi

, который даст вам вывод как:

getting URL...
+ curl -s --fail http://example.com/missing -o /tmp/example
curl failed

Однако это создает дополнительные затраты на создание новой подоболочки для команды.

33 голосов
/ 13 мая 2013

Другой вариант - поставить «-x» в верхней части скрипта, а не в командной строке:

$ cat ./server
#!/bin/bash -x
ssh user@server

$ ./server
+ ssh user@server
user@server's password: ^C
$

(Недостаточно повторений, чтобы прокомментировать выбранный ответ.)

19 голосов
/ 01 декабря 2015

Согласно TLDP Руководство по Bash для начинающих: Глава 2. Написание и отладка сценариев

2.3.1. Отладка всего скрипта

$ bash -x script1.sh

...

Теперь для Bash доступен полноценный отладчик, доступный по адресу SourceForge . Эти функции отладки доступны в большинстве современных версий Bash, начиная с 3.x.

2.3.2. Отладка части (частей) скрипта

set -x            # activate debugging from here
w
set +x            # stop debugging from here

...

Таблица 2-1. Обзор установленных опций отладки

Short  | Long notation | Result  
-------+---------------+--------------------------------------------------------------
set -f | set -o noglob | Disable file name generation using metacharacters (globbing).  
set -v | set -o verbose| Prints shell input lines as they are read.  
set -x | set -o xtrace | Print command traces before executing command.  

...

В качестве альтернативы, эти режимы могут быть указаны в самом скрипте, добавление нужных опций в первую строку объявления оболочки. Опции можно комбинировать, как это обычно бывает с командами UNIX:

#!/bin/bash -xv
17 голосов
/ 15 марта 2014

Введите «bash -x» в командной строке перед именем сценария bash. Например, чтобы выполнить foo.sh, введите:

bash -x foo.sh
8 голосов
/ 05 сентября 2017

Вы можете выполнить скрипт bash в режиме отладки с опцией -x .
Это отобразит все команды.

bash -x example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt


Вы также можете сохранить параметр -x в скрипте . Просто укажите опцию -x в шебанге.

######## example_script.sh ###################
#!/bin/bash -x

cd /home/user
mv text.txt mytext.txt

##############################################

./example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt



5 голосов
/ 08 июня 2016

Кто-то выше разместил:

#!/bin/bash
#function to display commands
exe() { echo "\$ $@" ; "$@" ; }

и это выглядит многообещающе, но я никак не могу понять, что это делает. Я гуглил и искал на странице man bash "\ $" и "$ @", и не нашел абсолютно ничего .

Я понимаю, что создается функция с именем "exec ()". Я понимаю, что фигурные скобки обозначают начало и конец функции. Думаю, я понимаю, что точка с запятой отмечает «жесткий возврат» между многострочными командами, так что '{echo "\ $ $ @"; "$ @"; } 'становится, по сути:

{
echo "\$ $@"
"$@"

}

Может ли кто-нибудь дать мне краткое объяснение или где найти эту информацию, поскольку, очевидно, мое гугл-фу меня подводит?

(Не имея смысла начинать новый вопрос со старого потока, моя цель состоит в том, чтобы перенаправить вывод в файл. Метод "set -x; [команды]; set + x" будет работать для меня достаточно хорошо, но Я не могу понять, как выводить результаты в файл, а не на экран, поэтому я пытался понять этот другой метод в надежде, что смогу использовать очень плохое понимание перенаправления / pipe / tee / etc, чтобы сделать то же самое .)

Спасибо!

ПОСЛЕДНЕЕ РЕДАКТИРОВАНИЕ:

С некоторой переделкой, я думаю, я понял это. Вот мой эквивалентный код для того, что мне нужно:

SCRIPT_LOG="\home\buddy\logfile.txt"
exe () {
  params="$@"                       # Put all of the command-line into "params"
  printf "%s\t$params" "$(date)" >> "$SCRIPT_LOG"   # Print the command to the log file
  $params                           # Execute the command
}

exe rm -rf /Library/LaunchAgents/offendingfile
exe rm -rf /Library/LaunchAgents/secondoffendingfile

Результаты в файле logfile.txt выглядят примерно так:

Tue Jun  7 16:59:57 CDT 2016  rm -rf /Library/LaunchAgents/offendingfile
Tue Jun  7 16:59:57 CDT 2016  rm -rf /Library/LaunchAgents/secondoffendingfile

Как раз то, что мне было нужно. Спасибо!

...