Bashスクリプトからプログラムが存在するかどうかを確認するにはどうすればよいですか?


2210

エラーを返して終了するか、スクリプトを続行する方法で、プログラムが存在することをどのように検証しますか?

簡単なようですが、困っています。


「プログラム」とは?関数とエイリアスは含まれていますか?whichこれらに対してtrueを返します。type引数なしの場合、予約語とシェルのビルトインに対してさらにtrueが返されます。「プログラム」が「で実行可能」を意味する場合$PATHは、この回答を参照してください。
トム・ヘイル

回答:


3055

回答

POSIX互換:

command -v <the_command>

Bash固有の環境の場合:

hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords

説明

避けてくださいwhich。外部プロセスの効果は簡単に変化しますがhashtypeそれcommandはあなたがほとんど何もしないために起動している外部プロセスであるだけでなく(のような組み込みコマンドを意味するか、またははるかに安価です)、組み込みコマンドに依存して実際に必要なことを実行することもできますシステム間。

なぜ気にするの?

  • 多くのオペレーティングシステムには、終了ステータスを設定しない a whichあります。つまり、if which fooはそこでも機能せず、存在しない場合でも常にfoo存在すること報告します(一部のPOSIXシェルもこれを行うように見えることに注意してくださいhash)。
  • 多くのオペレーティングシステムwhichは、出力を変更したり、パッケージマネージャーにフックしたりするなど、カスタムおよび悪質なことを行います。

したがって、は使用しないでくださいwhich。代わりに次のいずれかを使用してください。

$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
$ type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
$ hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }

(副次的注意:一部は2>&-同じである2>/dev/nullが短いと示唆します– これは正しくありません。stderrに書き込もうとするとプログラムでエラー2>&-が発生するFD 2を閉じます。 これは、正常に書き込んで出力を破棄することとは大きく異なります。 (そして危険!))

あなたのハッシュバンがそうであるならば、あなたは/bin/shPOSIXが言うことを気にするべきです。typehashの終了コードはPOSIXであまり明確に定義されてhashおらず、コマンドが存在しない場合(これをtypeまだ確認していない場合)は正常に終了するように見えます。 commandの終了ステータスはPOSIXによって明確に定義されているため、おそらく最も安全に使用できます。

スクリプトが使用する場合はbashしかし、POSIX規則はもう本当に問題ではないとの両方typehash使用に完全に安全になります。type今持っている-Pだけで検索するようにPATHしてhash、コマンドの場所は通常、あなたは、おそらく実際にそれを使用するために、その存在を確認するため、良いことである、(より速くあなたがそれを使用する次の時間をルックアップするために)ハッシュ化されることが副作用を持っています。

簡単な例として、gdate存在する場合に実行される関数を次に示しますdate

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "$@"
    else
        date "$@"
    fi
}

35
@Geert:&> / dev / nullの部分は、「foo」が存在しない場合に「type」が発行するメッセージを非表示にします。エコーの>&2により、エラーメッセージは標準出力ではなく標準エラーに送信されます。それは慣習だからです。どちらも端末に表示されますが、標準エラーは間違いなくエラーメッセージと予期しない警告の優先出力です。
lhunath

5
-Pフラグは「sh」では機能しません。たとえば、stackoverflow.com
questions / 2608688 /…

130
bashでの「高度な」I / Oリダイレクトに慣れていない場合:1)2>&- (「出力ファイル記述子2を閉じる」。これはstderrです)の結果はと同じ2> /dev/nullです。2)>&2はのショートカットで1>&2、「stdoutをstderrにリダイレクトする」と認識される場合があります。詳細については、「高度なBashスクリプトガイド」の「i / oリダイレクト」ページ参照してください。
mikewaters、2011

9
@mikewaters ABSはかなり高度に見え、bashおよび非bashの幅広いCLI機能を説明しますが、多くの点で非常に過失であり、優れた慣例に従っていません。このコメントには、書き上げるのに十分なスペースがありません。私はBADコードのいくつかのランダムな例を貼り付けることができます:while read element ; do .. done <<< $(echo ${ArrayVar[*]})for word in $(fgrep -l $ORIGINAL *.txt)ls -l "$directory" | sed 1d 、{{中のためseq $BEGIN $END}}、...多くは、作者に連絡し、改善を提案しようとしたが、それはまったくのwikiや要望聴覚障害者の耳に着弾したません。
lhunath 2013年

