以下に基づく条件を持つスクリプトを作成しようとしています。変数がリストに表示されます:
#!/bin/bash
LIST=`ls`
function listcontains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && return 0 || return 1
}
if [ $(listcontains "${LIST}" "multi.sh") ] ; then
echo "Found!"
else
echo "Failed :("
fi
$(listcontains "${LIST}" "multi.sh")
echo returned $?
リストには「multi.sh」というファイルがあるため、「Found!」が予想されますが、上記のスクリプトでは「Failed:(」を報告します。後続の呼び出しは0を返します。
頑張った
if [ 0 -eq $(listcontains "${LIST}" "multi.sh") ] ; then
ところで、エラーが発生します。
./script.sh: 行9: [: 0: 単項演算子が必要
失敗:(
私がここで何を見逃しているのでしょうか?
ベストアンサー1
if [ $(listcontains "${LIST}" "multi.sh") ] ; then
関数は何も印刷しないので、コマンド置換はトークン化後にフィールドを生成しません。これは実行と同じで、if [ ]; then ...
間にパラメータがない場合はfalse状態を返します。[
]
[
引用符を使用してこれを行うと、空の文字列をlikeif [ "$(listcontains...)" ]; then
に渡し、false状態も返すので役に立ちません。 (括弧の間にパラメータがあり、そのパラメータがnullでないことを確認してください。)[
[ "" ]
コマンド置換自体の終了ステータスは、実行する他のコマンドがない場合にのみ表示されます。$(listcontains ...)
これは、後で1行でコマンドを単独で実行する場合です。
コマンドオーバーライドでテストするには、何かを印刷する必要があります。例えば
listcontains() {
if ...; then
echo yes
fi # else print nothing
}
if [ "$(listcontains ...)" ]; then
echo ok
fi
(またはと共にif [ "$(listcontains ...)" = yes ]; then ...
)
ただし、終了ステータスを直接表示できるため、これは必要ありません。
listcontains() {
if [[ ... ]]; then
return 0
fi
return 1
}
if listcontains ...; then
echo ok
fi
関数の終了状態は最後のコマンドの終了状態なので、関数を次のように単純化できます。
listcontains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]]
}
$2
ただし、内容に正規表現の特殊文字が含まれていても、内容が文字通り処理されるように引用したいと思います。
たとえば、上記の場合は単一の文字と一致するため、listcontains 'foo matchxsh bar' match.sh
一致が検索されます。.
一致しない括弧などの問題が発生する可能性があります。
一致する前に文字列の先頭と末尾にスペースを入れることで長さを短くすることもできます。
listcontains() {
[[ " $1 " =~ [[:space:]]"$2"[[:space:]] ]]
}
または、より多くのPOSIXlyを使用してDashでも使用できます。
listcontains() {
case " $1 " in
*[[:space:]]"$2"[[:space:]]*) return 0;;
*) return 1;;
esac
}