私はLinux Shell scriptをプログラミングしています。これは、適切なツール、たとえばfiglet
がinstalledである場合にのみ、実行中にステータスバナーを印刷します==(これは到達可能ですシステム上path)。
例:
#!/usr/bin/env bash
echo "foo"
figlet "Starting"
echo "moo"
figlet "Working"
echo "foo moo"
figlet "Finished"
figlet
がインストールされていないの場合でも、スクリプトが機能するようにしたいエラーなし.
実用的な方法は何でしょうか?
私の解釈では、ツールと同じ名前のラッパー関数を使用します。その関数で、実際のツールが存在する場合はそれを実行します。
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
figlet
が存在するかどうかをテストすることができます
if type figlet >/dev/null 2>&1
then
echo Figlet is installed
fi
これを行う一般的な方法は、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
で、-x
とwhich
コマンドを組み合わせて、この問題を回避する例を見つけました。
if [ -x "`which bunzip`" ]; then bunzip -c "$1"
else echo "No bunzip available"; fi ;;
そうすれば、PATH
のどこにbunzip
実行可能ファイルがあるかを事前に知らなくても、これは機能します。
スクリプトの開始時に、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に準拠しているので、ほとんどのシェルで動作するはずです。
別の代替案-プロジェクトの自動構成スクリプトで見たパターン:
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
で誤って何かを取得したりしたくない、または期待したコマンドではないかもしれません。
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"
テストの実行、出力の抑制、成功/失敗コードのテストを行うことができます。このテストを安価にするために、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
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