Bash

將變數擴展推遲到子shell

  • June 20, 2016

我的服務廣泛使用環境變數進行配置(主要是因為將它們注入 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

引用自:https://unix.stackexchange.com/questions/290966