代码之家  ›  专栏  ›  技术社区  ›  Jack Nock

如何在执行shell命令时回显它们?

  •  690
  • Jack Nock  · 技术社区  · 16 年前

    在shell脚本中,如何回显所有调用的shell命令并展开任何变量名?

    例如,给定以下行:

    ls $DIRNAME
    

    ls /full/path/to/some/dir
    

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

    14 回复  |  直到 7 年前
        1
  •  1200
  •   Charles Duffy    7 年前

    set -x set -o xtrace 展开变量并在行前打印一个加号。

    set -v set -o verbose 打印前不展开变量。

    使用 set +x set +v

    在脚本的第一行,可以 #!/bin/sh -x (或 -v 设置-x (或 -五

    以上也适用于 /bin/sh .

    请参见上的bash黑客wiki set attributes ,等等 debugging .

    $ cat shl
    #!/bin/bash                                                                     
    
    DIR=/tmp/so
    ls $DIR
    
    $ bash -x shl 
    + DIR=/tmp/so
    + ls /tmp/so
    $
    
        2
  •  351
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    set -x 会给你想要的。

    下面是一个示例shell脚本来演示:

    #!/bin/bash
    set -x #echo on
    
    ls $PWD
    

    这将展开所有变量并在输出命令之前打印完整的命令。

    输出:

    + ls /home/user/
    file1.txt file2.txt
    
        3
  •  101
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    我使用一个函数回显并运行命令:

    #!/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
    
        4
  •  93
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    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
    
        5
  •  68
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    shuckc's answer 对于回显,select行有一些缺点:您最终会遇到以下问题 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
    

        6
  •  38
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    $ cat ./server
    #!/bin/bash -x
    ssh user@server
    
    $ ./server
    + ssh user@server
    user@server's password: ^C
    $
    
        7
  •  36
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    TLDP Bash Guide for Beginners: Chapter 2. Writing and debugging scripts

    2.3.1. 对整个脚本进行调试

    $ bash -x script1.sh
    

    SourceForge . 从3.x开始,Bash的大多数现代版本都提供了这些调试功能。

    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
    
        8
  •  21
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    在命令行中,在bash脚本名称之前键入“bash-x”。例如,要执行foo.sh,请键入:

    bash -x foo.sh
    
        9
  •  16
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    执行 调试模式下的Bash脚本 -x .

    bash -x example_script.sh
    
    # Console output
    + cd /home/user
    + mv text.txt mytext.txt
    

    你也可以 在脚本中保存-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
    
        10
  •  5
  •   Gama11 zzapper    5 年前

    setopt VERBOSE
    

    为了调试,

    setopt XTRACE
    
        11
  •  2
  •   cnst    7 年前

    为了 csh tcsh ,你可以 set verbose set echo (或者您甚至可以同时设置两者,但大多数情况下可能会导致一些重复)。

    verbose 选项打印与您键入的shell表达式几乎相同的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.

        12
  •  2
  •   Phani Rithvij    5 年前

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

    # 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

    如果需要命令的退出状态,如前所述 here

    使用

    { 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!
    
        13
  •  1
  •   Karthik Arun    10 年前
    $ cat exampleScript.sh
    #!/bin/bash
    name="karthik";
    echo $name;
    
    bash -x exampleScript.sh
    

    输出如下:

    enter image description here

        14
  •  1
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    为了允许复合命令得到响应,我使用 eval 加上Soth's 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