Assigning the result of 'test' to a variable

You need to quote whitespace:

mytest='[ -f $file ]'
if $mytest; then echo yes; fi

However, this is extremely brittle and potentially insecure. See http://mywiki.wooledge.org/BashFAQ/050 for a detailed discussion and some better ways to accomplish something similar.

If you want to encapsulate a complex piece of code, a function is usually the way to go:

mytest () { [ -f "$file" ]; }
if mytest; then echo yes; fi

If you want to run the code once and store its result so you can examine it later, I would rephrase it like this:

if [ -f "$file" ]; then
    mytest=true
else
    mytest=false
fi
if $mytest; then echo yes; fi

As others have documented here, using the string "true" is a red herring; this is not an appropriate way to store boolean values in shell scripts, as evaluating it means dynamically invoking a command rather than simply inspecting the stored value using shell builtins hardcoded in your script.

Instead, if you really must store an exit status, do so as a numeric value:

[ -f "$file" ]               # run the test
result=$?                    # store the result

if (( result == 0 )); then   # 0 is success
  echo "success"
else                         # nonzero is failure
  echo "failure"
fi

If compatibility with set -e is desired, replace the first two lines of the above with:

result=0
[ -f "$file" ] || result=$?

...as putting the test on the left-hand side of || marks it as "checked", suppressing errexit behavior. (That said, see BashFAQ #105 describing the extent to which set -e harms predictable, portable behavior; I strongly advise against its use).


mytest=/bin/true is storing the string /bin/true in the $mytest variable.

mytest=[ -f $file ] is setting the $mytest variable to the value [ for the duration of the command -f $file ] (which as your output indicates fails as there is no -f command available).

mytest= [ -f $file ] (like the above) sets the value of the $mytest variable to blank for the duration of the [ -f $file ] command (and returns whatever [ returns).

mytest= /bin/false this is the same as the above case only the command being run is /bin/false.

If you want to store the return code from a command in a variable you can do

/bin/true
ret=$?

if you want to store the output from a command in a variable you can do

out=$(/bin/true)

(though with /bin/true that variable will be empty as it outputs no text.

For your case you want the former $? model.

Also, using set -x (and/or set -v) in your scripts might have helped you diagnose this.


A old one but left this here for reference for people that might need it. Not the most beautiful solution but it works in bash:

mytest=$( [ -f $file ] ; echo $? )

More portable, using the test command, and the backticks:

set mytest=`test -f $file ; echo $?`

In a subprocess (<!> system load), the condition is evaluated, and then the result echoed to the output that is captured by the variable $mytest.

Tags:

Bash