応答に「接続成功」という文字列が含まれるまでbashスクリプトでこのコマンドを繰り返すにはどうすればよいですか?

応答に「接続成功」という文字列が含まれるまでbashスクリプトでこのコマンドを繰り返すにはどうすればよいですか?

私はこれでどこにも行けません。

10回繰り返し、出力に「Connection成功した」文字列が含まれている場合は、中断されるbashスクリプトを作成したいと思います。

ret=$?thenと同じことを試しましたが、1であっても引き続きif [$ret -ne 0]elseステートメントが表示されます。ret

今、「接続成功」という単語を見つけようとしていますが、その構文の使い方がわかりません。

だから私は次のようなものが欲しい:

for i in {1..10}
do
  ret=bluetoothctl connect 26:EE:F1:58:92:AF | grep "connection successful"

  if [$ret -ne ""]; then
    break
  fi
done

しかし、明らかに正しい構文を使用すると、$ret=bluetoothctl connect 26:EE:F1:58:92:AF | grep "connection successful"

どんな助けでも大変感謝します。

答え1

grep一部のテキストがパターンと一致するかどうかをテストする場合は、出力を保存する必要はほとんどありません。代わりにオプションをgrep使用して呼び出し-qて、終了状態に応じて対処してください。

#!/bin/sh

tries=10

while [ "$tries" -gt 0 ]; do
    if bluetoothctl connect '26:EE:F1:58:92:AF' | grep -q 'connection successful'
    then
        break
    fi

    tries=$(( tries - 1 ))
done

if [ "$tries" -eq 0 ]; then
    echo 'failed to connect' >&2
    exit 1
fi

失敗および成功時に正常な終了状態が返される場合、ループのステートメントはbluetoothctl不要で、次のように短縮できgrepます。if

if bluetoothctl connect '26:EE:F1:58:92:AF' >/dev/null
then
    break
fi

実際には、bluetoothctlループ条件を一部として含めることもできます(ここに示すように、forループからループの使用に切り替えると仮定します)。while

#!/bin/sh

tries=10

while [ "$tries" -gt 0 ] && ! bluetoothctl connect '26:EE:F1:58:92:AF'
do
    tries=$(( tries - 1 ))
done >/dev/null

if [ "$tries" -eq 0 ]; then
    echo 'failed to connect' >&2
    exit 1
fi

使用を検討してくださいhttps://www.shellcheck.netシェルスクリプトの構文を確認してください。問題のスクリプトについては、テストには次のスペースが必要であると指定されています[ ... ]

  if [$ret -ne ""]; then
  ^-- SC1009 (info): The mentioned syntax error was in this if expression.
     ^-- SC1035 (error): You need a space after the [ and before the ].
     ^-- SC1073 (error): Couldn't parse this test expression. Fix to allow more checks.
                  ^-- SC1020 (error): You need a space before the ].
                  ^-- SC1072 (error): Missing space before ]. Fix any mentioned problems and try again.

空でない文字列のテストは、または[ -n "$ret" ]を使用して実行されます[ "$ret" != "" ]-neこれは山水テスト。

また、パイプの出力をret。あなたが使う計画は

ret=$( bluetoothctl ... | grep ... )

答え2

Kusalanandaはコードを改善する方法についてのヒントを提供しますが、正確に何が間違っているかを説明しません。復習してみましょう:

ret=$?私はthenのようなものを試しましたが、if [$ret -ne 0]retが1にもかかわらずまだelseステートメントを取得します。

[はコマンドなので、コマンドと引数の間にスペースを入れる必要があります。それ以外の場合、引数はコマンド名の一部として理解されます。retに設定すると、1bashはエラーを印刷し、[1: command not foundエラーifにはfalseを表示する必要があります。繰り返しますが、[最後のパラメータは必須ですが、]そうではありません0]。そこにもスペースが必要です。

あなたが望むもの:

if [ "$ret" -ne 0 ]

次の部分:

ret=bluetoothctl connect 26:EE:F1:58:92:AF | grep "connection successful"

ここで行うことは、コマンド(存在しない可能性があります)に値を持つ環境変数をconnect 26:EE:F1:58:92:AF | grep "connection successful"提供しながらパイプラインを実行することです。connectretbluetoothctl

出力を収集するには、コマンドを次にまとめる必要があります$()

  ret="$(bluetoothctl connect 26:EE:F1:58:92:AF | grep "connection successful")"

これで:

  if [$ret -ne ""]; then

空白の欠落と同じ問題がありますが、より深く理解すると、基本的にほとんどの項目は bash で暗黙的に文字列であり、引用符はほとんどの拡張の一部の詳細を制御することに加えて、より明示的な方法にすぎないということです。つまり、[$ret -ne ""]次のようにほぼ正確に計算されます。

[$ret -ne ]
[$ret -ne ""''""'']
"["$ret "-ne" """]"
"["$ret"" "-ne""""" """]"""

空の場合$retと同じです[ -ne ]。空でない文字列であることを確認するために検証される引数(無視])が1つしかないため、trueと評価されます。[-ne

$retそれと似たようなものは、引用符がないためfoo bar bazにトークン化され、[foo bar baz -ne ]4つの引数(インクルード)を取り、]bashがコマンドを見つけることができないため、falseのコマンドを取得します[foo$retlikeを引用すると、2つの引数(含む)があり、bashがコマンドを見つけることができないため、falseになる["$ret" -ne ""]同等の結果が得られます。"[foo bar baz" -ne ]][foo bar baz

ここで犯すもう一つの間違いは、-ne特に数値比較に使用することです。空白と引用符の問題を解決しても、bashはエラーを引き起こしますinteger expression expected。あなたが望むのは!=文字列比較のためのものです。

これらすべての問題を要約して解決するには、次のものが必要です。

if [ "$ret" != "" ]; then

次のように書くこともできます。

if [ -n "$ret" ]; then

または

if [ "$ret" ]; then

関連情報