シェル言語

シェル言語

長い話を短く

私はこれについていくつかの調査を行いました、あなたは私がしたことを見ることができます詳細と私の試み部分。

私のコマンドは

date && echo "hi 1" && echo "1/0" | bc >/dev/null 2>&1 && echo "hi 2" && date +'%s'

私の予想/必要な出力は次のとおりです。

Tue, Nov 17, 2020  3:13:49 PM
hi 1

そして止めてください。私の考えは式の「echo/ bc」部分です(作業優先順位が括弧で示されていると仮定)

<part-before> echo "1/0" | bc >/dev/null 2>&1 ) && <part-after>

<part-after>目的が達成されないようにしてください。しかし、私実際出力(date現在のコマンドを使用)は次のとおりです。

Tue, Nov 17, 2020  3:13:49 PM
hi 1
hi 2
1605651229

質問:何も出力せずに失敗し、ゼロで割る問題で停止するにはどうすればよいですか?


(以降の内容は、より詳細な内容を提供するためのものです。)

クイックノート:リダイレクトがない場合でもゼロで割り切ることができなくても、チェーン、&&つまり短絡されたAND演算子チェーンは停止しません。より、

bballdave025@MACHINE ~
$ date && echo "hi 1" && echo "1/0" | bc && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:14:47 PM
hi 1
Runtime error (func=(main), adr=3): Divide by zero
hi 2
1605651287

bballdave025@MACHINE ~
$

bc私は主に$(( ))以下のようなbash-ismを避けるためにこの方法を使いたいと思います。 (bash-ismsについて言えば、努力しても&>/dev/null何も変わりませんでした。)以下の例のようなものを手に入れたいです。

bballdave025@MACHINE ~
$ date && echo "hi 1" && echo "$((1/0))" >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:15:17 PM
hi 1
-bash: 1/0: division by 0 (error token is "0")

bballdave025@MACHINE ~
$

しかし、私はエラーを望んでいません。 0で割った誤った結果が出力されない限り、つまり-edがなければechoエラーを取り除くことができます(これはリダイレクトの目的を崩します。stdoutstderr

### NOT WHAT I WANT, other than what is output ###
bballdave025@MACHINE ~
$ date && echo "hi 1" && ((1/0)) >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:15:44 PM
hi 1

bballdave025@MACHINE ~
### NOT WHAT I WANT, other than what is output. ###

より理論的な説明は次のとおりです。に0(ゼロ)を渡しています&&。何ですか?

私は見つけたこのソースアーカイブ)、すなわち

リダイレクトはコマンドではありません。

今はどこを見るべきかわかりません。


編集する:もう少し調べてみました。 2つの点を追加したい。

  1. 複数のソースが見つかりました。それらの一つアーカイブ)これはコアかもしれないと思いますが、それがどのように適用されるかはまだ理解されていません。その他アーカイブ)段落について説明しますが、これが重要であると考えられています。

  2. >/dev/null誤って交換したときに奇妙な動作が見つかり、バグが>dev/null発生しました。後ろに問題をゼロで割ります。これが私が見るものです。

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:41:39 PM
hi 1
-bash: dev/null: No such file or directory

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:41:48 PM
hi 1
-bash: dev/null: No such file or directory

bballdave025@MACHINE ~
$

正直なところ、これは特に最初の、おそらくコアソースを考慮すると、より混乱しています。


詳細と私の試み

私はより大きな実行可能ファイルを含むより長いチェーンを構築するために&&チェーンとリダイレクトを理解しようとしています。/dev/null私も知りたいコマンドリスト区切り記号アーカイブ)一般的に言えば、これらの実行可能ファイルがどのように連携するかに関係なく、ここで何が起こっているのかを本当に理解したいと思います&&

私は実際の例に進む前にこのおもちゃの例に取り組んできました。私は問題を見つけることができるかどうかを確認するために「戻る作業」しようとしてきました。おそらくこれは問題を解決するのに役立ちます。

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:16:41 PM
hi 1
hi 2
1605651401

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:16:52 PM
hi 1
hi 2
1605651412

