我有一些使用 YAML 檔案配置的應用程式。該應用程式進行一些處理并支持鉤子在處理前后執行 shell 代碼。這主要是為了執行實際業務的外部腳本檔案,但也可以例如匯出環境變數。似乎事情只是簡單地轉發到帶有配置字串的 shell 呼叫。
需要注意的重要一點是,如果在處理程序中出現任何問題,會特別呼叫一個鉤子。在這種情況下,應用程式會向配置的 shell 腳本提供一些額外的錯誤詳細資訊。這是通過讀取 YAML 配置的必要部分并將特殊關鍵字的簡單字串替換為運行時實際可用的內容來完成的。這些關鍵字遵循語法{...}。我的配置中的內容如下所示:
on_error:
- |
export BGM_ERR_VAR_CONFIG_PATH="{configuration_filename}"
export BGM_ERR_VAR_REPO="{repository}"
export BGM_ERR_VAR_ERROR_MSG="{error}"
export BGM_ERR_VAR_ERROR_OUT="{output}"
'/path/to/script.sh 'some_arg' '[...]' [...]
最初這些關鍵字應該作為被呼叫腳本中的引數轉發,但我的腳本已經需要一些其他引數,所以我決定使用環境變數轉發內容。不過,不應該對我的問題產生太大影響。
這個問題是真的任何事情都可能出錯,尤其是占位符{output}可能包含任意復雜的錯誤訊息。它很可能是執行的 shell 命令的混合,在大多數情況下使用單引號,以及使用雙引號實作應用程式的編程語言的堆疊跟蹤。使用上面的配置,這會導致最終執行無效的 shell 代碼:
[2021-10-12 07:18:46,073] ERROR: /bin/sh: 13: Syntax error: Unterminated quoted string
以下是應用程式記錄的正在執行的內容:
[2021-10-12 07:18:46,070] DEBUG: export BGM_ERR_VAR_CONFIG_PATH="/path/to/some.yaml"
export BGM_ERR_VAR_REPO="HOST:PARENT/CHILD"
export BGM_ERR_VAR_ERROR_MSG="Command 'borg check --prefix arch- --debug --show-rc --umask 0007 HOST:PARENT/CHILD' returned non-zero exit status 2."
export BGM_ERR_VAR_ERROR_OUT="using builtin fallback logging configuration
35 self tests completed in 0.04 seconds
SSH command line: ['ssh', '-F', '/[...]/.ssh/config', 'HOST', 'borg', 'serve', '--umask=007', '--debug']
RemoteRepository: 169 B bytes sent, 66 B bytes received, 3 messages sent
Connection closed by remote host
Traceback (most recent call last):
File "borg/archiver.py", line 177, in wrapper"
'/path/to/script.sh '[...]' '[...]' '[...]' '[...]'
我自己腳本的 args 在參考方面是安全的,那些只是硬編碼的路徑、關鍵字等,沒有任何動態。問題應該是用于拋出例外的 python 檔案路徑的雙引號。OTOH,如果我只在我的環境變數中使用單引號,那些會中斷,因為呼叫的輸出 shell 命令也使用單引號。
那么,{output}在這種情況下,我如何實作安全轉發到環境變數中?
我想過使用一些子shell="$(...)"并sed規范化引號,但是我想出的所有內容都導致命令列具有與以前完全相同的參考問題。這同樣適用于printf與其%q逃避報價。看來我需要一些能夠處理任意單個引數并將它們再次連接到某個字串或類似的東西的東西。此外,事情不應該太復雜,以免最終使 YAML 配置膨脹。
以下可能有效,但會丟失雙引號:
export BGM_ERR_VAR_ERROR_OUT="$(echo "{output}")"
那個怎么樣?
export BGM_ERR_VAR_ERROR_OUT="$(cat << EOT
{output}
EOT
)"
還要別的嗎?謝謝!
uj5u.com熱心網友回復:
為了避免所有替換問題,我建議不要使用替換,而是將值作為環境變數轉發。這假設您可以控制呼叫代碼,我認為根據您的解釋是正確的。
由于環境變數按照慣例是大寫的,將您的值放在小寫名稱中是非常安全的,然后您可以簡單地執行
on_error:
- |
export BGM_ERR_VAR_CONFIG_PATH="$configuration_filename"
export BGM_ERR_VAR_REPO="$repository"
export BGM_ERR_VAR_ERROR_MSG="$error"
export BGM_ERR_VAR_ERROR_OUT="$output"
'/path/to/script.sh 'some_arg' '[...]' [...]
呼叫代碼需要相應地修改環境,以便它包含預期值。這是轉發值的最安全方法,因為它保證根本不會將值解釋為 bash 語法。
如果這是不可能的,那么下一個最好的方法可能是使用heredoc,盡管帶有引號以避免處理內容中的任何內容 - 您可以使用read以避免不必要的cat:
on_error:
- |
read -r -d '' BGM_ERR_VAR_CONFIG_PATH <<'EOF'
{configuration_filename}
EOF
export BGM_ERR_VAR_CONFIG_PATH
# ... snip: other variables ...
'/path/to/script.sh 'some_arg' '[...]' [...]
您在這里唯一需要注意的是,內容可能不包括一行閱讀EOF。呼叫代碼需要確保這一點。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/314568.html
上一篇:提高bash腳本的性能
下一篇:php網頁不執行腳本
