如何在不額外引用的情況下將 bash 變數作為命令運行?

如何在不額外引用的情況下將 bash 變數作為命令運行?

我正在嘗試製作一個腳本,該腳本需要保存要作為字串運行的命令。有問題的字串需要包含引號,當嘗試執行它時,bash 會添加額外的引號字符,這在某些情況下會導致命令無法按預期運行。

這是一個範例腳本。在此範例腳本中運行的命令example顯然不會執行任何操作,它只會說command not found,但是您仍然可以運行該腳本並查看我在說什麼,因為我添加到了-x#!/bin/bash行,以便列印正在運行的確切命令。

例子:

#!/bin/bash -x

#command typed explicitly
example -options "-i filename"

#command stored in string first
commandstring='example -options "-i filename"'
echo "running command: ${commandstring}"
${commandstring}

為我運行此腳本的輸出是(忽略兩個“命令未找到”錯誤):

+ example -options '-i filename'
+ commandstring='example -options "-i filename"'
+ echo 'running command: example -options "-i filename"'
running command: example -options "-i filename"
+ example -options '"-i' 'filename"'

因此,您可以看到第一行當然按預期運行,給出了命令列參數:

-i filename

然而,儘管該echo命令以同樣可以完美執行的方式列印字串,但當將字串放在命令列上時,它會發生變化,並且傳入的參數會變成

''-i' '檔名''

其中包含額外的引號字符,這導致我在真實腳本中使用的實際命令失敗。

有什麼辦法可以防止這種情況發生嗎?

答案1

如果您使用的是bash,準確保存命令的最簡單方法是將其放入陣列中。如果您要執行的命令是:

example -options "-i filename"

您可以將其保存在數組變數中:

commandline=(example -options "-i filename")

然後,您可以透過 @ 擴展雙引號內的陣列來運行已儲存的命令:

"${commandline[@]}"

這裡要知道的關鍵是,"'\當直接在命令列中輸入時,shell 對待引號字元 () 的方式與在變數擴展中(如${commandstring}.在命令列中,引號字元具有特殊的引用功能。在參數擴展中,它們只是普通的非特殊字元。因此,"-i filename"是在命令列中鍵入時被解析為 的單字-i filename,但變數中的相同字元擴展為單字"-ifilename"


Bash常見問題 50更詳細地涵蓋了這個主題。

相關內容