## LET'S SEE WHAT GETS SENT TO /dev/null

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:17:06 PM
hi 1
hi 2
1605651426

bballdave025@MACHINE ~
$ cat abc
1

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:17:18 PM
hi 1
hi 2
1605651438

bballdave025@MACHINE ~
$ cat abc
Runtime error (func=(main), adr=3): Divide by zero

## LET'S TRY GIVING IT ANOTHER ERROR RIGHT AFTER

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:24:35 PM
hi 1
-bash: dev/null: No such file or directory

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:00 PM
hi 1
-bash: dev/null: No such file or directory

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:14 PM
hi 1
hi 2
1605651914

bballdave025@MACHINE ~
$ cat abc
1

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:24 PM
hi 1
hi 2
1605651924

bballdave025@MACHINE ~
$ cat abc
Runtime error (func=(main), adr=3): Divide by zero

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" | bc >abc/def 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:41 PM
hi 1
-bash: abc/def: Not a directory

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" | bc >abc/def 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:25:46 PM
hi 1
-bash: abc/def: Not a directory

## GO BACK WITHOUT `bc` and without redirection

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:29:03 PM
hi 1
hi 2
1605652143

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" >/dev/null 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:29:12 PM
hi 1
hi 2
1605652152

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:29:21 PM
hi 1
hi 2
1605652161

bballdave025@MACHINE ~
$ cat abc
1/1

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" >abc 2>&1 && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:29:29 PM
hi 1
hi 2
1605652169

bballdave025@MACHINE ~
$ cat abc
1/0

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$b" && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:30:09 PM
hi 1
1/1
hi 2
1605652209

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "$a/$c" && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:30:14 PM
hi 1
1/0
hi 2
1605652214

bballdave025@MACHINE ~
$ a=1; b=1; c=0; date && echo "hi 1" && echo "hi 2" && date +'%s'
Tue, Nov 17, 2020  3:30:26 PM
hi 1
hi 2
1605652226

bballdave025@MACHINE ~
$

このSO交換アーカイブ)役に立つものがあるかもしれません。

答え1

リダイレクトがなくてもゼロで除算できない場合でも、「and」演算子の段落チェーン&&チェーンは停止しません。

GNU BC:

$ echo "1/0" | bc 
Runtime error (func=(main), adr=3): Divide by zero
$ echo $?
0

忙しい箱:

$ echo "1/0" | busybox bc 
bc: divide by zero
$ echo $?
1

POSIX BC:

名前
bc - 任意精度算術言語の
終了状態
次の終了値を返す必要があります。
0 - すべての入力ファイルが正常に処理されました。
指定しない - エラーが発生しました。

根拠
エラー条件の終了状態は、いくつかの理由で指定されません。

  • bcユーティリティは、対話型状況と非対話型状況の両方で使用できます。両方の目的に異なる終了コードが適している可能性があります。
  • ゼロ以外の出口がいつ提供されるべきかは明確ではない。ゼロ除算、未定義関数、および構文エラーの両方が可能です。
  • 終了状態がどの用途に使用されるかは不明です。

BCはゼロで割ることが間違った終了状態を返す価値がないと思うので、チェーンは壊れません。

ただし、GNU bc は、入力ファイルを読み取れない場合、無効な終了状態を返します。

私は主に後で$(())のようなbash-ismsを避けるためにbcメソッドを使用したいと思います。

$(( ))バシズムではなくバシズムの一部POSIXシェル言語(算術拡張)


&&ここでの文脈が何であるか、ゼロで割ることが条件やチェーンとどのように関連するのか、最終的に何をしたいのか分からないので、アドバイスを提供することは困難です。

ゼロで除算を検出する別の方法は、まず、除算を試みる前に除算がゼロであることを確認することです。

答え2

これは、XYの問題、パイプ、出力、および分割の問題が混在しています。答えるべき「単一」の質問があるようには思えませんが、これを明確にしようとします。

