2015-11-06 57 views
1

我得到以下輸出:測試! -a總是成功的文件是否存在

$ touch bar 
$ if [ -a bar ]; then echo "Yes"; fi 
Yes 
$ if [ ! -a bar ]; then echo "Yes"; fi 
Yes 
$ rm bar 
$ if [ -a bar ]; then echo "Yes"; fi 
$ if [ ! -a bar ]; then echo "Yes"; fi 
Yes 

我預計,第二個命令不應打印「是」,因爲! -a應該是-a相反。出了什麼問題?

使用-f而不是-a確實表現得如我所料。

版本號是GNU bash, version 4.3.42(3)-release (i686-pc-cygwin)

+0

在'bash'和'sh'中''表達式''內的選項'-a'可以被評估爲'邏輯和''',例如'if [-f/tmp/test -a -f/tmp/other];回聲確定; fi'。 – alvits

+0

@alvits我明白了。我從[這個線程](http://stackoverflow.com/questions/5553352/how-do-i-check-if-file-exists-in-makefile)使用'-a'的想法,這足夠好了不提這個問題:) –

回答

3

bash手冊頁獲得[三個參數(注意我的重點):

以列出的順序應用以下條件

  • 如果第二個參數是以下條件表達式上面列出的二進制條件運算符之一中,表達的結果是使用第一和第三個參數作爲操作數的二進制測試的結果。 當有三個參數時,'-a''-o'運算符被認爲是二元運算符。

  • 如果第一個參數是'!',該值是使用第二和第三個參數的兩個參數的測試的否定。

  • 如果第一個參數是準確'(',第三個參數是完全')',結果是第二個參數的一個參數的測試。

  • 否則,表達式爲false。

換句話說,當你期望它在這種情況下-a不是演戲。它實際上是被視爲邏輯和操作員,並因爲這兩個!bar被認爲是真正的and荷蘭國際集團他們的結果也是如此:

pax> if [ ! ] ; then echo yes ; fi 
yes 
pax> if [ bar ] ; then echo yes ; fi 
yes 

[的弱點是多種多樣的,這就是爲什麼明智的bash編碼器將使用[[代替:-)

+0

啊!感謝您的解釋,我也會避開'-a' –

1

試試這個:

$ touch bar 
$ if [[ -a bar ]]; then echo "Yes"; fi 
Yes 
$ if [[ ! -a bar ]]; then echo "Yes"; fi 
<NOTHING> 

編號:http://mywiki.wooledge.org/BashFAQ/031

爲,[被定義爲有,但[可能缺乏(取決於實現)特殊的原語:

Description 
Primitive 
Example 
entry (file or directory) exists 
-e 
[[ -e $config ]] && echo "config file exists: $config" 
file is newer/older than other file 
-nt/-ot 
[[ $file0 -nt $file1 ]] && echo "$file0 is newer than $file1" 
two files are the same 
-ef 
[[ $input -ef $output ]] && { echo "will not overwrite input file: $input"; exit 1; } 
negation 
! 
[[ ! -u $file ]] && echo "$file is not a setuid file" 
+0

你能解釋爲什麼原始代碼不起作用嗎? – Barmar

+1

在所有引用的材料中,它解釋了爲什麼'[! - 酒吧]'工作不同? – Barmar

2

如果你想堅持[ ... ],使用(引用)括號來消除歧義[1]

if [ ! \(-a bar \) ]; then echo "Yes"; fi  

如果你正在寫一個劇本bash(無需擔心可移植性),使用[[ ... ]],這避免了括號的需要:

if [[ ! -a bar ]]; then echo "Yes"; fi  

[1] Barmar,在一個自刪除的答案,解釋含糊固有的[ ! -a bar ]
-a服務均爲作爲一元文件存在運算符作爲二進制邏輯AND運算符。
在手邊,-a的情況下,由於參數的存在下,被解釋爲邏輯操作者,治療!bar作爲其字面操作數:兩個!bar非空字符串,它們在布爾環境中被認爲是真實的,所以總體表達式爲總是爲真。

相比之下,bash[[ ... ]]構建專門使用邏輯&& AND(與||爲OR)來避免這種不確定性;換句話說:-a只有被識別爲一元文件存在操作符,所以沒有歧義,並且不需要括號。