web-dev-qa-db-ja.com

シェルスクリプトのwhileループ:[パイプラインの周りに `] 'がありません

私が使用しようとしているシェルスクリプトが次のエラーを出し続けます。

$ ./script.sh: line 2: [: missing `]' 
grep: ]: No such file or directory

この行は、特定のプロセスがファイルをロックするかどうかを確認しようとするセクションの一部です。

COUNTER=0
while [ ps aux | grep "[r]elayevent.sh" ] && [ "$COUNTER" -lt 10 ]; do
    sleep 3
    let COUNTER+=1
done

明らかに、角かっこがすべて正しくペアになっていることを確認しました-私には問題ありません。また、条件の問題の周りにある一般的な空白は適用されません。

ここで何が欠けていますか?

4
Kiwi Cam

エラーは、終了ステータスを確認してから直接コマンドを使用するため、最初に_[_を削除する必要があることです。

Shellcheckツール のWikiページには、これに関する説明があります( issue SC1014 ):

_[ .. ]_は、ifステートメントのようなシェル構文の一部ではありません。 Cライクな言語の括弧if (foo) { bar; }と同等ではないため、テストするコマンドを囲む必要はありません。

_[_は、whoamiまたはgrepのような通常のコマンドですが、おかしな名前が付いています(_ls -l /bin/[_を参照)。これは、testの省略形です。

特定のコマンドの終了ステータスを確認する場合は、そのコマンドを直接使用します。

コマンドの出力を確認する場合は、"$(..)"を使用して出力を取得し、次にtestまたは_[_/_[[_を使用して文字列を比較します。

また、_ps aux | grep -q "[r]elayevent.sh"_を使用して、stdoutに何かを出力する代わりに、サイレントモードで終了ステータスを取得します。

または、pgrepを使用して、その出力を_/dev/null_に送信することもできます。

最後のケースの方が効率的であるため、最初に2番目の条件を使用します。

したがって、最終的なスクリプトは次のようになります。

_#!/bin/bash
COUNTER=0

while [ "$COUNTER" -lt 10 ] && ps aux | grep -q "[r]elayevent.sh"   ; do

    sleep 3

    let COUNTER+=1

done
_

または

_#!/bin/bash
COUNTER=0

while [ "$COUNTER" -lt 10 ] && pgrep  "[r]elayevent.sh" >/dev/null  ; do

    sleep 3

    let COUNTER+=1

done
_
7
Prvt_Yadav

[ ... ]内にパイプを置くことはできません。また、pgrepの出力を解析するよりも、psを使用する方が適切です。

count=0
while [ "$count" -lt 10 ] && pgrep relayevent.sh >/dev/null; then
    sleep 3
    count=$(( count + 1 ))
done

BSDシステムは、通常のpgrepと同様に、grepの実際の出力を破棄するためにpgrep -q ...ではなくpgrep ... >/dev/nullを使用できます(終了ステータスのみに関心があります) 。

pgrepコマンドを[ ... ]内に配置しないことに注意してください。これは、出力には関心がなく、終了ステータスのみに関心があるためです。 [ ... ]を使用すると、通常、文字列または数値を比較します。 [ ... ]は、pgrepの実行と同様に、終了ステータスがゼロ(true)または非ゼロ(false)になります。

ただし、これは、特定のプロセスが実行されているかどうかだけをチェックして、ロックメカニズムをチェックしません。

スクリプトのインスタンスを1つだけ実行する場合は、次のようにすることをお勧めします(EXITトラップは、スクリプトが正常に終了するたびに実行されると想定しています)。

lockdir=dir.lock

if mkdir "$lockdir"; then
    trap 'rmdir "$lockdir"' EXIT
else
    echo 'Only one instance of this script allowed' >&2
    exit 1
fi

何度も試行錯誤して:

lockdir=dir.lock

count=0
while [ "$count" -lt 10 ]; then
    if mkdir "$lockdir"; then
        trap 'rmdir "$lockdir"' EXIT
        break
    else
        echo 'Locked. Sleeping...' >&2
        sleep 3
    fi

    count=$(( count + 1 ))
done

if [ "$count" -eq 10 ]; then
    echo 'Giving up.' >&2
    exit 1
fi

関連:

2
Kusalananda