Bash
將變數擴展推遲到子shell
我的服務廣泛使用環境變數進行配置(主要是因為將它們注入 Docker 容器非常容易)。
我還有一些可以在生產環境中執行的維護腳本。但是因為我真的不希望我的 shell 環境預設配置為與 prod 對話,所以我有一個幫助腳本來設置環境,然後呼叫我的維護腳本。輔助腳本目前看起來像這樣:
#!/bin/bash export DB_NAME=foo export DB_HOST=foo.service.local export DB_USERNAME=testy_testerson export DB_PASSWORD=password export SERVICE_API_KEY=qwertyuiop "$@"
我像執行它一樣
bin/production_env.sh scripts/maintenance_script.sh arg1 arg2
。這一切都很好。我的維護腳本之一是
dump_db.sh
,如下所示:#!/bin/sh pg_dump --no-owner --clean --if-exists --dbname "$DB_NAME" --host "$DB_HOST" --port "$DB_PORT" --username "$DB_USER" > "db/${RAILS_ENV}-dump.$(date +%Y-%m-%dT%H:%M:%S).sql"
這也很好用。但我希望能夠使用配置的環境執行臨時命令,而無需先將該邏輯放入腳本文件中。例如,
bin/production_env.sh psql --username "$DB_USER" --command 'select version()'
當然,問題是在正確的變數可用
DB_USER
之前,該變數已在我目前的 shell 中展開。DB_USER
有沒有一種方便的方法來執行這樣的臨時命令,將變數的擴展推遲到子shell?還是將我的臨時命令放入腳本中是最簡單的方法?
在你的最後一行使用
eval
,並確保父 shell 不吃$
:#!/bin/bash export FOO=bar export BAR=baz eval "$@"
像這樣執行:
wouter@gangtai:~$ ./foo.sh echo '$BAR' baz
有關詳細資訊,請參閱
help eval
。
你可以讓你
production_env.sh
測試沒有 args (或一些特殊-i
的單個 arg 像 ),然後讀取一行(-e
允許輸入編輯)並執行它。例如,將其最後一行更改為:if [ $# = 0 -a -t 0 ] then read -p 'prod> ' -e cmd bash -c "$cmd" else "$@" fi