如何在执行 shell 命令时回显它们
在 shell 脚本中,如何回显所有调用的 shell 命令并展开任何变量名称?
例如,给定以下行:
ls $DIRNAME
我希望脚本运行该命令并显示以下内容
ls /full/path/to/some/dir
目的是保存调用的所有 shell 命令及其参数的日志。也许有更好的方法来生成这样的日志吗?
In a shell script, how do I echo all shell commands called and expand any variable names?
For example, given the following line:
ls $DIRNAME
I would like the script to run the command and display the following
ls /full/path/to/some/dir
The purpose is to save a log of all shell commands called and their arguments. Is there perhaps a better way of generating such a log?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
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 的 wiki,了解
设置
属性,以及调试。set -x
orset -o xtrace
expands variables and prints a little + sign before the line.set -v
orset -o verbose
does not expand the variables before printing.Use
set +x
andset +v
to turn off the above settings.On the first line of the script, one can put
#!/bin/sh -x
(or-v
) to have the same effect asset -x
(or-v
) later in the script.The above also works with
/bin/sh
.See the bash-hackers' wiki on
set
attributes, and on debugging.set -x
会给你你想要的。下面是一个用于演示的 shell 脚本示例:
这会展开所有变量并在命令输出之前打印完整命令。
输出:
set -x
will give you what you want.Here is an example shell script to demonstrate:
This expands all variables and prints the full commands before output of the command.
Output:
我使用一个函数来回显并运行命令:
whichoutputs
对于更复杂的命令管道等,您可以使用 eval:
whichoutputs
I use a function to echo and run the command:
Which outputs
For more complicated commands pipes, etc., you can use eval:
Which outputs
您还可以通过将脚本中的选定行包装在
set -x
和set +x
中来切换此功能,例如,You can also toggle this for select lines in your script by wrapping them in
set -x
andset +x
, for example,shuckc 的答案用于回显选择行有一些缺点:您最终会回显以下
set +x
命令,并且您无法使用$?
测试退出代码,因为它会被set +x
覆盖。另一种选择是在子 shell 中运行该命令:
这将为您提供如下输出:
不过,这确实会产生为该命令创建新子 shell 的开销。
shuckc's answer for echoing select lines has a few downsides: you end up with the following
set +x
command being echoed as well, and you lose the ability to test the exit code with$?
since it gets overwritten by theset +x
.Another option is to run the command in a subshell:
which will give you output like:
This does incur the overhead of creating a new subshell for the command, though.
根据 TLDP 的 Bash 初学者指南:第 2 章。编写和调试脚本:
According to TLDP's Bash Guide for Beginners: Chapter 2. Writing and debugging scripts:
您可以使用
-x
选项在调试模式下执行 Bash 脚本。这将回显所有命令。
您还可以将 -x 选项保存在脚本中。只需在 shebang 中指定
-x
选项即可。You can execute a Bash script in debug mode with the
-x
option.This will echo all the commands.
You can also save the -x option in the script. Just specify the
-x
option in the shebang.另一种选择是将“-x”放在脚本顶部而不是命令行上:
Another option is to put "-x" at the top of your script instead of on the command line:
结合所有的答案,我发现这是最好、最简单的
{ set +x; 2>/dev/null
来自 https://stackoverflow.com/a/19226038/8608146如果需要命令的退出状态,如此处
使用
稍后使用
$STATUS
就像最后的exit $STATUS
稍微有用的一个
Combining all the answers I found this to be the best, simplest
{ set +x; } 2>/dev/null
from https://stackoverflow.com/a/19226038/8608146If the exit status of the command is needed, as mentioned here
Use
And use the
$STATUS
later likeexit $STATUS
at the endA slightly more useful one
在命令行中,在 Bash 脚本名称之前键入“bash -x”。例如,要执行 foo.sh,请输入:
Type "bash -x" on the command line before the name of the Bash script. For instance, to execute foo.sh, type:
对于 zsh、echo
以及调试,
For zsh, echo
And for debugging,
为了允许回显复合命令,我使用
eval
加上 Soth 的exe
函数来回显并运行命令。这对于管道命令很有用,否则这些命令将只显示任何内容或仅显示管道命令的初始部分。不带 eval:
输出:
带 eval:
输出
To allow for compound commands to be echoed, I use
eval
plus Soth'sexe
function to echo and run the command. This is useful for piped commands that would otherwise only show none or just the initial part of the piped command.Without eval:
Outputs:
With eval:
Which outputs
按照Soth的答案。
可以创建不突出显示的 Markdown 输出(未给出语言)
脚本
输出
让我们从 in.mp4 中获取随机关键帧:
$$ kfn=20
kf=$(ffprobe -v error -select_streams v -show_frames -print_format csv in.mp4 | grep 'frame,video,0,1' | head -20 | tail -1 | perl -pe 's|frame,video,0,1,. ?),.*|\1|')
$$ kf=3.803792
让我们选择 3.803792 处的关键帧。以下是 in.mp4 中该关键帧周围所有帧的时间戳。
$$ ffprobe -v 错误 -select_streams v -show_frames -print_format csv in.mp4 | perl -pe 's|帧,视频,0,(.*?),.*?,(.*?),.*|\2 \1|' | perl -pe 's|(.*?) 1|\1\tKF|' | perl -pe 's|(.*?) 0|\1|' |grep -A 5 -B 5 --颜色 3.803792
Following the answer of Soth.
It is possible to create a markdown output without highlight (no language given)
script
Output
Lets take a random keyframe from in.mp4:
$$ kfn=20
kf=$(ffprobe -v error -select_streams v -show_frames -print_format csv in.mp4 | grep 'frame,video,0,1' | head -20 | tail -1 | perl -pe 's|frame,video,0,1,.?,(.?),.*|\1|')
$$ kf=3.803792
Lets select keyframe at 3.803792. Here are the timestamps of the all the frames from in.mp4 around this keyframe.
$$ ffprobe -v error -select_streams v -show_frames -print_format csv in.mp4 | perl -pe 's|frame,video,0,(.*?),.*?,(.*?),.*|\2 \1|' | perl -pe 's|(.*?) 1|\1\tKF|' | perl -pe 's|(.*?) 0|\1|' |grep -A 5 -B 5 --color 3.803792
对于
csh
和tcsh
,您可以set verbose
或set echo
(或者您甚至可以同时设置两者,但它大多数时候可能会导致一些重复)。verbose
选项几乎可以打印您键入的确切 shell 表达式。echo
选项更能说明通过生成将执行的内容。http://www.tcsh.org/tcsh.html/Special_shell_variables.html#详细
http://www.tcsh.org/tcsh.html /Special_shell_variables.html#echo
特殊 shell 变量
详细
如果设置,则在历史替换(如果有)之后打印每个命令的单词。通过-v命令行选项设置。
echo
如果设置,则每个命令及其参数在执行之前都会被回显。对于非内置命令,所有扩展都在回显之前发生。在命令和文件名替换之前会回显内置命令,因为这些替换是有选择地完成的。通过 -x 命令行选项设置。
For
csh
andtcsh
, you canset verbose
orset echo
(or you can even set both, but it may result in some duplication most of the time).The
verbose
option prints pretty much the exact shell expression that you type.The
echo
option is more indicative of what will be executed through spawning.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.
如果您只想记录特定命令,而不是每一行,
set -x
有点难以使用。但是您可以使用此函数来打印任何命令,前缀为$
:用法:
将
printf
与%q
格式说明符一起使用可确保输出的打印方式适合复制并粘贴到 shell 中,即使存在空格或其他特殊字符也是如此。它似乎使用\
转义空格而不是添加引号,但输出确实正确地表示了实际正在运行的内容。If you want to log only specific commands, rather than every single line,
set -x
is somewhat difficult to use. But you can use this function to print any command, prefixed with$
:Usage:
Using
printf
with the%q
format specifier makes sure that the output is printed in a way suitable for copying and pasting into a shell, even in the presence of spaces or other special characters. It seems to escape spaces using\
rather than adding quotes, but the output does correctly represent what's actually being run.我使用以下内容来准确控制我想要看到的内容:
扩展变量的关键是使用双引号。单引号不会扩展。
我有时使用“logger”而不是“echo”发送到 /var/log/syslog,因为它们通常以非交互方式运行。
I use the following to control exactly what I want to see:
The key to expand a variable is to use double quote. Single quote would not expand.
I sometimes use "logger" instead of "echo" to send to /var/log/syslog since they are often run non-interactively.
输出如下:
Output is as follows: