You are not logged in.
Pages: 1
Trying to implement a check for the availability of a given text editor inside a bash script, I discovered that test -x needs its argument to be put in quotes if the argument is a command substitution. Maybe someone can exlplain to me why.
Here's an example of what happens if you don't put the quotes:
$ type -p nano # nano is installed
/usr/bin/nano
$ type -p gedit # gedit is not installed
$
$if [ -x $(type -p nano) ]; then echo "found executable"; else echo "command not found/not an executable"; fi
found executable
$ if [ -x $(type -p gedit) ]; then echo "found executable"; else echo "command not found/not an executable"; fi
found executable # This is strange.
$
$ if [ -x "$(type -p nano)" ]; then echo "found executable"; else echo "command not found/not an executable"; fi
found executable
$ if [ -x "$(type -p gedit)" ]; then echo "found executable"; else echo "command not found/not an executable"; fi
command not found/not an executable
Last edited by msi (2018-01-05 02:21:20)
Offline
Well, without the quotes it tells me that gedit is found/executable, but gedit is not installed here. I'l take a guess and say that -x is testing the executability of the command substitution. When you quote it, you're telling the shell to expand what's inside the quotes, so -x tests the result of that.
For more complication, try it with double-brackets for test:
if [[ -x $(type -p gedit) ]]; then echo "found executable"; else echo "command not found/not an executable"; fi
command not found/not an executable
Offline
I'l take a guess and say that -x is testing the executability of the command substitution. When you quote it, you're telling the shell to expand what's inside the quotes, so -x tests the result of that.
That sounds like a reasonable explanation, though I'm not sure it's accurate. But a look at exit codes also points into that direction:
$ test -x /usr/bin/whoami
$ echo $?
0
$ test -x /usr/bin/whoarethey
$ echo $?
1
$ test -x $(type -p whoami)
$ echo $?
0
$ test -x $(type -p whoarethey)
$ echo $?
0
$ test -x "$(type -p whoami)"
$ echo $?
0
$ test -x "$(type -p whoarethey)"
$ echo $?
1
Offline
The explanation is in how the bash expands commands, and how "-x" works.
Without quotes, a phrase like
[ -x $(type -p gedit)]
gets "expanded" into the following phrase when "gedit' is missing (aka "type" returns nothing):
[-x ]
i.e., "-x" without argument, and that succeeds. Whereas with quotes around it, the expansion is
[ -x "" ]
i.e. "-x" with an empty string as argument, and that fails.
Perhaps your statement should have been like
if type -p $program > /dev/null ; then echo UGH ; else echo NÖF; fi
That would be using the return code of "type" as condition, with 0 meaning success and non-0 meaning fail.
Offline
The explanation is in how the bash expands commands, and how "-x" works.
Without quotes, a phrase like
[ -x $(type -p gedit)]
gets "expanded" into the following phrase when "gedit' is missing (aka "type" returns nothing):
[-x ]
i.e., "-x" without argument, and that succeeds. Whereas with quotes around it, the expansion is
[ -x "" ]
i.e. "-x" with an empty string as argument, and that fails.
I see. Thanks for explaining that.
Perhaps your statement should have been like
if type -p $program > /dev/null ; then echo UGH ; else echo NÖF; fi
That would be using the return code of "type" as condition, with 0 meaning success and non-0 meaning fail.
The problem with this is that, according to man bash, type -p only...
returns the name of the disk file that would be executed if name were specified as a command name, or nothing if ``type -t name'' would not return file.
In other words, it just checks if $program is in your $PATH, not if it is executable.
So, the right way to perform that check would be to use text -x, but with proper quoting:
if [ -x "$(type -p "$program")" ]
then
[commands]
else
[commands]
fi
Last edited by msi (2018-01-04 21:24:31)
Offline
Pages: 1