56
@mikewatersはと同じで2>&-はありません2>/dev/null。前者はファイル記述子を閉じますが、後者は単にそれをにリダイレクトし/dev/nullます。プログラムがstderrでstderrが閉じていることを通知しようとするため、エラーが表示されない場合があります。
nyuszika7h 2014年

577

以下は、コマンドが存在し$PATH 実行可能かどうかを確認するための移植可能な方法です。

[ -x "$(command -v foo)" ]

例:

if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  exit 1
fi

でその名前の実行可能ファイルが見つからない場合、bashは非実行可能ファイルを返すため、実行可能チェックが必要です$PATH

また、実行可能ファイルと同じ名前の非実行可能ファイルが以前に存在する場合$PATH、後者は実行されますが、ダッシュは前者を返します。これはバグであり、POSIX標準に違反しています。[ バグレポート ] [標準 ]

さらに、探しているコマンドがエイリアスとして定義されている場合、これは失敗します。


4
ウィルcommand -vも、非実行ファイルのパスを作成?つまり、-xは本当に必要なのでしょうか。
einpoklum 2017年

5
@einpoklum -xは、ファイルが実行可能かどうかをテストします。これが問題でした。
Ken Sharp

3
@KenSharp:しかし、commandそれ自体が実行可能かどうかをテストするので、それは冗長であるように見えますか?
einpoklum 2017年

13
@einpoklumはい、必要です。実際、このソリューションでさえ、1つのエッジケースで失敗する可能性があります。私の注意をこれに持って来てくれてありがとう。dash、bash、およびzshはすべて$PATH、コマンドの実行時に非実行可能ファイルをスキップします。ただし、の動作command -vは非常に一貫していません。ダッシュでは、$PATH実行可能ファイルかどうかに関係なく、最初に一致したファイルをで返します。bashでは、で実行可能ファイルの最初の一致を返しますが、一致し$PATHない場合は、非実行可能ファイルを返すことができます。また、zshでは、実行可能でないファイルを返すことはありません。
nyuszika7h 2017年

5
私が知る限りdash、これら3つのうちPOSIXに準拠していないのは1つだけです。[ -x "$(command -v COMMANDNAME)"]他の2つで動作します。このバグはすでに報告されているようですが、まだ応答がありません:bugs.debian.org/cgi-bin/bugreport.cgi
bug=

210

lhunathの使用を阻止することに同意しますwhich彼のソリューションはBashユーザーにとって完全に有効です。ただし、よりポータブルにcommand -vするために、代わりに使用する必要があります。

$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }

コマンドcommandはPOSIXに準拠しています。仕様についてはこちらをご覧ください:コマンド-簡単なコマンドを実行します

注:typeはPOSIXに準拠していますが、準拠していtype -Pません。


3
上記と同じ- exit 1;そこから呼び出された場合、xtermを強制終了します。
ユーザー不明の

1
これは標準のshでは機能しません。あなた&>は有効なリダイレクト命令ではありません。
jyavenard 2012年

7
@jyavenard:質問はbashとタグ付けされているため、より簡潔なbash固有のリダイレクト表記 &>/dev/nullです。しかし、私はあなたに同意します。本当に重要なことは移植性です。私はそれに応じて私の回答を編集し、標準のshリダイレクトを使用し>/dev/null 2>&1ます。
GregV 2012年

この回答をさらに改善するには、2つのことを行います。1:Joshの回答のように、 "&>"を使用して簡略化します。2:読みやすくするために、{}を余分な行に分割し、エコーの前にタブを配置します
knocte

誰かが望めば、私はこの1つのライナーをbash関数に入れました... github.com/equant/my_bash_tools/blob/master/tarp.bash
equant

94

これを簡単にする.bashrcに関数を定義しています。

command_exists () {
    type "$1" &> /dev/null ;
}

これがどのように使用されるかの例を示します(myから.bash_profile)。

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi

何をし&>ますか?
Saad Malik


&>ご使用のバージョンのBashでは使用できない場合があります。マルチェロのコードは問題なく動作するはずです。同じことをします。
Josh Strater、

3
ビルトインと予約語で失敗する:thenたとえば、単語でこれを試してください。に実行可能ファイルが存在する必要がある場合は、この回答を参照してください$PATH
トム・ヘイル

84

それが$PATH変数のディレクトリの1つに存在するかどうか、またはその絶対的な場所を知っているかどうかによって異なります。$PATH変数に含まれているかどうかを知りたい場合は、

if which programname >/dev/null; then
    echo exists
else
    echo does not exist
fi

そうでなければ使用する

if [ -x /path/to/programname ]; then
    echo exists
