我正在嘗試在 bash 腳本中執行以下命令:
rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`
我正在嘗試類似的事情:
RM_CMD="$(rm -rf 'ls -t ${FOLDER}/other_folder | awk NR>5')"
稍後在函數中使用,我希望命令實際運行。
我嘗試了幾種變體,但總是失敗,這裡正確的方法是什麼?
-編輯-
更多資訊
如果我嘗試類似的事情
RM_CMD="rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`"
它似乎試圖立即執行命令,這不是我的意圖(我想儲存正確的命令以供以後執行),但它獲取所有正確的值,即沒有空的。
-編輯2-
我嘗試盡可能拆分命令,如下所示:
LS_CMD="ls -t ${FOLDER}/other_folder"
AWK_CMD="awk 'NR>5' ${LS_CMD}"
RM_CMD="rm -rf '${AWK_CMD}'"
但它給了這個問題:
+ ssh -t user@server 'rm -rf '\''awk '\''NR>5'\'' ls -t /full/path/to/folder/other_folder'\'''
bash: 5 ls -t /full/path/to/folder/other_folder: No such file or directory
答案1
通常對於這樣的問題,答案是閱讀BashFAQ #50:“我試圖將命令放入變數中,但複雜的情況總是失敗!”。簡短摘要:變數用於數據,而不是可執行程式碼,嘗試將程式碼放入其中會遇到各種各樣的問題。
但在這種情況下,還有另一個關鍵因素:您將透過 運行命令ssh
,這意味著它將被傳遞到遠端系統作為數據,並由遠端電腦上的 shell 解析為命令。這意味著將命令(作為資料)儲存在腳本中的變數中(在本機電腦上)是合理的。
在我看來,您遇到的最大問題是,當您使用反引號或$( )
(並且它們不在單引號中)時,內部命令會立即執行(在本機電腦上),並且其輸出儲存在變數。為了避免這種情況,可以在定義變數時轉義相關字元:
RM_CMD="rm -rf \$(ls -t '${FOLDER}/other_folder' | awk 'NR>5')"
請注意,我使用$( )
反引號代替,因為它通常是首選。在我看來,您在某些時候將反引號與單引號混淆了;它們看起來很相似,但效果卻完全不同。$( )
本質上做同樣的事情,但視覺上並不含糊。
另外,我假設${FOLDER}
是本地計算機上的變量,因此需要立即擴展(並且我在它周圍添加了單引號,以防它包含任何空格或其他 shell 元字元);如果要透過遠端 shell 擴展它,請改用\"\${FOLDER|/other_folder\"
。實際上,如果它本身包含任何單引號,則將單引號放在周圍${FOLDER}
是行不通的。有一種方法可以解決這個問題,但我沒有在這裡打擾。
您也可以在變數賦值中使用單引號,但是隨後您會在命令中使用單引號時遇到麻煩awk
(沒有乾淨的方法可以在單引號字串中嵌套單引號)並且沒有乾淨的方法${FOLDER}
在本地計算機上進行擴充。這些可以透過混合引用來解決,但很混亂。
最後,當您使用該變數時,您應該將其括在雙引號中:
ssh -t user@server "$RM_CMD"
……在這種特殊情況下這應該不重要,但是非雙引號變數引用可能會出現各種各樣的問題,因此雙引號通常是一個很好的做法。