Reusing output from last command in Bash

后端 未结 13 2087
长情又很酷
长情又很酷 2020-12-07 08:35

Is the output of a Bash command stored in any register? E.g. something similar to $? capturing the output instead of the exit status.

I could assign the

13条回答
  •  渐次进展
    2020-12-07 08:44

    Yeah, why type extra lines each time; agreed. You can redirect the returned from a command to input by pipeline, but redirecting printed output to input (1>&0) is nope, at least not for multiple line outputs. Also you won't want to write a function again and again in each file for the same. So let's try something else.

    A general solution for running the desired command only once and getting multi-line printed output of the command in an array variable line-by-line.

    If you are not exporting the files anywhere and intend to use it locally only, you can have Terminal set-up the function declaration. You have to add the function in ~/.bashrc file or in ~/.profile file. In second case, you need to enable Run command as login shell from Edit>Preferences>yourProfile>Command.

    Make a simple function, say:

    get_prev()
    {
        # option 1: create an executable with the command(s) and run it
        echo $* > /tmp/exe
        bash /tmp/exe > /tmp/out
        
        # option 2: if your command is single command (no-pipe, no semi-colons), still it may not run correct in some exceptions
        #echo `$*` > /tmp/out
        
        # return the command(s) outputs line by line
        IFS=$(echo -en "\n\b")
        arr=()
        exec 3

    So what we did was print the whole command to a temporary file /tmp/exe and run it and save the output to another file /tmp/out and then read the contents of the /tmp/out file line-by-line to an array.

    In main script:

    #run your command:
    cmd="echo hey ya; echo hey hi; printf `expr 10 + 10`'\n' ; printf $((10 + 20))'\n'"
    get_prev $cmd
    #or simply
    get_prev "echo hey ya; echo hey hi; printf `expr 10 + 10`'\n' ; printf $((10 + 20))'\n'"
    

    Now, bash saves the variable even outside previous scope, so the arr variable created in get_prev function is accessible even outside the function in the main script:

    #get previous command outputs in arr
    for((i=0; i<${#arr[@]}; i++)); do echo ${arr[i]}; done
    

    Edit:
    I'm using the following code in my implementation:

    get_prev()
    {
        usage()
        {
            echo "Usage: alphabet [ -h | --help ]
            [ -s | --sep SEP ]
            [ -v | --var VAR ] \"command\""
        }
        
        ARGS=$(getopt -a -n alphabet -o hs:v: --long help,sep:,var: -- "$@")
        if [ $? -ne 0 ]; then usage; return 2; fi
        eval set -- $ARGS
        
        local var="arr"
        IFS=$(echo -en '\n\b')
        for arg in $*
        do
            case $arg in
                -h|--help)
                    usage
                    echo " -h, --help : opens this help"
                    echo " -s, --sep  : specify the separator, newline by default"
                    echo " -v, --var  : variable name to put result into, arr by default"
                    echo "  command   : command to execute. Enclose in quotes if multiple lines or pipelines are used."
                    shift
                    return 0
                    ;;
                -s|--sep)
                    shift
                    IFS=$(echo -en $1)
                    shift
                    ;;
                -v|--var)
                    shift
                    var=$1
                    shift
                    ;;
                -|--)
                    shift
                    ;;
                *)
                    cmd=$option
                    ;;
            esac
        done
        if [ ${#} -eq 0 ]; then usage; return 1; fi
        
        echo $* > /tmp/exe
        ERROR=$( { bash /tmp/exe > /tmp/out; } 2>&1 )
        if [ $ERROR ]; then echo $ERROR; return 1; fi
        
        local a=()
        exec 3

    Ive been using this to print space-separated outputs of multiple/pipelined/both commands as line separated:

    get_prev -s " " -v myarr "cmd1 | cmd2; cmd3 | cmd4"
    

    For example:

    get_prev -s ' ' -v myarr whereis python # or "whereis python"
    # can also be achieved (in this case) by
    whereis python | tr ' ' '\n'
    

    Now tr command is useful at other places as well, such as

    echo $PATH | tr ':' '\n'
    

    But for multiple/piped commands... you know now. :)

    -Himanshu

提交回复
热议问题