else
    echo does not exist
fi

/dev/null/最初の例のへのリダイレクトは、whichプログラムの出力を抑制します。


22
私のコメントで概説されている理由から、あなたは本当に「which」を使用すべきではありません。
lhunath 2009年

39

@lhunathと@GregVの答えを拡張して、ifステートメント内にそのチェックを簡単に入れたい人のためのコードを次に示します。

exists()
{
  command -v "$1" >/dev/null 2>&1
}

使用方法は次のとおりです。

if exists bash; then
  echo 'Bash exists!'
else
  echo 'Your system does not have Bash'
fi

13
学び、改善する意欲は報われる必要があります。+1これはクリーンでシンプルです。私が追加できる唯一のことは、commandエイリアスに対しても成功することです。これは多少直観に反するかもしれません。対話型シェルでの存在を確認すると、スクリプトに移動したときとは異なる結果が得られます。
Palec

1
私はテストしてshopt -u expand_aliasesエイリアスを無視/非表示にし(alias ls='ls -F'別の回答で述べたように)、shopt -s expand_aliasesを介してそれらを解決しますcommand -v。したがって、コマンドコールの出力を明示的にキャプチャして返さない場合、関数の戻り値に影響する可能性がありますが、チェックの前に設定し、後で設定解除する必要があります。
dragon788

24

使ってみてください:

test -x filename

または

[ -x filename ]

条件式の Bashマンページから:

 -x file
          True if file exists and is executable.

26
つまり、アプリケーションへの完全なパスをすでに知っている必要があります。
lhunath 2009年

12
OPは、特定のインスタンスをチェックするのか、実行可能インスタンスをチェックするのかを指定しませんでした...私はそれを私が読んだ方法で答えました。
dmckee ---元モデレーターの子猫

16

@lhunathが示唆するように、Bashスクリプトでを使用するにhashは:

hash foo &> /dev/null
if [ $? -eq 1 ]; then
    echo >&2 "foo not found."
fi

このスクリプトが実行hashされ$?、最新のコマンドの終了コードであるに保存されている値がに等しいかどうかが確認され1ます。hashが見つからない場合foo、終了コードはになります1。場合はfoo存在している、終了コードは次のようになります0

&> /dev/nullリダイレクト標準エラー標準出力からhash、それが画面上に表示されないようにし、echo >&2標準エラーにメッセージを書き込みます。


8
なぜif hash foo &> /dev/null; then ...ですか?
Beni Cherniavsky-Paskin

9

私がアクセスできるボックスで作業するために以前の答えを得ることはありませんでした。1つは、typeインストールされています(何をするかmore)。したがって、組み込みディレクティブが必要です。このコマンドは私にとってはうまくいきます:

if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi

3
大括弧はif構文の一部ではありませんif builtin type -p vim; then ...。単にを使用してください。また、バックティックは非常に古く、非推奨の構文で$()ありsh、すべての最新システムでもサポートされています。
nyuszika7h 2017

9

複数の依存関係を確認し、ステータスをエンドユーザーに通知する

for cmd in latex pandoc; do
  printf '%-10s' "$cmd"
  if hash "$cmd" 2>/dev/null; then
    echo OK
  else
    echo missing
  fi
done

出力例:

latex     OK
pandoc    missing

10コマンドの最大長に調整します。冗長ではないPOSIXの方法が見当たらないため、自動ではありません。 スペースで区切られたテーブルの列をBashで整列するにはどうすればよいですか?

いくつかのaptパッケージが一緒dpkg -sにインストールされているかどうかを確認し、そうでない場合はインストールします

参照:apt-getパッケージがインストールされているかどうかを確認し、Linuxにインストールされていない場合はインストールしてください

それは以前に言及されました:プログラムがBashスクリプトから存在するかどうかを確認するにはどうすればよいですか?


1
それを行う非冗長な方法:1)幅指定子を取り除きます。2)コマンド名のprintfの後にスペースを追加します。3)forループをcolumn -t(util-linuxの一部)にパイプします。
Patrice Levesque、2015

8

プログラムの存在を確認すると、おそらく後で実行することになります。そもそも実行してみませんか?

if foo --version >/dev/null 2>&1; then
    echo Found
else
    echo Not found
fi

これは、単にPATHディレクトリとファイルのアクセス許可を確認するよりも、プログラムが実行されていることの信頼できるチェックです。

さらに、バージョンなど、プログラムから有用な結果を得ることができます。

