在 shell 脚本中,如何回显所有调用的 shell 命令并扩展任何变量名?
例如,给定以下行:
ls $DIRNAME
我希望脚本运行命令并显示以下内容
ls /full/path/to/some/dir
目的是保存所有调用的 shell 命令及其参数的日志。是否有更好的方法来生成这样的日志?
set -x
或set -o xtrace
扩展变量并在行前打印一个小 + 号。
set -v
或set -o verbose
在打印前不展开变量。
使用set +x
和set +v
关闭上述设置。
在脚本的第一行,可以将#!/bin/sh -x
(or ) 放在后面的脚本中与( or -v
) 具有相同的效果。set -x
-v
以上也适用于/bin/sh
.
请参阅 bash-hackers 的关于set
属性和调试的 wiki 。
$ cat shl
#!/bin/bash
DIR=/tmp/so
ls $DIR
$ bash -x shl
+ DIR=/tmp/so
+ ls /tmp/so
$
set -x
会给你你想要的。
这是一个示例 shell 脚本来演示:
#!/bin/bash
set -x #echo on
ls $PWD
这会扩展所有变量并在命令输出之前打印完整的命令。
输出:
+ ls /home/user/
file1.txt file2.txt
我使用一个函数来回显并运行命令:
#!/bin/bash
# Function to display commands
exe() { echo "\$ $@" ; "$@" ; }
exe echo hello world
哪个输出
$ echo hello world
hello world
对于更复杂的命令管道等,可以使用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
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
shuckc回显选择行的答案有一些缺点:您最终set +x
也会回显以下命令,并且您将失去测试退出代码的能力,$?
因为它被set +x
.
另一种选择是在子shell中运行命令:
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
不过,这确实会产生为命令创建新子 shell 的开销。
根据TLDP的Bash Guide for Beginners:第 2 章编写和调试脚本:
2.3.1。调试整个脚本
$ bash -x script1.sh
...
现在有一个成熟的 Bash 调试器,可在SourceForge获得。从 3.x 开始,大多数现代版本的 Bash 都提供了这些调试功能。
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.
...
或者,可以在脚本本身中指定这些模式,方法是在第一行 shell 声明中添加所需的选项。可以组合选项,就像 UNIX 命令通常的情况一样:
#!/bin/bash -xv
另一种选择是将“-x”放在脚本顶部而不是命令行:
$ cat ./server
#!/bin/bash -x
ssh user@server
$ ./server
+ ssh user@server
user@server's password: ^C
$
您可以使用选项在调试模式下执行Bash 脚本。-x
这将回显所有命令。
bash -x example_script.sh
# Console output
+ cd /home/user
+ mv text.txt mytext.txt
您还可以在脚本中保存 -x 选项。只需-x
在 shebang 中指定选项即可。
######## 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
在 Bash 脚本名称之前的命令行中键入“bash -x”。例如,要执行 foo.sh,请键入:
bash -x foo.sh
结合所有答案,我发现这是最好的,最简单的
# https://stackoverflow.com/a/64644990/8608146
exe(){
set -x
"$@"
{ set +x; } 2>/dev/null
}
# example
exe go generate ./...
{ set +x; } 2>/dev/null
来自https://stackoverflow.com/a/19226038/8608146
如果需要命令的退出状态,这里提到
利用
{ STATUS=$?; set +x; } 2>/dev/null
并在最后使用$STATUS
后者exit $STATUS
一个稍微有用的
# https://stackoverflow.com/a/64644990/8608146
_exe(){
[ $1 == on ] && { set -x; return; } 2>/dev/null
[ $1 == off ] && { set +x; return; } 2>/dev/null
echo + "$@"
"$@"
}
exe(){
{ _exe "$@"; } 2>/dev/null
}
# examples
exe on # turn on same as set -x
echo This command prints with +
echo This too prints with +
exe off # same as set +x
echo This does not
# can also be used for individual commands
exe echo what up!
对于 zsh,回显
setopt VERBOSE
而对于调试,
setopt XTRACE
为了允许回显复合命令,我使用eval
plus Soth 的exe
函数来回显并运行命令。这对于管道命令很有用,否则这些命令将只显示不显示或仅显示管道命令的初始部分。
没有评估:
exe() { echo "\$ $@" ; "$@" ; }
exe ls -F | grep *.txt
输出:
$
file.txt
使用评估:
exe() { echo "\$ $@" ; "$@" ; }
exe eval 'ls -F | grep *.txt'
哪个输出
$ exe eval 'ls -F | grep *.txt'
file.txt
对于csh
and tcsh
,您可以set verbose
或set echo
(或者您甚至可以同时设置两者,但大多数情况下可能会导致一些重复)。
该verbose
选项几乎可以打印您键入的确切 shell 表达式。
该echo
选项更能说明将通过生成执行的操作。
http://www.tcsh.org/tcsh.html/Special_shell_variables.html#verbose
http://www.tcsh.org/tcsh.html/Special_shell_variables.html#echo
Special shell variables
verbose
If set, causes the words of each command to be printed, after history substitution (if any). Set by the -v command line option.
echo
If set, each command with its arguments is echoed just before it is executed. For non-builtin commands all expansions occur before echoing. Builtin commands are echoed before command and filename substitution, because these substitutions are then done selectively. Set by the -x command line option.