Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get different bash script results when invoked with 'set -x', and how do I fix it?

Tags:

bash

I've found that the results of my bash script will change depending upon if I execute it with debugging or not (i.e. invoking set -x). I don't mean that I get more output, but that the result of the program itself differs.

I'm assuming this isn't the desired behavior, and I'm hoping that you can teach me how to correc this.

The bash script below is a contrived example, I tried reducing the logic from the script I'm investigating so that the problem can be easily reproducible and obvious.

#!/bin/bash

# Base function executes command (print working directory) stores the value in
# the destination and returns the status.
function get_cur_dir {
    local dest=$1
    local result

    result=$((pwd) 2>&1)
    status=$?

    eval $dest="\"$result\""
    return $status
}

# 2nd level function uses the base function to execute the command and store
# the result in the desired location. However if the base function fails it
# terminates the script. Yes, I know 'pwd' won't fail -- this is a contrived
# example to illustrate the types of problems I am seeing.
function get_cur_dir_nofail {
    local dest=$1
    local gcdnf_result
    local status

    get_cur_dir gcdnf_result
    status=$?
    if [ $status -ne 0 ]; then
        echo "ERROR: Command failure"
        exit 1
    fi

    eval dest="\"$gcdnf_result\""
}


# Cause blarg to be loaded with the current directory, use the results to
# create a flag_file name, and do logic with the flag_file name.
function main {
    get_cur_dir blarg

    echo "Current diregtory is:$blarg"

    local flag_file=/tmp/$blarg.flag

    echo -e ">>>>>>>> $flag_file"

    if [ "/tmp//root.flag" = "$flag_file" ]; then
        echo "Match"
    else
        echo "No Match"
    fi
}


main

.

.

When I execute without the set -x it works as I expect as illustrated below:

Current diregtory is:/root
>>>>>>>> /tmp//root.flag
Match

.

.

However, when I add the debugging output with -x it doesn't work, as illustrated below: root@psbu-jrr-lnx:# bash -x /tmp/example.sh

+ main
+ get_cur_dir blarg
+ local dest=blarg
+ local result
+ result='++ pwd
/root'
+ status=0
+ eval 'blarg="++ pwd
/root"'
++ blarg='++ pwd
/root'
+ return 0
+ echo 'Current diregtory is:++ pwd
/root'
Current diregtory is:++ pwd
/root
+ local 'flag_file=/tmp/++ pwd
/root.flag'
+ echo -e '>>>>>>>> /tmp/++ pwd
/root.flag'
>>>>>>>> /tmp/++ pwd
/root.flag
+ '[' /tmp//root.flag = '/tmp/++ pwd
/root.flag' ']'
+ echo 'No Match'
No Match
root@psbu-jrr-lnx:#  
like image 662
John Rocha Avatar asked Apr 29 '13 16:04

John Rocha


2 Answers

I think what happens is you capture the debugging logging output produced by the shell when you run it with set -x, this line, for example, does it:

 result=$((pwd) 2>&1)

In the above line you shouldn't really need to redirect standard error to standard output, so remove 2>&1.

like image 179
piokuc Avatar answered Oct 30 '22 03:10

piokuc


Changing...

result=$((pwd) 2>&1)

...into...

result=$(pwd 2>&1)

...will allow you to capture the output of pwd without capturing the debug info generated by set -x.

like image 25
Joachim Isaksson Avatar answered Oct 30 '22 05:10

Joachim Isaksson