ブール変数を反転


26

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

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

しかし、私はそれを実行すると、I型の場合true、私はそれを見ますx="true"flag="true"、しかし、サイクルが終了していません。スクリプトの何が問題になっていますか?ブール変数を適切に反転するにはどうすればよいですか?



THX!私は今それを手に入れました
繁殖

回答:


21

スクリプトには2つのエラーがあります。最初は、あなたが間にスペース必要があるということです!$flag、呼ばれるコマンドのためのそれ以外のシェルルックスを!$flag。2番目のエラーは-eq整数比較のためですが、文字列で使用しています。シェルに応じて、エラーメッセージが表示され、条件[ "$x" -eq "true" ]が真になれないためループが永久に継続するか、整数以外のすべての値が0として扱われ、文字列(を含む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

[組み込みではksh、算術式[ x -eq y ]x算術式と同じ数に解決される場合にtrueを返すyため、たとえばx=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'yesが出力されます。
ステファンシャゼラス

10

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準拠のシェルで動作するのであれば、驚かないでしょうが、標準はチェックしていません。


1
! ! ((val))CやC ++のように、Bashでも機能しますか?たとえば、valが0の場合、その後は0のまま! !です。val1の場合、その後も1のまま! !です。val8の場合、後に1にプルダウンされ! !ます。または、別の質問をする必要がありますか?

1
-1 | POSIX shでは、スタンドアロン((..))は未定義です。それへの参照を削除してください
LinuxSecurityFreak

Vlastimilの質問は具体的にはbashについてであり、posixシェルについてではありません。質問がそのトピックに関するものではないのに、なぜ反対票を投じるのですか?
ニック・ブル

6

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

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

2

これは私のために働く:

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

しかし、実際には、あなたがすべきことは次のものに置き換えることですwhile

while ! $flag

0

シェルにはブール変数の概念はありません。
シェル変数は、可能性がtextある場合に、そのテキストが(整数として解釈することができる、(文字列)、および10xa010、など)。

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

ひも

何行うことができることのいずれかの文字列の比較である[ "$flag" == "true" ]か、いくつかのコマンドで変数の内容を使用してチェックし、その結果を実行するように、true(両方の実行ファイルが呼び出されがあるのでtrue、もう1つは呼ばれるfalseそのコマンドの終了コードがゼロの場合)コマンドとして、チェック(成功)。

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

または短く:

if "$flag"; then ... fi

変数の内容をコマンドとして!使用する場合、次のように、両方の間にスペースが存在する場合(! cmd)、コマンドの終了ステータスを無効にするためにa を使用できます。

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

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

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

整数

数値と算術展開を使用します。

この場合、$((0))is 1の終了コードと$((1))isの終了コードです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/でエラーを確認してください。問題を見つけるのに十分な回数です。


0

untilwhile !(およびBourne とuntilは反対に!)の略であるため、次のことができます。

flag=false
until "$flag"
do
   IFS= read -r x
   if [ "$x" = true ]
   then
     flag=true
   fi
   printf '%s\n' "$x : $flag"
done

次と同じである必要があります:

flag=false
while ! "$flag"
do
   IFS= read -r x
   if [ "$x" = true ]
   then
     flag=true
   fi
   printf '%s\n' "$x : $flag"
done

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

until
   IFS= read -r x
   printf '%s\n' "$x"
   [ "$x" = true ]
do
   continue
done

until/ whileとの間の部分は、do単一のコマンドである必要はありません。

!POSIXシェル構文のキーワードです。区切り記号で区切る必要があります。トークンはパイプラインに先行する最初のトークンである必要があります(! foo | barパイプラインをfoo | ! bar無効にし、一部のシェルは拡張として受け入れますが、無効です)。

!true!true存在する可能性が低いコマンドとして解釈されます。! true動作するはずです。!(true)そのようPOSIX準拠のシェルで動作するはずです!、それが続いていますとして区切られ(たトークンが、中に実際には仕事をしないksh/ bash -O extglobそれはと競合するところ!(pattern)(SHエミュレーションを除く)、拡張グロブ演算子やzshのそれはと競合するところglob(qualifiers)bareglobqualし、glob(group)なし。


-1
[ ${FOO:-0} == 0 ] && FOO=1 || FOO=0

あるいは:

[ ${FOO:-false} == false ] && FOO=true || FOO=false

仕事をするべきです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.