我正在嘗試製作一個腳本,該腳本需要保存要作為字串運行的命令。有問題的字串需要包含引號,當嘗試執行它時,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
,但變數中的相同字元擴展為單字"-i
和filename"
。
Bash常見問題 50更詳細地涵蓋了這個主題。