我的服务广泛使用环境变量进行配置(主要是因为将它们注入 Docker 容器非常容易)。
我还有一些可以在生产环境中运行的维护脚本。但自从我真的不希望我的 shell 环境配置为默认与产品对话,我有一个帮助程序脚本来设置环境,然后调用我的维护脚本。帮助程序脚本目前看起来像这样:
#!/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
在正确的DB_USER
变量可用之前,该变量已在我当前的 shell 中展开。
有没有一种方便的方法来运行这样的临时命令,将变量的扩展推迟到子 shell 中?或者将我的临时命令放入脚本中是最简单的方法吗?
答案1
在最后一行使用eval
,并确保父 shell 不会吃掉$
:
#!/bin/bash
export FOO=bar
export BAR=baz
eval "$@"
像这样运行:
wouter@gangtai:~$ ./foo.sh echo '$BAR'
baz
有关详细信息,请参阅help eval
。
答案2
您可以让您production_env.sh
测试没有参数(或一些特殊的单个参数,例如-i
),然后读取一行(允许-e
输入编辑)并执行它。例如将其最后一行更改为:
if [ $# = 0 -a -t 0 ]
then read -p 'prod> ' -e cmd
bash -c "$cmd"
else "$@"
fi