||で複数のコマンドを使用しない理由 または&&条件付き作業?


12

これは、シェル(bash、dash)プロンプトで機能します。

[ -z "" ] && echo A || echo B
A

ただし、私はPOSIXシェルスクリプトを記述しようとしています。

#!/bin/sh

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

readonly raw_input_string=${1}

[ -z "${raw_input_string}" ] && echo "The given argument is empty."; exit 1

理由はわかりませんが、メッセージが表示されません

指定された引数は空です。

このようなスクリプトを呼び出すと:

./test_empty_argument ""

何故ですか?


5
変数が空であるか、スペースのみが含まれているかどうかをテストするにはどうすればよいですか?を参照してください 変数が空であるか、設定されていないか、または空白のみが含まれているかをテストする方法。この質問の問題はそれとは何の関係もありません。
-ilkkachu

1
使用するだけif [ X”” = X”$var” ] ; then echo isempty ; fi
user2497

3
@ user2497過去20年間にリリースされたシェルでそれを使用する理由はありません。これは、古いバグのあるシェルの回避策です。
-chepner

@chepnerだから、それは有効な解決策ではありませんか?他の何かを使用する必要がありますか?
user2497

6
[ "" = "$var" ]うまくいくでしょう。引用された空の文字列は、の引数リストから削除されません[。しかし、それ[ -z "$var" ] 必要ありません。これうまく機能するからです。
chepner

回答:


37

あなたの行に注意してください

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

これはと同じです

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."
exit 1

(引用符なし ;ほとんどの場合、文字は改行文字に置き換えることができます)

これは、 exit 1、スクリプトに渡された引数の数に関係なくステートメントが常に実行されるます。これは、メッセージThe given argument is empty.が印刷される可能性がないことを意味します。

「短絡構文」を使用してテスト後に複数のステートメントを実行するには、ステートメントをにグループ化し{ ...; }ます。別の方法は、適切なifステートメントを使用することです(私見では、スクリプトではよりきれいに見えます)。

if [ "$#" -ne 1 ]; then
    echo 'Invalid number of arguments, expected one.' >&2
    exit 1
fi

2回目のテストでも同じ問題が発生します。


に関して

[ -z "" ] && echo A || echo B

これは指定された例では機能しますが、一般的な

some-test && command1 || command2

と同じではないだろう

if some-test; then
    command1
else
    command2
fi

代わりに、それはより似ています

if ! { some-test && command1; }; then
    command2
fi

または

if some-test && command1; then
    :
else
    command2
fi

つまり、テストまたは最初のコマンドのいずれかが失敗すると、2番目のコマンドが実行されます。つまり、関連する3つのステートメントすべてを実行できる可能性があります。


18

この:

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

ではありません:

[ "${#}" -eq 1 ] || { echo "Invalid number of arguments, expected one."; exit 1; }

しかし、代わりに:

{ [ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; } 
exit 1

スクリプトは、渡された引数の数に関係なく終了します。


8

より読みやすくする1つの方法は、次のようなdie関数(àla perl)を定義することです。

die() {
  printf >&2 '%s\n' "$@"
  exit 1
}

# then:

[ "$#" -eq 1 ] || die "Expected one argument, got $#"

[ -n "$1" ] || die "Empty argument not supported"

必要に応じて、色、接頭辞、行番号などの追加機能を追加できます。


実際にはdie、複数の引数で関数を呼び出すことはありますか?(もしそうなら、例を挙げてもらえますか?)私はほとんど同じdie機能を使用していますが、"$*"代わりに使用します。
jrw32982は

3
の価値"$@"は、リテラル改行を追加する必要なく複数行メッセージを許可することです。
チャールズダフィー

1
@ jrw32982、"$*"引数をスペースで結合するために使用することは、変更された$IFSコンテキストを含むすべてのコンテキストで機能するためにSPC に設定する必要があることも意味します$IFS。または、ksh/ zshを使用するprint -r -- "$@"echo -E - "$@"、またはで使用できますzsh
ステファンシャゼラス

@CharlesDuffyはい、しかし、-type関数のコンテキストでそれを見たことはありませんdie。私が求めているのは、実際にはdie "unable to blah:" "some error"、2行のエラーメッセージを取得する目的で誰かが書いているのを見たことがありますか?
jrw32982は、

@StéphaneChazelas良い点。だから(私の処方では)それはあるはずですdie() { IFS=" "; printf >&2 "%s\n" "$*"; exit 1; }。この種のdie関数を個人的に使用してprintf、複数の引数を渡して複数行のエラーメッセージを生成したことがありますか?またはdie、出力に単一の改行のみを追加するように、単一の引数のみを渡しますか?
jrw32982は、モニカをサポートしています

-1

私はこれを空の文字列のテストとしてよく見ました:

if [ "x$foo" = "x" ]; then ...

「=」である必要があります-修正済み。
-wef

3
その慣行は文字通り1970年代のものです。使用され、今では陳腐化機能などの引用正しい限り、(1992 POSIX shの基準に準拠している任意のシェルでそれを使用する一切の理由はありません-a-o(および)ようderectivesを伝えるためにtest、単一の呼び出しで複数の操作を組み合わせることは、回避されます; pubs.opengroup.org/onlinepubs/9699919799/utilities/test.htmlのOBマーカーを参照してください)。
チャールズダフィー

非Linuxユニックスは、元の 'sh'とともに '90'年代に出荷されました-おそらくまだそうです。当時の仕事では、ポータブルインストールスクリプトを作成する必要があり、この構成を使用しました。NVidiaがLinuxに同梱しているインストールスクリプトを調べたところ、まだこのコンストラクトが使用されています。
-wef

NVidiaはそれを使用するかもしれませんが、そうするための技術的な正当性があると言っているわけではありません。商用UNIXでの貨物カルト開発は、残念ながら一般的です。Heirloom Bourneにも問題のバグはありません。そのため、SunOSコードベース(非POSIXを出荷する最後の商用UNIX /bin/shであり、Heirloom Bourneの前身)にもバグがありませんでした。
チャールズダフィー

1
帽子をかぶっていないので、1990年以降にこのバグで商用UNIXで公開されたシェルを誰かが見せたとしても、それを食べるYouTubeビデオを投稿することは約束できません... 。:)
チャールズダフィー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.