シェル言語

グループ

echo "before" && echo inside1 && echo inside2 && echo "after"

複数のステートメントをグループ化する方法は、括弧または中括弧を使用することです。

echo "before" && ( echo inside1 && echo inside2 ) && echo "after"
echo "before" && { echo inside1 && echo inside2; } && echo "after"

()サブシェルで実行され、{ }単に現在の環境でリストを形成します。どちらもそのセクションの出力をリダイレクトするために使用できます。

echo "before" && ( echo inside1 && echo inside2 ) > /dev/null && echo "after"
echo "before" && { echo inside1 && echo inside2; } > /dev/null && echo "after"

戻り値

各コマンドは完了後に値を返します。$?お使いいただけるように保存されています。echo $? 実行直後

成功を示すには 0 を返し、失敗を示すには 0 以外の値を返すのがルールです。どんな計画でも成功と見なすことができます。 and&&およびまたは||シェル演算子はこの概念を利用します。また、常に0(成功)と0以外の値(失敗)を返すtrueandという便利なユーティリティもあります。false

if true && false; then
 echo Yes
else
 echo No
fi

series を連結すると、&&演算子の右側は左が成功を返す場合にのみ実行されます。

photosたとえば、というフォルダを作成し、すべてのファイルをそのフォルダに移動できます。

まず試してみてください。

mv *.jpg photos

ただし、写真が1つだけでphotosフォルダがない場合は、写真の名前がに変わりますphotos

フォルダが正常に作成されたら、そのフォルダを使用して画像を移動することができます&&

mkdir photos && mv *.jpg photos

mkdir失敗するとmv実行されません。

mkdirこれは、失敗するとゼロ以外の値が返されるためです。

ただし、フォルダがphotosすでに存在する場合は、mkdirエラー条件も返されます(フォルダを作成できません)。

したがって、より複雑な検査は次のようになります。

( test -d photos || mkdir photos ) && mv *.jpg photos/

photosがすでにディレクトリの場合は、ディレクトリを作成しようとせずに画像の移動に移動します。ただし、photosディレクトリではありませんが、作成できる場合は成功し、写真を移動します。

写真がフォルダ(またはフォルダへのシンボリックリンク)ではなく、作成されていない場合、左側の部分は&&失敗し、写真は移動しません。

注:この特定の例では、より簡単なものを使用できますmkdir -p photos && mv *.jpg photos/-pフラグを使用すると、mkdirは中間フォルダを作成し、フォルダがすでに存在する場合は終了しませんが、説得力が少ないためです。

管路

パイプがある場合、デフォルトではパイプの戻り値は最も右側のコマンドの1つです。実行すると

command1 | command2 | command3

パイプライン全体の戻り値はの戻り値になりますcommand3command1あるいはcommand2、ゼロ以外の値を返すことは重要ではありません。pipefail戻り値が次のいずれかになるようにオプションを設定して変更できます。ゼロ以外の値を返すパイプラインの一番右のコマンド

0で割る

あなたの場合、ゼロで割る試みの診断を画面に提供しても、ゼロコードが実際に返されるecho 1/0 | bcため、パイプラインは停止しません。bc

$((1/0))拡張機能でエラーが発生するため、直接実行する際に問題があります。新しいシェルプロセスでラップできます。

echo hi1 && bash -c 'echo $((1/0))' 2> /dev/null && echo hi2

それとも単なるサブシェルかもしれません。

echo hi1 && ( echo $((1/0))' ) 2> /dev/null && echo hi2

実際には基本的な解決策があります。除数がゼロであることを確認する。たとえば、

division() {
  if [ "$2" -eq 0 ]; then
     return 1
  fi
  echo "$(( $1 / $2 ))"
}

echo hi1 && division 1 0 && echo hi2

関数を使用して同様の操作を実行することもできますbc(ただし、何も出力せずに0を出力します)。

define division(x,y) {
   if (y == 0) return;
   return x/y;
}
division(1,0)

関連情報