もちろん、欠点は、一部のプログラムは起動が重く、一部のプログラムは--versionすぐに(そして正常に)終了するオプションがないことです。


6

hash foo 2>/dev/null:Zシェル(Zsh)、Bash、Dashおよびashで動作します。

type -p foo:Zシェル、Bashおよびash(BusyBox)で動作するように見えますが、Dashでは動作しません(-p引数として解釈されます)。

command -v foo:Zシェル、Bash、Dashでは機能しますが、ash(BusyBox)では機能しません(-ash: command: not found)。

またbuiltin、ashとDashでは使用できません。


4

次のことができる場合は、Bashビルトインを使用します。

which programname

...

type -P programname

15
えっ? whichBashビルトインではありません。
tripleee 2013年

type -P programnameが優先されます。受け入れられた回答を参照してください
RobertG

@RobertG私が見るすべてはそれ-PがPOSIX ではないということです。なぜtype -P好まれますか?
mikemaccana 2018年

私は「bash環境で優先される」と言ったはずです-私はbash固有の以前のコメントに答えようと意図していたからです。とにかく、それは何年も前のことでした-もう一度言いますが、 "accpeted"とマークされた答えをあなたに示してください
RobertG

4

-vPOSIX_BUILTINSオプションが設定されている場合、コマンドは正常に動作します<command>テスト、そうでない場合は失敗する可能性があります。(それは私のために何年も働いていました、しかし私は最近それがうまくいかないものに出会いました。)

次の方がフェイルプルーフであることがわかります。

test -x $(which <command>)

パス、存在、実行許可の3つをテストするため。


動作しません。test -x $(which ls)0を返し、などしtest -x $(which sudo)ていても、lsインストールされ、実行可能とされてsudoも、私が実行しているドッキングウィンドウコンテナ内に設置されていません。
藻類

@algalあなたは私が思うに引用符を使用する必要があるのでtest -x "$(which <command>)"
JoniVR

@algalおそらくlsエイリアスされていますか?コマンドにパラメータがある場合は機能しないと思います。
AnthonyC

3

関心のある人にとって、インストール済みのライブラリを検出したい場合、以前の回答の方法はどれも機能しません。パス(ヘッダーファイルなどの可能性がある)を物理的にチェックするか、次のようなもの(Debianベースのディストリビューションを使用している場合)が残っていると思います。

dpkg --status libdb-dev | grep -q not-installed

if [ $? -eq 0 ]; then
    apt-get install libdb-dev
fi

上記からわかるように、クエリからの「0」の回答は、パッケージがインストールされていないことを意味します。これは「grep」の関数です。「0」は一致が見つかったことを意味し、「1」は一致が見つからなかったことを意味します。


10
しかし、アンチパターンがcmd; if [ $? -eq 0 ]; thenにリファクタリングする必要がありますif cmd; then
tripleee

これは、dpkgまたはを介してインストールされたライブラリに対してのみ機能しますapt
Weijun Zhou

3

ここにはたくさんのオプションがありますが、簡単なワンライナーに驚かされました。これは、スクリプトの冒頭で使用したものです。

[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }

これは、ここで選択した回答と別のソースに基づいています。


2

ぶら下がっているaliasesのため、ポータブルで100%信頼できる方法はないと思います。例えば:

alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/

もちろん、最後の1つだけが問題です(Ringoに害はありません!)。しかし、それらはすべてalias、の観点からは有効なes ですcommand -v

のようなぶら下がっているものを拒否するにringoは、シェルの組み込みaliasコマンドの出力を解析し、それらに再帰する必要command -vがあります(は、aliasここいるわけではありません)。そのためのポータブルソリューションはなく、Bash-特定のソリューションはかなり退屈です。

このようなソリューションは無条件に拒否されalias ls='ls -F'ます:

test() { command -v $1 | grep -qv alias }

いい視点ね。ただし、bashスクリプト内から実行すると、エイリアスは表示されません。
バジルムーサ

1
また、問題があります。「エイリアス」コマンドをチェックするとfalseが返されます。trueを返す必要がある場合。例:テスト「エイリアス」
バジルムーサ

2
私はテストし、使用shopt -u expand_aliasesしてこれらのエイリアスを無視/非shopt -s expand_aliases表示にし、を介して表示していcommand -vます。
dragon788 2017

2

これにより、プログラムが存在するかどうかが場所に応じて通知されます。

    if [ -x /usr/bin/yum ]; then
        echo "This is Centos"
    fi

はい、サーバ、Open suse、Centos、Debianにパッケージをインストールする必要がある場合は、このコマンドを追加しました
Klevin Kona

