如何执行shell命令?

Jac*_*ock 812 bash shell trace posix sh

在shell脚本中,如何回显所有调用的shell命令并展开任何变量名?例如,给定以下行:

ls $DIRNAME
Run Code Online (Sandbox Code Playgroud)

我希望脚本运行该命令并显示以下内容

ls /full/path/to/some/dir
Run Code Online (Sandbox Code Playgroud)

目的是保存所有调用的shell命令及其参数的日志.也许有更好的方法来生成这样的日志?

Tom*_*Tom 918

set -xset -o xtrace扩展变量并在行前打印一个小+符号.

set -v或者set -o verbose在打印前不扩展变量.

使用set +xset +v关闭上述设置.

在脚本的第一行,可以使#!/bin/sh -x(或-v)在脚本中稍后具有与set -x(或-v)相同的效果.

以上也适用/bin/sh.

http://www.faqs.org/docs/abs/HTML/options.html

$ cat shl
#!/bin/bash                                                                     

DIR=/tmp/so
ls $DIR

$ bash -x shl 
+ DIR=/tmp/so
+ ls /tmp/so
$
Run Code Online (Sandbox Code Playgroud)

  • 如果您还想查看正在执行的编号行,请参阅/sf/answers/1246356191/ (7认同)
  • 如果我希望它在回声时通过类似人声的语音合成器来唱歌每个命令,以便我可以从远处听到它的声音并欣赏音乐,该怎么办?也许以不同的声音表示输入和输出。 (4认同)
  • 如果要在回显以区分命令及其结果输出时给命令着色,该怎么办? (3认同)
  • `bash -x foo.sh` 是我需要的关键。(作为评论发布是因为在不修改脚本本身的情况下是否可以立即看出是否有效;它确实有效。) (3认同)
  • @LewisChan:您可以在命令中添加彩色静态或动态前缀 fe 时间戳,请参阅 /sf/answers/4383433631/ 。 (2认同)
  • @AndreasDietrich 谢谢。如果你真的找到了一种方法来实现我的笑话问题,那我就很开心了。最好有一些强大的 cli 工具并且只有几行代码。 (2认同)

rad*_*man 293

set -x 会给你你想要的.

这是一个示例shell脚本来演示:

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

ls $PWD
Run Code Online (Sandbox Code Playgroud)

这会扩展所有变量并在输出命令之前打印完整命令.

输出:

+ ls /home/user/
file1.txt file2.txt
Run Code Online (Sandbox Code Playgroud)

  • 使用"详细"这个词并不能完成任何事情.你可以做`set -o verbose`或`set -v`(只有"verbose")或`set -o xtrace`或`set -x`(只有"xtrace")或`set -xv`(两者)或者`set -o xtrace -o verbose`(两者). (21认同)

shu*_*ckc 84

您还可以通过在包装他们切换此为选线在你的脚本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
Run Code Online (Sandbox Code Playgroud)

  • 但是,脚本也会打印 `set +x` (9认同)
  • 提示:我们可以使用`{ set +x; } &> /dev/null` 使 `set +x` 输出静音。 (2认同)

Sot*_*oth 83

我使用函数来回显然后运行命令

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

exe echo hello world
Run Code Online (Sandbox Code Playgroud)

哪个输出

$ echo hello world
hello world
Run Code Online (Sandbox Code Playgroud)

编辑:

对于更复杂的命令管道等,您可以使用eval:

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

exe eval "echo 'Hello, World!' | cut -d ' ' -f1"
Run Code Online (Sandbox Code Playgroud)

哪个输出

