web-dev-qa-db-ja.com

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

私はLinux Shell scriptをプログラミングしています。これは、適切なツール、たとえばfigletinstalledである場合にのみ、実行中にステータスバナーを印刷します==(これは到達可能ですシステム上path)。

例:

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

figletインストールされていないの場合でも、スクリプトが機能するようにしたいエラーなし.

実用的な方法は何でしょうか?

15

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

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

次に、figlet arg1 arg2...スクリプトで変更なし。

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

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

Figletがインストールされていない場合でもfigletへの引数を出力する場合は、Olorinの提案を次のように調整してください。

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

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

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

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

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

この亜種は、実行可能ファイルの完全なパスを知っていることに依存しています。 /bin/lesspipeで、-xwhichコマンドを組み合わせて、この問題を回避する例を見つけました。

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

そうすれば、PATHのどこにbunzip実行可能ファイルがあるかを事前に知らなくても、これは機能します。

6
kasperd

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

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

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

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

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

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

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

5
Chris

別の代替案-プロジェクトの自動構成スクリプトで見たパターン:

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で誤って何かを取得したりしたくない、または期待したコマンドではないかもしれません。

5
rrauenza
type -p figlet > /dev/null && figlet "foo"

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

テストの実行、出力の抑制、成功/失敗コードのテストを行うことができます。このテストを安価にするために、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
0
nigel222

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
Jus de Patate_