"echo"行で構文の強調表示がオフになっています。解決策は何ですか?Bashスクリプトが異なる必要があることを示唆していますか?
Peter Mortensen、

@PeterMortensen文字列であることを認識しないため、構文の強調表示はオフになっています。
エイドリアン

1

whichコマンドは便利かもしれません。男は

実行可能ファイルが見つかった場合は0を返し、見つからないか実行可能でない場合は1を返します。

NAME

       which - locate a command

SYNOPSIS

       which [-a] filename ...

DESCRIPTION

       which returns the pathnames of the files which would
       be executed in the current environment, had its
       arguments been given as commands in a strictly
       POSIX-conformant shell. It does this by searching
       the PATH for executable files matching the names
       of the arguments.

OPTIONS

       -a     print all matching pathnames of each argument

EXIT STATUS

       0      if all specified commands are 
              found and executable

       1      if one or more specified commands is nonexistent
              or not executable

       2      if an invalid option is specified

良い点whichは、実行可能ファイルが実行されている環境で使用可能かどうかを判断することwhichです。これにより、いくつかの問題が解消されます...


fooという名前の実行可能ファイルを探している場合はwhichを使用しますが、特定のファイル/ path / to / a / named / fooを確認する場合は、私の答えを参照してください。また、一部の最小限のシステムでは使用できない場合がありますが、本格的なインストールでは存在するはずです...
dmckee --- ex-moderator kitten

9
その終了ステータスに依存しないでください。多くのオペレーティングシステムは持っていても0以外の終了ステータスを設定しないいる
lhunath

1

Debianサーバーの私のセットアップ:

複数のパッケージに同じ名前が含まれていると問題が発生しました。

例えばapache2。これが私の解決策でした:

function _apt_install() {
    apt-get install -y $1 > /dev/null
}

function _apt_install_norecommends() {
    apt-get install -y --no-install-recommends $1 > /dev/null
}
function _apt_available() {
    if [ `apt-cache search $1 | grep -o "$1" | uniq | wc -l` = "1" ]; then
        echo "Package is available : $1"
        PACKAGE_INSTALL="1"
    else
        echo "Package $1 is NOT available for install"
        echo  "We can not continue without this package..."
        echo  "Exitting now.."
        exit 0
    fi
}
function _package_install {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install $1
            sleep 0.5
        fi
    fi
}

function _package_install_no_recommends {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install_norecommends $1
            sleep 0.5
        fi
    fi
}

1

もしあなたがここで答えのものがうまく機能せず、背中から髪を引っ張っているなら、を使って同じコマンドを実行してみてくださいbash -c。この陰鬱なせん妄を見てください。これは、$(サブコマンド)を実行したときに実際に起こっていることです。

最初。それはあなたに完全に異なる出力を与えることができます。

$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls

第二。それはあなたに全く出力を与えることができません。

$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found

この違いは、シェルのインタラクティブモードと非インタラクティブモードの違いによって発生します。〜/ .bashrcは、シェルが非ログインでインタラクティブな場合にのみ読み込まれます。2つ目は奇妙に見えます。これは、PATH環境変数の違いが原因である必要があるためですが、サブシェルは環境を継承します。
Palec、2015

私の場合.bashrc[ -z "$PS1" ] && return前にが付いている# If not running interactively, don't do anythingので、それが、非インタラクティブモードでのbashrcの明示的なソーシングでも役に立たない理由だと思います。この問題は、ss64.com / bash / source.htmlドット演算子を使用してスクリプトを呼び出すことで回避できますが、毎回入力. ./script.shすることを覚えておく必要はありません。
user619271

1
ソースを提供することになっていないスクリプトを調達することは悪い考えです。私が言おうとしていたのは、あなたの答えは、尋ねられる質問とはほとんど関係がなく、Bashとその(非)対話モードとは関係があるということです。
Palec、2015

これらのケースで何が起こっているかを説明している場合、それは回答への役立つ補足となります。
Palec、2015

0

ハッシュバリアントには1つの落とし穴があります。たとえば、コマンドラインで次のように入力できます。

one_folder/process

プロセスを実行します。このため、one_folderの親フォルダは$ PATHにある必要があります。ただし、このコマンドをハッシュしようとすると、常に成功します。

hash one_folder/process; echo $? # will always output '0'

4
「これを行うには、one_folderの親フォルダが含まれている必要があります$PATH」-これは完全に不正確です。それを試してみてください。これが機能するには、one_folderが現在のディレクトリにある必要があります。
ワイルドカード

