7

How, on Bash, do we test a name string is an executable, as tried it won't work:

$ [[ -x cp ]] &&echo YES
$
$ [[ -x ls ]] &&echo YES

as tried it hard won't be correct way:

$ >/dev/null type ls && echo YES
YES

$ >/dev/null type -fat && echo YES YES

This the very falling failure thanks for help before

Raffa
  • 34,963
Dumb
  • 79

4 Answers4

10

The question is not quite clear:

  • Do you want to test if some string corresponds to an executable command? or
  • Do you want to test if a file is executable

You want to test if a file is executable

The -x test is useful in the second case because it tests whether a given file is executable, i.e., if the executable bit is set.

It requires you to provide a valid file name. Unless you provide a full file path, the current directory is searched. Thus your command will typically fail for e.g. cp, unless you first make the directory of the executable current, i.e. cd /usr/bin.

To retrieve the full file path of an executable, you can use the shell build-in type with the options -P so only a matching executable in the search PATH is retrieved (ignoring aliases, hashed commands and functions). Note that that may not be what is executed on the system by default.

You could also add an action to execute if the test fails. Then your statement becomes:

[[ -x $(type -P cp) ]] && echo YES || echo NO

which can also be written as

test -x $(type -P cp) && echo YES || echo NO

You want to test if some string corresponds to an executable command

If your question aimed to ask how to test if something is an executable command on your system, just use type:

type ls &>/dev/null && echo YES || echo NO

Type will return an error code if the string does not correspond with something executable, so the second command will not be executed.

Barmar
  • 241
vanadium
  • 97,564
6

You can use the command -v command to test this:

command -v cp >/dev/null 2>&1 && echo "YES"

Will return:

YES

While:

command -v fhdjskfsfs >/dev/null 2>&1 && echo "YES"

Will most likely return nothing (unless you have an executable in path named fhdjskfsfs).

Artur Meinild
  • 31,035
5

How, on Bash, do we test a name string is an executable?

Your logic with the type shell builtin command should work (excluding shell builtin commands and functions as you seem to want that), if you use it like so:

&>/dev/null type -afPt -- ls && echo yes

... and that would work as long as the provided string argument is not empty or otherwise it will return 0(success) on an empty string ... Therefore, if you are using this in a script and passing names/strings in a variable e.g. var, then you might want to use it like this: ${var:-empty} which if var is empty, then Bash will expand that variable to the word empty ... Double quoting the variable expansion should work as well.

Examples:

$ &>/dev/null type -afPt -- ls && echo yes || echo no
yes
$
$ &>/dev/null type -afPt -- notcommand && echo yes || echo no
no
$
$ &>/dev/null type -afPt -- set && echo yes || echo no
no
$
$ &>/dev/null type -afPt -- ./myscript.sh && echo yes || echo no
yes
$
$ &>/dev/null type -afPt -- echo && echo yes || echo no
yes

Notice: if you are going to discard off all the output, then you might not need all those options as only -P should be enough to exclude both shell builtins and functions because it forces a path search for each word in the passed string and this will exclude those two by default.

Raffa
  • 34,963
2

If you want to test not only if a command is an executable, but generally what kind of command it is, you can use the following shellscript, which you might give the name what-about and make it executable.

#!/bin/bash

LANG=C inversvid="\0033[7m" resetvid="\0033[0m"

if [ $# -ne 1 ] then echo "Usage: ${0##*/} <program-name>" echo "Will try to find corresponding package" echo "and tell what kind of program it is" exit 1 fi command="$1"

str=;for ((i=1;i<=$(tput cols);i++)) do str="-$str";done tmp="$command" first=true curdir="$(pwd)" tmq=$(which "$command") tdr="${tmq%/}" tex="${tmq##/}" if test -d "$tdr"; then cd "$tdr"; fi #echo "cwd='$(pwd)' ################# d"

while $first || [ "${tmp:0:1}" == "l" ] do first=false #echo "tmp=$tmp########################################## d 1.0" tmp=${tmp##-&gt;\ } tmq="$tmp" #echo "tmp=$tmp########################################## d 1.1" tmp="$(ls -l "$(which "$tmp")" 2>/dev/null)" #echo "tmp=$tmp########################################## d 1.2" tdr="${tmq%/}" tex="${tmq##*/}" if test -d "$tdr"; then cd "$tdr"; fi

echo "cwd='$(pwd)' ################# d"

if [ "$tmp" == "" ] then tmp=$(ls -l "$tex" 2>/dev/null) #echo "tmp=$tmp########################################## d 2.1" tmp=${tmp##*\ } #echo "tmp=$tmp########################################## d 2.2" if [ "$tmp" == "" ] then echo "$command is not in PATH"

package=$(bash -ic "$command -v 2>&1")

echo "package=$package XXXXX 0"

bash -ic "alias '$command' > /dev/null 2>&1" > /dev/null 2>&1 if [ $? -ne 0 ] then echo 'looking for package ...' package=$(bash -ic "$command -v 2>&1"| sed -e '0,/with:/d'| grep -v '^$') else echo 'alias, hence not looking for package' fi

echo "package=$package XXXXX 1"

if [ "$package" != "" ] then echo "$str" echo "package: [to get command '$1']" echo -e "${inversvid}${package}${resetvid}" fi else echo "$tmp" fi else echo "$tmp" fi done tmp=${tmp##*\ } if [ "$tmp" != "" ] then echo "$str" program="$tex" program="$(pwd)/$tex" file "$program" if [ "$program" == "/usr/bin/snap" ] then echo "$str" echo "/usr/bin/snap run $command # run $command " sprog=$(find /snap/"$command" -type f -iname "$command"
-exec file {} ; 2>/dev/null | sort | tail -n1) echo -e "${inversvid}file: $sprog$resetvid" echo "/usr/bin/snap list $command # list $command" slist="$(/usr/bin/snap list "$command")" echo -e "${inversvid}$slist$resetvid" else package=$(dpkg -S "$program") if [ "$package" == "" ] then package=$(dpkg -S "$tex" | grep -e " /bin/$tex$" -e " /sbin/$tex$") if [ "$package" != "" ] then ls -l /bin /sbin fi fi if [ "$package" != "" ] then echo "$str" echo " package: /path/program [for command '$1']" echo -e "${inversvid} $package ${resetvid}" fi fi fi echo "$str" alias=$(bash -ic "alias '$command' 2>/dev/null"| grep "$command") if [ "$alias" != "" ] then echo "$alias" else type=$(bash -ic "type &quot;$command&quot; 2>/dev/null") if [ "$type" != "" ] then echo "type: $type" elif [ "$alias" == "" ] then echo "type: $command: not found" fi fi cd "$curdir"

sudodus
  • 47,684