コマンド実行可能かどうかを調べる方法の比較

ある名前が指定されたときにそれを実行できるかどうかを調べる方法について、以下のシェルで比較してみた。

  • zsh 5.7.1
  • bash 3.2.57
  • dash 0.5.10.2
  • fish 3.1.2
  • tcsh 6.21.00

テストスクリプト

前提としてmakeコマンドがPATHにあることとする。

# which.sh
alias a_make=make
f_make() { make; }

try() {
  echo
  echo TRY: "$@"
  "$@"
  echo EXIT: $?
}

try type make
try type a_make
try type f_make
try type cd
try type not_exist

echo ---------------
try command -v make
try command -v a_make
try command -v f_make
try command -v cd
try command -v not_exist

echo ---------------
try command -V make
try command -V a_make
try command -V f_make
try command -V cd
try command -V not_exist

echo ---------------
try which make
try which a_make
try which f_make
try which cd
try which not_exist
# which.fish
alias a_make=make
function f_make; make; end

function try
  echo
  echo TRY: $argv
  $argv
  echo EXIT: $status
end

try type make
try type a_make
try type f_make
try type cd
try type not_exist

echo ---------------
try command -v make
try command -v a_make
try command -v f_make
try command -v cd
try command -v not_exist

echo ---------------
try command -V make
try command -V a_make
try command -V f_make
try command -V cd
try command -V not_exist

echo ---------------
try which make
try which a_make
try which f_make
try which cd
try which not_exist
# which.csh

# https://vivafan.com/2013/03/csh-no-function/
# http://www.linuxmisc.com/12-unix-shell/52d675f409c37a60.htm
alias function '\\
 <<"end function" sed -e '"'"'\\
#\\!/bin/sed -f\\
#\\
## Make the eval command\\
# quote quotes\\
s/'"'"'"'"'"'"'"'"'/'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'/g;\\
# enclose with quotes\\
1s/^/eval '"'"'"'"'"'"'"'"'/;\\
$s/$/'"'"'"'"'"'"'"'"'/;\\
#\\
## Make the alias command\\
# escape exclamation marks and newlines\\
s/\\!/\\\\!/g;\\
s/$/\\\\/g\\
# quote quotes\\
s/'"'"'"'"'"'"'"'"'/'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'/g;\\
# enclose with quotes\\
1s/^/alias @alias_name@ '"'"'"'"'"'"'"'"'/;\\
$a\\\
;echo >/dev/null'"'"'"'"'"'"'"'"'\\
#^^^^^^^^^^^^^^^ (workaround against printing of arguments)\\
'"'"' | \\
 sed -e s/@alias_name@/\!\!:1/ >/tmp/make_alias$$; \\
 source /tmp/make_alias$$; \\
 rm /tmp/make_alias$$; \\
'

alias a_make make

function try
  echo
  echo TRY: "!!:1-*"
  !!:1-*
  echo EXIT: $?
"end function"

try type make
try type a_make
# try type f_make # tcshに関数はない
try type cd
try type not_exist

echo ---------------
try command -v make
try command -v a_make
# try command -v f_make # tcshに関数はない
try command -v cd
try command -v not_exist

echo ---------------
try command -V make
try command -V a_make
# try command -V f_make # tcshに関数はない
try command -V cd
try command -V not_exist

echo ---------------
try which make
try which a_make
# try which f_make # tcshに関数はない
try which cd
try which not_exist

結果

type

Shell zsh bash / bash --posix dash fish tcsh
make make is /usr/bin/make (0) make is /usr/bin/make (0) make is /usr/bin/make (0) make is /usr/bin/make (0) make is /usr/bin/make (0)
a_make a_make is an alias for make (0) a_make is aliased to `make' (0) a_make is an alias for make (0) a_make is a function with definition
# Defined in - @ line 1
...(以下略)
(0)
/usr/bin/type: line 4: type: a_make: not found (1)
f_make f_make is a shell function from which.sh (0) f_make is a function
f_make ()
make
}
(0)
f_make is a shell function (0) f_make is a function with definition
# Defined in which.fish @ line 2
...(以下略)
(0)
--
cd cd is a shell builtin (0) cd is a shell builtin (0) cd is a shell builtin (0) cd is a function with definition
# Defined in /usr/local/Cellar/fish/3.1.2/...(以下略)
(0)
cd is a shell builtin (0)
not_exist not_exist not found (1) bash: type: not_exist: not found (1) not_exist: not found (127) type: Could not find 'not_exist' (1) /usr/bin/type: line 4: type: not_exist: not found (1)

command -v

Shell zsh bash / bash --posix dash fish tcsh
make /usr/bin/make (0) /usr/bin/make (0) /usr/bin/make (0) /usr/bin/make (0) /usr/bin/make (0)
a_make alias a_make=make (0) alias a_make='make' (0) alias a_make='make' (0) 出力なし (1) 出力なし (1)
f_make f_make (0) f_make (0) f_make (0) 出力なし (1) --
cd cd (0) cd (0) cd (0) /usr/bin/cd (0) cd (0)
not_exist 出力なし (1) 出力なし (1) 出力なし (127) 出力なし (1) 出力なし (1)

command -V

Shell zsh bash / bash --posix dash fish tcsh
make /usr/bin/make (0) make is /usr/bin/make (0) make is a tracked alias for /usr/bin/make (0) command: Unknown option '-V' (2) make is /usr/bin/make (0)
a_make a_make is an alias for make (0) a_make is aliased to `make' (0) a_make is an alias for make (0) command: Unknown option '-V' (2) /usr/bin/command: line 4: command: a_make: not found (1)
f_make f_make is a shell function from which.sh (0) f_make is a function
f_make ()
make
}
(0)
f_make is a shell function (0) command: Unknown option '-V' (2) --
cd cd is a shell builtin (0) cd is a shell builti (0) cd is a shell builtin (0) command: Unknown option '-V' (2) cd is a shell builtin (1)
not_exist not_exist not found (1) bash: command: not_exist: not foun (1) cd is a shell builtin (127) command: Unknown option '-V' (2) /usr/bin/command: line 4: command: not_exist: not found (1)

which

Shell zsh bash / bash --posix dash fish tcsh
make /usr/bin/make (0) /usr/bin/make (0) /usr/bin/make (0) /usr/bin/make (0) /usr/bin/make (0)
a_make a_make: aliased to make (0) 出力なし (1) 出力なし (1) 出力なし (1) /usr/bin/make: aliased to make (0)
f_make f_make () {
make
}
(0)
出力なし (1) 出力なし (1) 出力なし (1) --
cd cd: shell built-in command (0) /usr/bin/cd (0) /usr/bin/cd (0) /usr/bin/cd (0) cd: shell built-in command. (0)
not_exist not_exist not found (1) 出力なし (1) 出力なし (1) 出力なし (1) not_exist: Command not found. (1)