0

「コマンド-v」の2番目の使用法。例えばこのように:

md=$(command -v mkdirhier) ; alias md=${md:=mkdir}  # bash

emacs="$(command -v emacs) -nw" || emacs=nano
alias e=$emacs
[[ -z $(command -v jed) ]] && alias jed=$emacs

0

CIサーバーのデプロイの一部としてGitがインストールされているかどうかを確認する必要がありました。私の最終的なBashスクリプトは次のとおりです(Ubuntuサーバー)。

if ! builtin type -p git &>/dev/null; then
  sudo apt-get -y install git-core
fi

3
git-coreがすでにインストールされている場合はapt-getが満たされ、終了するため、条件は、apt-getを実行するための起動時間を法として、あまり役に立たない。
tripleee

3
起動時間は無視できませんが、より重要な動機はsudo次のとおりです。条件なしでは、常に停止してパスワードを要求します(最近sudoを実行した場合を除く)。ところで、sudo -p "Type your password to install missing git-core: "プロンプトが突然出ないようにすると便利かもしれません。
Beni Cherniavsky-Paskin、2012年

0

Bashを模倣type -P cmdするために、POSIX準拠を使用できますenv -i type cmd 1>/dev/null 2>&1

man env
# "The option '-i' causes env to completely ignore the environment it inherits."
# In other words, there are no aliases or functions to be looked up by the type command.

ls() { echo 'Hello, world!'; }

ls
type ls
env -i type ls

cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }

7
なぜこれが支持されているのですか?これは実際にどのシステムで機能しますか?ほとんどのシェルtypeではaのようですが、builtinenv使用execvpして実行commandするcommandことはできないので、これは機能しませんbuiltin(そして、builtin常に同じ環境内で実行されます)。これは私のために失敗したbashksh93zshbusybox [a]shおよびdashそれらの全ては提供typeシェル組み込みとして。
AdrianFrühwirth2014

0

type利用可能な外部コマンドがない場合(ここで当然と見なされているように)、POSIX準拠を使用できますenv -i sh -c 'type cmd 1>/dev/null 2>&1'

# Portable version of Bash's type -P cmd (without output on stdout)
typep() {
   command -p env -i PATH="$PATH" sh -c '
      export LC_ALL=C LANG=C
      cmd="$1"
      cmd="`type "$cmd" 2>/dev/null || { echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; }`"
      [ $? != 0 ] && exit 1
      case "$cmd" in
        *\ /*) exit 0;;
            *) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
      esac
   ' _ "$1" || exit 1
}

# Get your standard $PATH value
#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp

少なくともMac OS X v10.6.8(Snow Leopard)では、Bash 4.2.24(2)を使用するcommand -v lsと、移動され/bin/ls-tempたと一致しません。


0

ケースでは、プログラムが存在するかどうかを確認したいと本当にプログラムではなく、組み込みコマンドバッシュで、その後、commandtypeおよびhash彼らとしてビルトインコマンドのすべての戻り0終了ステータスをテストするには適していません。

たとえば、time組み込みコマンドよりも多くの機能を提供するtimeプログラムがあります。プログラムが存在するかどうかを確認するには、次の例のように使用することをお勧めします。which

# First check if the time program exists
timeProg=`which time`
if [ "$timeProg" = "" ]
then
  echo "The time program does not exist on this system."
  exit 1
fi

# Invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt

0

同じ質問に答えたいが、Makefile内で実行したい。

install:
    @if [[ ! -x "$(shell command -v ghead)" ]]; then \
        echo 'ghead does not exist. Please install it.'; \
        exit -1; \
    fi

-1

脚本

#!/bin/bash

# Commands found in the hash table are checked for existence before being
# executed and non-existence forces a normal PATH search.
shopt -s checkhash

function exists() {
 local mycomm=$1; shift || return 1

 hash $mycomm 2>/dev/null || \
 printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n"; return 1;
}
readonly -f exists

exists notacmd
exists bash
hash
bash -c 'printf "Fin.\n"'

結果

 [ABRT]: notacmd: command does not exist
hits    command
   0    /usr/bin/bash
Fin.

-1

とても簡単なのでこれを使います:

if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then echo exists;else echo "not exists";fi

または

if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then
echo exists
else echo "not exists"
fi

シェルのビルトインとプログラムのエコーステータスを標準出力に使用し、標準エラーには何も使用しません。一方、コマンドが見つからない場合は、ステータスを標準エラーにのみエコーします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.