ひも

ひも

簡単なスクリプトを試してみたいです。

flag=false
while !$flag
do
   read x
   if [ "$x" -eq "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

ただし、実行時に入力するとandがtrue表示されますが、ループは終了しません。スクリプトにどのような問題がありますか?ブール変数を正しく反転する方法は?x="true"flag="true"

答え1

スクリプトには2つのエラーがあります。 1つ目は、!との間にスペースが必要です$flag。それ以外の場合、シェルはというコマンドを探します!$flag。 2番目のエラーは-eq整数比較のためのものですが、文字列に使用しています。シェルによってはエラーメッセージが表示され、条件が真になることができないか、整数以外のすべての値がゼロとして処理されるため、ループは永久に続行されます。を含む文字列を入力すると、[ "$x" -eq "true" ]ループはfalse次の数字で終了します。 0.

これは正しいですが、! $flag文字列をコマンドとして扱うことはお勧めできません。動作しますが、スクリプトの変更に非常に敏感です。またはそれ以外のもので$flagないことを確認する必要があるからです。ここでは、以下のテストのように文字列比較を使用する方が良いです。truefalse

flag=false
while [ "$flag" != "true" ]
do
   read x
   if [ "$x" = "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

あなたが求める論理を表現するより良い方法があります。たとえば、無限ループを作成し、終了条件が検出された場合はこれを中止できます。

while true; do
  read -r x
  if [ "$x" = "true" ]; then break; fi
  echo "$x: false"
done

答え2

Bashにはブール変数はありませんが、算術評価を使用してこれをエミュレートするのは非常に簡単です。

flag= # False
flag=0 # False
flag=1 # True (actually any integer number != 0 will do, but see remark below about toggling)
flag="some string" # Maybe False (make sure that the string isn't interpreted as a number)

if ((flag)) # Test for True
then
  : # do something
fi

if ! ((flag)) # Test for False
then
  : # do something
fi

flag=$((1-flag)) # Toggle flag (only works when flag is either empty or unset, 0, 1, or a string which doesn't represent a number)

これはkshでも動作します。すべてのPOSIX互換シェルで動作しても驚くことはありません。しかし、まだ標準を確認していません。

答え3

変数に0または1が含まれると確信している場合は、ビットXOR等号演算子を使用して2つの値を切り替えることができます。

$ foo=0
$ echo $foo
0
$ ((foo ^= 1))
$ echo $foo
1
$ ((foo ^= 1))
$echo $foo
0

答え4

シェルにはブール変数の概念はありません。
シェル変数は(文字列)のみであり、text場合によってはテキストを整数(10xaなど010)として解釈することができます。

したがって、aはflag=trueシェルに対して真または偽を意味しません。

ひも

できることは、文字列比較[ "$flag" == "true" ]または一部のコマンドで変数の内容を使用して確認することです。その結果、コマンドで実行(名前付き実行ファイルと名前付き実行ファイルのtrue両方があるため)し、そのコマンドの終了コードが0(成功)であることを確認するのと同じです。truefalse

$flag; if [ "$?" -eq 0 ]; then ... fi

またはより短く:

if "$flag"; then ... fi

変数の内容がコマンドとして使用されている場合、次のように2つの間にスペース()がある場合は、aを!使用してコマンドの終了状態を無効にできます。! cmd

if ! "$flag"; then ... fi

スクリプトは次のように変更する必要があります。

flag=false
while ! "$flag" 
do
   read x
   if [ "$x" == "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

整数

数字と算術拡張

この場合の終了コード$((0))はで1、終了コードは$((1))です0
bash、ksh、およびzshでは、a内で算術を実行できます(((..))始めがないことに注意してください)。$

flag=0; if ((flag)); then ... fi

このコードの移植可能なバージョンはより複雑です。

flag=0; if [ "$((flag))" -eq 0 ]; then ... fi      # test for a number
flag=0; if [ "$((flag))"  == 0 ]; then ... fi      # test for the string "0"

bash/ksh/zsh では、次のことができます。

flag=0    
while ((!flag)) 
do
   read x
   [ "$x" == "true" ] && flag=1
   echo "${x} : ${flag}"
done

または

「ブール変数を反転」できます(数値が含まれている場合)。

((flag=!flag))

そうだろう変化flagまたは0価値1


ノート:エラーがないか確認してください。https://www.shellcheck.net/多くの場合、問題をコードを発行する前に問題を見つけるのに十分です。

関連情報