Bash
為什麼使用雙括號“[[”檢查萬用字元匹配的文件是否存在失敗,而單括號“[”有效?
假設我生成了兩個目錄,每個目錄中都有文本文件,就像這樣
mkdir "Directory1" mkdir "Directory2" touch "Directory1/fileclass1_"{1..5}".txt" touch "Directory1/fileclass2_"{1..5}".txt" touch "Directory2/fileclass1_"{1..5}".txt" touch "Directory2/fileclass2_"{1..5}".txt"
假設我通過執行驗證所有文件都在裡面
A=( "Directory1" "Directory2" ) B=( "fileclass1" "fileclass2" ) for a in "${A[@]}"; do for b in "${B[@]}"; do for i in {1..5}; do name="${a}/${b}*${i}.txt" [[ ! -e $name ]] && echo "$name Does Not Exist" done done done
這返回
Directory1/fileclass1*1.txt Does Not Exist Directory1/fileclass1*2.txt Does Not Exist ...
但是,如果我用單引號代替雙括號,我會得到
A=( "Directory1" "Directory2" ) B=( "fileclass1" "fileclass2" ) for a in "${A[@]}"; do for b in "${B[@]}"; do for i in {1..5}; do name="${a}/${b}*${i}.txt" [ ! -e $name ] && echo "$name Does Not Exist" done done done
它什麼也不返回,表明所有文件確實在那裡。
為什麼在這種情況下,雙括號失敗,而單括號有效?我假設我應該始終使用雙括號,字元串匹配中的萬用字元是否會創建我不應該擁有的東西?
條件運算符測試是否存在具有給定名稱的
-e
文件。它不進行任何模式匹配。[[ -e fileclass1*1.txt ]]
測試fileclass1*1.txt
名稱中是否有一個帶有星號的文件,而不是是否至少有一個文件與萬用字元模式匹配fileclass1*1.txt
。使用單括號
[ ! -e $name ]
, 因為$name
未加引號,所以 的值會name
進行萬用字元替換和分詞。如果值為,name
則Directory1/fileclass1*1.txt
效果取決於有多少文件與萬用字元模式匹配。
- 如果該模式與任何文件都不匹配,則它保持未展開狀態。然後
-e
操作員看到文件名Directory1/fileclass1*1.txt
,它不存在,所以[ ! -e $name ]
是真的。- 如果模式匹配單個文件,則將其替換為該文件的名稱。然後
-e
操作員看到該文件名,它存在¹,所以[ ! -e $name ]
是假的。- 如果模式匹配兩個或更多文件,則將其替換為匹配文件名列表,這會導致條件句中出現語法錯誤。在這種情況下,
[ ! -e $name ]
顯示錯誤消息並返回失敗狀態。效果不同,
[[ -e $name ]]
因為[[ … ]]
是特殊語法(而[
普通命令的參數是正常擴展的)。內部沒有進行分詞或萬用字元擴展[[ … ]]
。要解決您的實際問題,請參閱測試是否有與模式匹配的文件以執行腳本
¹除非在極少數情況下,由於競爭條件,文件在 shell 列出目錄內容以擴展萬用字元模式的時間和
-e
操作員檢查文件存在的時間之間被刪除。