Linuxシェルスクリプト:プログラムが存在する場合のみ実行し、存在しない場合は無視します


15

たとえば、適切なツールがインストールされている場合にのみ、実行中にステータスバナーを出力するLinuxシェルスクリプトをプログラミングしています(これは、システムパスで到達可能です)。 figlet

例:

#!/usr/bin/env bash
echo "foo"
figlet "Starting"
echo "moo"
figlet "Working"
echo "foo moo"
figlet "Finished"

私は仕事に私のスクリプトのために希望のエラーのない場合であっても、figletされてインストールされていません

何をすることができ実用的な方法



@sudodus: 'figlet'(およびそのパラメーター)コマンドを無視するだけで問題ありません。もちろん、継続的な実行。
ソパラホデアリエレス

2
この質問のタイトルは、あらゆる種類の形而上学的問題に私を
引き付けました-g_uint

2
すべてのエラーを無視しますか?使用するだけfiglet ... || trueです。
ジャコモアルゼッタ

終了コードを気にしない場合は、ショートカットを使用figlet || trueしますが、おそらく、バナーを印刷できない場合はプレーンテキストをエコーするシェル関数がおそらく必要です。
eckes

回答:


30

私の解釈では、ツールと同じ名前のラッパー関数を使用します。その関数で、存在する場合は実際のツールを実行します。

figlet() {
  command -v figlet >/dev/null && command figlet "$@"
}

その後figlet arg1 arg2...、スクリプトを変更しないでください。

@Olorinはより簡単な方法を思い付きました:必要な場合にのみラッパー関数を定義します(ツールが存在しない場合):

if ! command -v figlet > /dev/null; then figlet() { :; }; fi

figletfigletがインストールされていなくても引数を印刷したい場合は、Olorinの提案を次のように調整してください。

if ! command -v figlet > /dev/null; then figlet() { printf '%s\n' "$*"; }; fi

1
どこcommandから来たの?私のインストール環境にはありません(Red Hat 6.8 EnterpriseおよびCygwin64)。
eewanco

1
@ eewanco、unix.stackexchange.com / a / 85250/117549を参照してください。簡単に言えば、bashに組み込まれています。これはおそらくあなたのシェルです。
ジェフシャラー

4
commandPOSIX Bourneシェル組み込みです。通常、指定されたコマンドを実行しますが、-vフラグによりtype、別のシェル組み込みのように動作します。
ウォーム

@eewanco type -a commandが表示します。whichは、ビルトイン、キーワード、関数、エイリアスではなく、実行可能ファイルのみを表示します$PATH
l0b0

@ l0b0:bashの、デフォルトのプロファイル(S)とRedHatのファミリーにwhich ない、それはエイリアスので、該当するエイリアスを見つけwhich実行するために自分自身を/usr/bin/which(!)で見にシェルのエイリアスのリストを、それを、パイプは(もちろん\which別名を抑制し、エイリアスを表示しないプログラムのみを使用します。)
dave_thompson_085

14

figlet存在するかどうかをテストすることができます

if type figlet >/dev/null 2>&1
then
    echo Figlet is installed
fi

6

