包含“*”(星號)的數組元素的自動擴展問題
我正在嘗試為我編寫一個
find
腳本,該腳本以後應該能夠讀取要從外部文件中排除的目錄列表。雖然我可以自己完成那部分,但令人討厭的數組擴展使任務變得困難。首先,一些“準備工作”以獲得合適的範例目錄樹:$ mkdir tmp && cd tmp $ mkdir excl1_dirx excl2_dirx excl3_dirx $ touch excl1_dirx/dummy1.txt excl2_dirx/dummy2.txt excl3_dirx/dummy3.txt $ mkdir excl1_diry excl2_diry excl3_diry $ touch excl1_diry/dummy4.txt excl2_diry/dummy5.txt excl3_diry/dummy6.txt $ touch dummy00.txt dummy01.txt
如果腳本有效,則只有
dummy00.txt
並且dummy01.txt
可能會顯示。#!/bin/bash excl_d=("excl*_dirx" "excl*_diry") find_str=" . -type f ! ( " for ((i=0 ; i<$((${#excl_d[*]})) ; i++)); do if [[ $i > 0 ]]; then find_str+=" -o " fi find_str+=" -path \"./${excl_d[i]}/*\"" done find_str+=" )" # this is just for debugging echo "[debug] value of str = find $find_str" find $find_str
首先:為什麼在“
done
”之前的行中(看似)如此復雜?嗯,bash
有時喜歡通過做他們不期望的事情來惹惱使用者。沒有這些引號,它將擴展每個數組元素;egexcl*_dirx
將成為excl1 dirx excl2 dirx excl3 dirx
,這(顯然)打破了-path
界限!儘管我在每個數組元素中使用了一對雙引號,這實際上是為了防止 bash 進行擴展惡作劇!然而,最好的還沒有到來:倒數第二行 - 當
(
)
轉義到時\(
\)
- 將在 shell 中正常工作,但不能在獨立腳本中工作。即使它不會拋出任何錯誤,但後一個實現的結果將是錯誤的。我已經嘗試了各種單引號和雙引號的組合
find_str+=" -path \"./${excl_d[i]}/*\""
行,但我只是無法讓它工作,即使它在顯示為倒數第二行時看起來絕對完美。似乎
bash
內部對待我的轉義引號\"
與非轉義引號不同。啊,引號內的引號幾乎無處不在,但由於某種原因,在使用該運算符時會被過濾掉+=
。我不僅在尋找這種行為的解釋,而且還在尋找如何在獨立腳本中使其工作的解決方案。這一定是我犯的一個愚蠢的錯誤。:-/
這裡的問題是這
find_str
是一個字元串,然後將其用作字元串列表。jw013 的評論是正確的,請閱讀我正在嘗試將命令放入變數中,但複雜的情況總是失敗!. 您沒有將整個命令放在一個變數中,但是一旦您嘗試將多個單詞填充到字元串變數中,就會出現問題。在 Bourne/POSIX shell 中,這是必要的邪惡。但是在 ksh/bash/zsh 中,有一個更好的方法:使用數組。
#!/bin/bash excl_d=("excl*_dirx" "excl*_diry") find_str=( . -type f \! \( ) for ((i=0 ; i<$((${#excl_d[*]})) ; i++)); do if [[ $i > 0 ]]; then find_str+=( -o ) fi find_str+=( -path "./${excl_d[i]}/*" ) done find_str+=( \) ) find "$find_str[@]}"
有一種更簡單的方式來表達這樣的過濾器。
#!/bin/bash exclude_patterns=("excl*_dirx" "excl*_diry") exclude_args=() while [[ ${#exclude_patterns} -gt 0 ]]; do exclude_args+=( -path "./${exclude_patterns[1]}/*" -prune -o ) shift exclude_patterns done find "${exclude_args[@]}" -type f