Echo command, and then run it? (Like make)

前端 未结 6 1507
走了就别回头了
走了就别回头了 2021-02-02 12:49

Is there some way to get bash into a sort of verbose mode where, such that, when it\'s running a shell script, it echoes out the command it\'s going to run before running it? T

6条回答
  •  深忆病人
    2021-02-02 13:34

    To add to others' implementations, this is my basic script boilerplate, including argument parsing (which is important if you're toggling verbosity levels).

    #!/bin/sh
    
    # Control verbosity
    VERBOSE=0
    
    # For use in usage() and in log messages
    SCRIPT_NAME="$(basename $0)"
    
    ARGS=()
    
    # Usage function: tells the user what's up, then exits.  ALWAYS implement this.
    # Optionally, prints an error message
    # usage [{errorLevel} {message...}
    function usage() {
        local RET=0
        if [ $# -gt 0 ]; then
            RET=$1; shift;
        fi
        if [ $# -gt 0 ]; then
            log "[$SCRIPT_NAME] ${@}"
        fi
        log "Describe this script"
        log "Usage: $SCRIPT_NAME [-v|-q]" # List further options here
        log "   -v|--verbose    Be more verbose"
        log "   -q|--quiet      Be less verbose"
        exit $RET
    }
    
    # Write a message to stderr
    # log {message...}
    function log() {
        echo "${@}" >&2
    }
    
    # Write an informative message with decoration
    # info {message...}
    function info() {
        if [ $VERBOSE -gt 0 ]; then
            log "[$SCRIPT_NAME] ${@}"
        fi
    }
    
    # Write an warning message with decoration
    # warn {message...}
    function warn() {
        if [ $VERBOSE -gt 0 ]; then
            log "[$SCRIPT_NAME] Warning: ${@}"
        fi
    }
    
    # Write an error and exit
    # error {errorLevel} {message...}
    function error() {
        local LEVEL=$1; shift
        if [ $VERBOSE -gt -1 ]; then
            log "[$SCRIPT_NAME] Error: ${@}"
        fi
        exit $LEVEL
    }
    
    # Write out a command and run it
    # vexec {minVerbosity} {prefixMessage} {command...}
    function vexec() {
        local LEVEL=$1; shift
        local MSG="$1"; shift
        if [ $VERBOSE -ge $LEVEL ]; then
            echo -n "$MSG: "
            local CMD=( )
            for i in "${@}"; do
                # Replace argument's spaces with ''; if different, quote the string
                if [ "$i" != "${i/ /}" ]; then
                    CMD=( ${CMD[@]} "'${i}'" )
                else
                    CMD=( ${CMD[@]} $i )
                fi
            done
            echo "${CMD[@]}"
        fi
        ${@}
    }
    
    # Loop over arguments; we'll be shifting the list as we go,
    # so we keep going until $1 is empty
    while [ -n "$1" ]; do
        # Capture and shift the argument.
        ARG="$1"
        shift
        case "$ARG" in
            # User requested help; sometimes they do this at the end of a command
            # while they're building it.  By capturing and exiting, we avoid doing
            # work before it's intended.
            -h|-\?|-help|--help)
                usage 0
                ;;
            # Make the script more verbose
            -v|--verbose)
                VERBOSE=$((VERBOSE + 1))
                ;;
            # Make the script quieter
            -q|--quiet)
                VERBOSE=$((VERBOSE - 1))
                ;;
            # All arguments that follow are non-flags
            # This should be in all of your scripts, to more easily support filenames
            # that start with hyphens.  Break will bail from the `for` loop above.
            --)
                break
                ;;
            # Something that looks like a flag, but is not; report an error and die
            -?*)
                usage 1 "Unknown option: '$ARG'" >&2
                ;;
            #
            # All other arguments are added to the ARGS array.
            *)
                ARGS=(${ARGS[@]} "$ARG")
                ;;
        esac
    done
    # If the above script found a '--' argument, there will still be items in $*;
    # move them into ARGS
    while [ -n "$1" ]; do
        ARGS=(${ARGS[@]} "$1")
        shift
    done
    
    # Main script goes here.
    

    Later...

    vexec 1 "Building myapp.c" \
        gcc -c myapp.c -o build/myapp.o ${CFLAGS}
    

    Note: This will not cover piped commands; you need to bash -c those sorts of things, or break them up into intermediate variables or files.

提交回复
热议问题