将变量扩展推迟到子 shell

将变量扩展推迟到子 shell

我的服务广泛使用环境变量进行配置(主要是因为将它们注入 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

相关内容