【问题标题】:Quoted String in Environment Variable Passed to Program on Command-Line [duplicate]环境变量中的引用字符串传递给命令行上的程序[重复]
【发布时间】:2018-12-22 03:32:35
【问题描述】:

我有一个将带引号的字符串放在环境变量中的系统。此环境变量作为命令行参数传递给 python 程序,但引用的字符串被拆分为多个单词,而不是保持在一起。

例如:

在外壳中:

$ export ARG_OPTIONS='--flag -a 31 --big_complicated_flag "How are you?"'

在 bash 脚本中:

python args.py $ARG_OPTIONS

在python脚本中:

import sys
print sys.argv

结果输出是:

['args.py', '--flag', '-a', '31', '--big_complicated_flag', '"How', 'are', 'you?"']

这里的重要部分是带引号的字符串已被分成多个部分,这不是程序所期望的参数。 我不能太多地改变这个设置,所以任何想法都将不胜感激。


我尝试过的事情

Shell 中的双引号

python args.py "$ARG_OPTIONS"
Result: ['args.py', '--flag -a 31 --big_complicated_flag "How are you?"']

这是不正确的,因为整个变量作为单个参数传入。 但是,我预料到这种行为,但我想我会尝试。

Shell 中的单引号

python args.py "$ARG_OPTIONS"
Result: ['args.py', '$ARG_OPTIONS']

同样不正确,但从我对单引号的理解来看。

环境变量双引号

export ARG_OPTIONS="--flag -a 31 --big_complicated_flag \"How are you?\""
Result: ['args.py', '--flag', '-a', '31', '--big_complicated_flag', '"How', 'are', 'you?"']

这个结果和原来的一样。

单引号环绕环境变量双引号

export ARG_OPTIONS='"--flag -a 31 --big_complicated_flag \"How are you?\""'
Result: ['args.py', '"--flag', '-a', '31', '--big_complicated_flag', '\\"How', 'are', 'you?\\""']

同样不正确。

玩弄 IFS

更改 IFS 分隔符并手动分隔环境变量中的参数:

export ARG_OPTIONS='--flag|-a|31|--big_complicated_flag|How are you?'

在shell脚本中:

IFS='|'
python args.py $ARG_OPTIONS

Result: ['args.py', '--flag', '-a', '31', '--big_complicated_flag', 'How are you?']

这会产生预期的输出,但它看起来很老套,以后容易混淆。显然,关于 shell 和环境变量之间的交互,我有些不理解。

为什么要分隔双引号中的单词?有没有更清洁的方法来实现我的目标?

【问题讨论】:

  • 在执行时,shell 做了几件事。它将 shell 变量扩展为它们的值;应用元字符扩展(如“*”);插值...然后将所有内容传递给您的可执行文件。您修改 IFR 的想法是一个很好的解决方案。
  • 这在BashFAQ #50中有详细介绍
  • @dwwork, ...简短的回答是“使用数组”。 arg_options=( --flag -a 31 --big_complicated_flag "How are you?" ),然后python args.py "${arg_options[@]}" 将完美运行。
  • @Charles 感谢您找到重复项,我很难知道究竟要搜索什么。常见问题解答也很棒。如果不是通过无法处理数组的环境变量进行通信,数组的想法会起作用。
  • 展望未来,我建议ARG_OPTIONS="--flag -a 31 --big_complicated_flag \"How are you?\"" ; readarray -d '' arg_options < <(xargs printf '%s\0' <<<"$ARG_OPTIONS"); python args.py "${arg_options[@]}",如果您的目标系统具有足够新的 bash 以拥有readarray -d。 (否则readarray可以换成arg_options=( ); while IFS= read -r -d '' word; do arg_options+=( "$word" ); done,但相比之下显然是拗口)。

标签: bash shell


【解决方案1】:

代替

python args.py $ARG_OPTIONS

你可能想使用

eval "python args.py $ARG_OPTIONS"

来自 eval 的 bash 帮助:

eval: eval [arg ...]
Execute arguments as a shell command.

Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.

简而言之,eval 再次重新评估它的论点;这会将一对文字双引号转换为影响分词的双引号。

但是,请注意:这种方法会带来安全风险 - 现在可以执行任意代码。

【讨论】:

  • 这会引入新的错误,其中一些会影响安全。 至少,设为eval "python args.py $ARG_OPTIONS";这更清楚它在做什么,并且在将它们连接在一起并将结果解析为单个 shell 命令之前,不会将您的字符串拆分为单词并将它们扩展为 glob。
  • 有关未能引用传递给eval 的字符串的具体示例,请运行cmd='printf "%s\n" " * "'; eval $cmd,并在eval "$cmd" 时进行比较
  • (任何查看此内容的人都应该阅读BashFAQ #48;如果邮件不是"How are you",而是"Prevented login from unauthenticated user $(rm -rf ~)'$(rm -rf ~)'"eval 将非常危险)。
  • 添加了双引号并提到了安全风险。
  • @CharlesDuffy 是的,这正是我想要的。即使存在安全风险,我也会标记为已接受,因为我的输入不是来自外部来源。显然,关于 shell 脚本,我还有很多东西要学!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-10
  • 1970-01-01
  • 2021-05-16
  • 1970-01-01
  • 2018-02-09
  • 1970-01-01
相关资源
最近更新 更多