在 bash 腳本上執行複雜的命令

在 bash 腳本上執行複雜的命令

我正在嘗試在 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"

……在這種特殊情況下這應該不重要,但是非雙引號變數引用可能會出現各種各樣的問題,因此雙引號通常是一個很好的做法。

答案2

您可以使用以下命令檢查 bash 腳本中的常見錯誤外殼檢查,它可以在線工作,但也可以作為離線節目。它支援不同的 shell(由 shebang 標識),並且還提供樣式警告(就像在您的情況下使用$(...)而不是反引號)。普通教學結合使用很有幫助) )。

相關內容