これを行う一般的な方法はtest -xakaを使用すること[ -xです。/etc/init.d/ntpLinuxシステムでの例を次に示します。

if [ -x /usr/bin/lockfile-create ]; then
    lockfile-create $LOCKFILE
    lockfile-touch $LOCKFILE &
    LOCKTOUCHPID="$!"
fi

この亜種は、実行可能ファイルの完全なパスを知っていることに依存しています。では/bin/lesspipeI組み合わせることにより、その周りに動作例見つかった-xwhichコマンドを:

if [ -x "`which bunzip`" ]; then bunzip -c "$1"
else echo "No bunzip available"; fi ;;

これによりPATHbunzip実行可能ファイルの場所を事前に知らなくても機能します。


4
使用しないでくださいwhich。そして、たとえwhich機能していても、test -xその出力での使用はばかげています:からパスを取得する場合which、それは存在します。
ジル 'SO-悪であるのをやめる'

1
@Gilles:技術的に言えtest -xば、ファイルが存在するかどうかを確認するだけではありません(それtest -eが目的です)。また、ファイルに実行権限が設定されているかどうかも確認します。
comfreak

@comfreakそうwhichです。
ジル 'SO-悪であるのをやめる'

5

スクリプトの開始時に、figlet存在するかどうかを確認し、存在しない場合は、何もしないシェル関数を定義します。

type figlet >/dev/null 2>&1 || figlet() { :; }

typefigletシェルのビルトイン、関数、エイリアス、またはキーワードとして存在するかどうかをチェックし、>/dev/null 2>&1出力を取得しないようにstdinとstdoutを破棄し、存在しない場合は何もしない関数としてfiglet() { :; }定義figletします。

この方法により、を使用するスクリプトのすべての行を編集しfigletたり、figlet呼び出されるたびに存在するかどうかを確認したりする必要がなくなります。

必要に応じて、診断メッセージを追加できます。

type figlet >/dev/null 2>&1 || { echo 'figlet not installed.' ; figlet() { :; } ; }

おまけに、使用しているシェルについては言及しなかったため、これはPOSIXに準拠していると思われるため、ほとんどのシェルで動作するはずです。


この答えのシンプルさが気に入っています。bashを使用type figlet >/dev/null 2>&1しているhash figlet 2>/dev/null場合は、に置き換えることもできます。(OPは「私のパスにある場合」と言いました。)
ジョー

5

別の選択肢-プロジェクト自動構成スクリプトで見たパターン:

if [ -x /usr/bin/figlet ]
then
    FIGLET=/usr/bin/figlet
else
    FIGLET=:
fi

$FIGLET "Hello, world!"

あなたの特定のケースでは、あなたもすることができます、

if [ -x /usr/bin/figlet ]
then
   SAY=/usr/bin/figlet
elif [ -x /usr/local/bin/figlet ]
then
   SAY=/usr/local/bin/figlet
elif [ -x /usr/bin/banner ]
then
   SAY=/usr/bin/banner
else
   SAY=/usr/bin/echo
fi

$SAY "Hello, world!"

特定のパスがわからない場合は、複数のelif場所を試して(上記を参照)既知の場所を試すか、PATHを使用して常にコマンドを解決します。

if command -v figlet >/dev/null
then
    SAY=figlet
elif command -v banner >/dev/null
then
    SAY=banner
else
    SAY=echo
fi

一般に、スクリプトを書くとき、私が指定した特定の場所でのみコマンドを呼び出すことを好みます。私は、エンドユーザーがPATH自分自身に、おそらく自分自身で入れたかもしれないものの不確実性/リスクが好きではありません~/bin

たとえば、呼び出している特定のコマンドの出力に基づいてファイルを削除する可能性のある複雑なスクリプトを他の人のために書いて~/binいた場合、コマンドであるかどうかにかかわらず、誤って何かを拾いたくない期待した。


3
またはにいた場合figletはどうなりますか?/usr/local/bin/home/bob/stuff/programs/executable/figlet
ジル 'SO-邪悪なことをやめる'

3
type -p figlet > /dev/null && figlet "foo"

bash typeコマンドは、コマンド、関数、エイリアス、キーワード、または組み込みコマンド(を参照help type)を見つけて、場所または定義を出力します。また、検索結果を表すリターンコードを返します。見つかった場合はtrue(0)。したがって、ここで行っているのはfiglet、パスで検索しようとしていることです(-p組み込みファイルや関数ではなく、ファイルのみを検索し、エラーメッセージを抑制します)。出力を破棄します(> /dev/nullそうです&&)。 、実行されfigletます。

figlet固定された場所にある場合、これは簡単です。

[ -x /usr/bin/figlet ] && /usr/bin/figlet "foo"

ここでは、testコマンド(別名[)を使用して、/usr/bin/figlet実行可能かどうか()を確認し、実行-x可能であれば(&&)実行します。このソリューションtypeは、使用するよりも移植性が高いと思います。

これを行う関数を作成できます:

function x() {
    if type -p "$1" >/dev/null; then
        cmd="$1"
        shift
        "$cmd" "$@"
    fi
}

(潜在的なスペースのために引用符が必要です)

その後、あなたはただやるでしょう:

x figlet "foo"

0

o /、次のように言います

#!/usr/bin/env bash
# if figlet is installed :
if [ "$(which figlet 2>/dev/null)" ]; then
       # do what you wanted to do
       echo "foo"
       figlet "Starting"
       echo "moo"
       figlet "Working"
       echo "foo moo"
       figlet "Finished"
# if not
else
       # exit program with an error
       echo "please install figlet"
       exit 1
fi

0

テストの実行、出力の抑制、成功/失敗コードのテストを行うことができます。このテストを安価にするには、figletの引数を選択します。-?または--helpまたは--versionは明らかな可能性です。

if figlet --help >/dev/null 2>&1 ; then
    # figlet is available
    echo "foo"
    figlet "starting"
    #etc
else
    rc=$?
    echo "figlet is not installed or not working correctly (return code ${rc})"
fi

以下のコメントへの応答として追加されました:フィグレットが使用可能であることではなく、実際にそのフィグレットが存在することをテストしたい場合は、

figlet --help >/dev/null 2>&1 
rc=$?
if [ $rc -eq 127 ] ; then # 127 is "command not found" on linux bash 4.4.23(1)
    echo "command figlet not found"
else
    figlet "whatever" # use figlet
fi

ここでの問題は、figletがインストールされていない以外の理由で失敗する可能性があるため、終了コードをテストするだけでは十分ではないことです。
クリス

インストールのみをテストしたい場合$?は、127(私のLinuxシステム上)に等しいかどうかをテストします。127は「コマンドが見つかりません」です。しかし、私が考えているのは、合理的なコマンドの場合、command --help失敗した場合、インストールは十分に中断され、そこにない可能性があるということです!
nigel222

1
126は「コマンドは検出されましたが、実行可能ではありません」ですので、同様にテストすることもできます。残念ながら、利用可能であることに依存することはできませ--helpん。Posixユーティリティには1つはありませんが、実際に posixガイドラインがそれに対して推奨しています。たとえば、でat --help失敗しat: invalid option -- '-'130システムで終了ステータスが表示されます。
クリス

また、もちろん、figletがステータス127で終了できる場合、これも問題になる可能性があります。
クリス

126についてのフェアポイントほとんど 正気のユーティリティのような軽量無害なコマンドオプションのいくつかの並べ替えを持っている-? --help --version...またはあなたが何かを見つけることができるfiglet -0 --illegalで終了し、そしてあなたの成功の指標としてその御馳走(それは127ではない限り、私はクラスと同じように妨害行為として)。
nigel222
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.