為 bash 和 qmake 中的變數轉義雙引號
我為 qmake 編寫了以下元項目文件,該文件旨在建構
.pro
以下子目錄中的所有文件(由於歷史原因和其他工具鏈,文件名與文件夾名稱不匹配)。這基本上歸結為這樣的事情(拋開項目特定的東西)THIS_FILE=make-all.pro TEMPLATE=subdirs FIND= "find -name \'*.pro\' -printf \'%p\\n\'" AWK= "awk \'{$1=substr($1,3); print}\'" RMTHIS= "awk \'!/$$THIS_FILE/\'" SUBDIRS= $$system($$FIND | $$AWK | $$RMTHIS )
我需要獲取包含
.pro
Bash 腳本中文件的文件夾列表,因此我決定複製該方法#!/bin/bash FIND="find -name '*.pro' -printf '%h\\n" AWK="awk '{\$1=substr(\$1,3);printf}'" SUBDIRS=$($FIND | $AWK)
顯然這不起作用,在表達式
awk
中噴出錯誤。invalid char ''
嘗試直接在 Bash 中執行相同的行表明awk
只有在使用雙引號時才有效find -name '*.pro' | awk "{\$1=substr(\$1,3);printf}"
將有問題的行替換為
AWK='awk "{$1=substr($1,3);printf}" '
沒有工作結果,腳本的輸出為空,與手動輸入命令的輸出不同。顯然
find -name '*.pro'
In script 僅在目前文件夾中查找文件,而在 bash 命令行中的對應項在子文件夾中查找它。出了什麼問題以及為什麼 qmake 的工作方式也不同?
我不熟悉 qmake 語法,但是從您的範例中,它以與 shell 完全不同的方式使用引號和變數。所以你不能只使用相同的程式碼。
http://unix.stackexchange.com/questions/131766/why-does-my-shell-script-choke-on-whitespace-or-other-special-characters涵蓋了您需要知道的內容,所以在這裡我將只總結與您的問題相關的內容。
簡而言之,您不能簡單地將 shell 命令填充到字元串中。諸如 bash 之類的 shell 不會遞歸地解析字元串。他們解析原始碼並將命令建構為字元串列表:一個簡單的命令由命令名稱(執行檔的路徑、函式名稱等)及其參數組成。
當您使用類似的賦值時
AWK="awk '{\$1=substr(\$1,3);printf}'"
,這會將變數AWK
設置為字元串;當您將變數用作$AWK
外部雙引號時,這會通過在空格處解析變數的值將其轉換為字元串列表,但它不會將其解析為 shell 程式碼,因此像這樣的字元'
最終會出現在參數中。這很少是可取的,這就是為什麼在 shell 中使用變數的一般建議是**在變數擴展周圍加上雙引號,**除非您知道需要將它們關閉並且您了解這意味著什麼。(請注意,我在這裡的回答並不能說明全部。)在 bash 中,您可以將一個簡單的命令填充到一個數組中。
#!/bin/bash FIND=(find -name '*.pro' -printf '%h\\n') AWK=(awk '{$1=substr($1,3);print}') SUBDIRS=$("${FIND[@]}" | "${AWK[@]}")
但通常儲存命令的最佳方式是定義一個函式。這不僅限於一個簡單的命令:通過這種方式,您可以進行重定向、變數賦值、條件等。
#!/bin/bash find_pro_files () { find -name '*.pro' -printf '%h\\n' } truncate_names () { awk '{$1=substr($1,3);print}' } SUBDIRS=$(find_pro_files | truncate_names)
我不確定你想用這個腳本做什麼(特別是考慮到你改變了程式碼片段之間的
find
andawk
程式碼),但可能有更好的方法來做到這一點。您可以使用循環遍歷*.pro
目前目錄的子目錄中的文件for pro in */*.pro; do subdir="${pro%/*}" basename="${pro##*/}" … done
如果您想遞歸地遍歷子目錄,在 bash 中,您可以使用
**/*.pro
而不是*/*.pro
,但請注意,這也會遞歸到目錄的符號連結。