空の文字列で-dを使用してフォルダーが存在するかどうかを確認すると、trueが返されるのはなぜですか?


8

私はいくつかのスクリプトを書いていて、次のようなものを書きました

ARTIFACTS="/SOME/PATH"
[ -d $ARTIFCATS ] && rm -rf $ARTIFACTS/*

何が起こったのかというと、私は愚かさのために最初の行を実行せずに2行目を実行したということです。[-d ""]がtrueを返し、式が

rm -rf /*

幸い、それは単なるテストマシンであり、sudoではありませんでしたが、一部のデータを失いましたが

私の質問は、なぜ[-d ""]がtrueを返すのですか?ドキュメントには、パスが存在し、フォルダであるかどうかをチェックすることが明確に記載されています

私は使用して問題を解決しました

[ -e $ARTIFACTS ]
うまくいくようです

乾杯


5
または、おそらく両方の行を実行しました。上記のコード例では、ARTIFCATSを設定していません。
Buhb 2013年

2
私はそれrm -rf $ARTIFACTSなしでそれを書くだけ/*です。これにより、$ARTIFACTSディレクトリも削除されます。これは問題ありませmkdir -p $ARTIFACTSん。何かを配置する前にディレクトリが存在することを確認したい場合は、とにかく実行します。また、内部に隠されたファイルを削除します$ARTIFACTS私は書きませんので、細かいもある、rm -rf $ARTIFACTS/*あれば$ARTIFACTS含まれている何でも、私は保存したかったし。
ChristofferHammarström2013年

@ChristofferHammarströmは非常に真実
Moataz Elmasry 2013年

回答:


9

1.これらの2つのテストはtrueを返します

# [ -d ] && echo true || echo false
true
# [ -d $SOME_UNSET_VAR ] && echo true || echo false
true

POSIXに従って(@Timで説明)。

2.しかし、これは偽を返します(質問で述べられているようにではありません

# [ -d "" ] && echo true || echo false
false

これtestは、2つの引数を指定して呼び出されるためです(2番目の引数は空の文字列です)。

3.そのため、現在のほとんどの(すべての)シェルが提供している()の[[ … ]]代わりに使用することをお勧めします。この構文は、十分な引数を提供するかどうかをチェックします(そうでない場合、エラーをスローして中止します)test[ … ]

# [[ -d ]] && echo true || echo false
bash: unexpected argument `]]' to conditional unary operator
bash: syntax error near `]]'

または単に期待するように動作します:

# [[ -d $SOME_UNSET_VAR ]] && echo true || echo false
false

4.そして、@ Gillesで指摘されているように、置換を二重引用符で囲むことがさらに重要です。だから、-d "$SOME_UNSET_VAR"に展開-d ""し、戻りはとさえtest(ケース2に等しいです)。したがって、これはBourneシェルとも互換性がありますsh

# [ -d "$SOME_UNSET_VAR" ] && echo true || echo false
false

bash 3.00.16(1)および4.1.5(1)でテスト済み


1
bash、ksh、zshは提供します[[ … ]]が、プレーンではありませんsh。本当に重要なのは、コマンド置換を二重引用符で囲むことです[ -d "$ARTIFACTS" ]
Gilles「SO-邪悪なことをやめなさい」

6

この質問はStackOverflowですでに回答されています。POSIX標準によれば、test空でない引数を1つだけ指定して(他の引数を指定せずに)呼び出すと、常に成功を返すはずです。

これはtest -e(実際には私のシステムにも)当てはまることなので、注意してください。

代わりに次を使用します:

[ -d "$ARTIFACTS" ]

test 変数が空の場合でも2つの引数で呼び出され、この場合はfalseを返します。


「正確に1つの空でない引数。」-これは誤解を招く要約です-リンクしたページが1つの引数で呼び出され、その引数は空ではありません。空でない引数の後に空の引数が続く場合については何もありません。正しい解決策は、変数名を引用符で囲むことです。
Random832 2013年

@ Random832ありがとうございます!提案された変更の両方を実装しました。
Tim

[ ! -z $ARTIFACTS ] && [ -d $ARTIFACTS ]$ARTIFACTS空ではない特定のケースにのみ対応します$ARTIFACTSが、空白またはが含まれている可能性がある場合は失敗します\[?*[ -d "$ARTIFACTS" ]それを行う正しい方法です(または[[ -d $ARTIFACTS ]]を持っているシェルで[[ … ]])。
Gilles 'SO-悪をやめる'

@ギレスあなたは正しい、私はそれを削除した。ありがとう!
Tim

4

[-e $ ARTIFACTS]を使用して問題を解決しました。

あなたは間違っています。$ARTIFACTS何かに設定されているため、機能します。

変数が設定されていない場合は、

[ -d $SOMEVAR ]

または

[ -e $SOMEVAR ]

それは言うことを意味するので、両方が評価するでしょうtrue

[ -d ]

そして

[ -e ]

それぞれ。(言う[ foobar ]ことは常に真と評価されます。)

言う

set -u

このような状況で役立ちます。 help setあなたに言うでしょう:

  -u  Treat unset variables as an error when substituting.

[-e ""] && echo "PRINT SOMETHING"は何も出力しないので、これはどうして間違っているのでしょうか?
Moataz Elmasry 2013年

2
ああがらくた[-e $アーチファクトが]空の成果物の利回り[-e] [-e ""]ではないと、それを得ました
Moataz Elmasry

4

変数ARTIFACTSを設定し、ARTIFCATSをチェックしていたことを確認してください。おそらくタイプミスですか?

とにかく、-dと-eは、未設定の変数に対して同じ結果を生成します。

したがって、二重引用符使用すると、役立ちます。

ARTIFACTS="/SOME/PATH"
[ -d "$ARTIFACTS" ] && rm -rf -- "$ARTIFACTS/"*

注:「/ SOME / PATH」にスペースのあるフォルダがある場合、指定したスクリプトは「2項演算子が必要です」というエラーで壊れます。

例:

ARTIFACTS="/home backup/"

1) [ -d $ARTIFACTS ] && rm -rf $ARTIFACTS/*
bash: [: /home: binary operator expected

2) [ -d "$ARTIFACTS" ] && rm -rf "$ARTIFACTS"/*

うまくいきます。に引用符を入れることを忘れないでくださいrm呼び出しにも(rm -rf $ARTIFACTS元気に削除してから/homebackup/*存在しないことについて文句を言うでしょう)。

また、-Lcheckを含めると、それがディレクトリであり、ディレクトリへの単なるシンボリックリンクではないことを確認できます。

だから基本的に、

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