$  echo 'Hello, World!' | cut -d ' ' -f1
Hello
Run Code Online (Sandbox Code Playgroud)

  • 这方面的一个主要缺点是输出丢失了引用信息.你无法区分`cp"foo bar"baz"和`cp foo"bar baz"`.因此,向用户显示进度信息是有益的; 调试输出或记录可重现命令的次数较少.不同的用例.在`zsh`中,你可以使用`:q`修饰符来保留引号:`exe(){echo'$'"$ {@:q}"; "$ @"; }` (11认同)
  • 如果您不想打印每个命令,这是最好的答案。它避免了关闭时的“++ set +x”输出,并且看起来更干净。不过,对于一两个语句,bhassel 使用子 shell 的答案是最方便的。 (3认同)
  • 我不喜欢这个答案。在很多情况下,您看到的不是您所得到的(特别是空格,引号,转义字符,变量/表达式替换等),因此请不要盲目地将echoed命令粘贴到终端中并假定它将运行以同样的方式。另外,第二种技术只是一种黑客手段,它将从您的命令中删除单词“ eval”的其他实例。因此,不要指望它可以在`exe eval“ echo'eval world'”`上正常工作! (2认同)

小智 51

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
Run Code Online (Sandbox Code Playgroud)

这会给你输出像:

getting URL...
+ curl -s --fail http://example.com/missing -o /tmp/example
curl failed
Run Code Online (Sandbox Code Playgroud)

但这确实会产生为命令创建新子shell的开销.

  • 避免`++ set + x`输出的好方法. (7认同)
  • 更好的是:取代`if [$?-eq 0]`with`if(set -x; COMMAND)`. (3认同)

小智 34

另一种选择是将"-x"放在脚本的顶部而不是命令行:

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

$ ./server
+ ssh user@server
user@server's password: ^C
$
Run Code Online (Sandbox Code Playgroud)

(对于所选答案的评论不足.)


Pha*_*vij 23

结合所有答案,我发现这是最好、最简单的

#!/bin/bash
# https://stackoverflow.com/a/64644990/8608146
exe(){
    set -x
    "$@"
    { set +x; } 2>/dev/null
}
# example
exe go generate ./...
Run Code Online (Sandbox Code Playgroud)

{ set +x; } 2>/dev/null来自/sf/answers/1345822691/

如果需要命令的退出状态,如此处所述

使用

{ STATUS=$?; set +x; } 2>/dev/null
Run Code Online (Sandbox Code Playgroud)

并在最后使用$STATUS稍后的内容exit $STATUS

稍微有用一点的

#!/bin/bash
# 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!
Run Code Online (Sandbox Code Playgroud)


Afr*_*ief 22

根据TLDPBash初学者指南:第2章编写和调试脚本

2.3.1.调试整个脚本

$ bash -x script1.sh
Run Code Online (Sandbox Code Playgroud)

...

现在有一个完整的Bash调试器,可以在SourceForge上找到.大多数现代版本的Bash都提供这些调试功能,从3.x开始.

2.3.2.调试脚本的部分内容

set -x            # Activate debugging from here
w
set +x            # Stop debugging from here
Run Code Online (Sandbox Code Playgroud)

...

表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.
Run Code Online (Sandbox Code Playgroud)

...

或者,可以在脚本本身中通过向第一行shell声明添加所需选项来指定这些模式.可以组合选项,通常是UNIX命令的情况:

#!/bin/bash -xv
Run Code Online (Sandbox Code Playgroud)


Ala*_*lan 17

在bash脚本的名称前面的命令行上键入"bash -x".例如,要执行foo.sh,请键入:

bash -x foo.sh
Run Code Online (Sandbox Code Playgroud)


Ren*_*Ren 9

您可以使用-x选项在调试模式下执行 bash脚本.这将回显所有命令.

bash -x example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt
Run Code Online (Sandbox Code Playgroud)


您还可以在脚本中保存-x选项.只需在shebang中指定-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
Run Code Online (Sandbox Code Playgroud)



  • 同样,`bash -vx`也可以做,但是没有变量插值 (2认同)

zza*_*per 5

对于 zsh,回显

setopt VERBOSE
Run Code Online (Sandbox Code Playgroud)

为了调试,

setopt XTRACE
Run Code Online (Sandbox Code Playgroud)