使用环境变量将参数传递给命令

13

我想编写一个bash脚本,将环境变量传递给命令。

如果我有这样的代码:

export OUT="-a=arg1 -b=\"arg2.0 arg2.1\""

我希望在我的bash脚本中做类似以下的操作:
<command> -a=arg1 '-b=arg2.0 arg2.1'

我有一种方法似乎可以做到这一点,但它涉及使用eval:

eval <command> ${OUT}

如果我在命令附近包含set -x,则会看到以下内容:

+ eval <command> a=arg1 'b="arg2.0' 'arg2.1"'
++ <command> -a=arg1 '-b=arg2.0 arg.1'

然而,我已经探究了使用eval的危险性,由于这将从用户输入中获取参数,因此不是理想的选择。

既然这是bash,我还考虑使用数组来存储我的参数,只需简单地使用<command> "$ARRAY[@]"即可完成我想要的功能。我一直在尝试使用IFS,但我不确定应该以什么为分隔符。


通常情况下,我会使用更高级的脚本语言,例如Ruby/Python/Perl等。 - larsks
你不能导出数组,所以如果你坚持使用bash脚本文件,那是行不通的。但是你可以在bash函数中使用数组。 - rici
备选方案:使用 set ...args... ; <更多代码>; command $@ - technosaurus
3个回答

4

如果您对$OUT的格式不是完全死板的,那么一种可能性是重复option=字符串以允许串联。然后您可以写成:

export OUT="a=arg1 b=arg2.0 b=arg2.1"

如果这是可以接受的,下面的脚本将起作用。
#!/bin/bash

# Parse $OUT into an associative array.
# Instead of using $OUT, it would be cleaner to use "$@".
declare -A args
for arg in $OUT; do
  if [[ "$arg" =~ ^([[:alnum:]]+)=(.*)$ ]]; then
    key=${BASH_REMATCH[1]}
    val=${BASH_REMATCH[2]}
    if [[ -z ${args[$key]} ]]; then
      args[$key]=-$key="$val"
    else
      args[$key]+=" $val"
    fi
  fi
done

# Test, approximately as specified
command() { :; }
set -x
command "${args[@]}"
set +x

我不太喜欢它,但这是我能达到的最接近的状态。
下面是一个样本运行:
$ export OUT="a=foo b=bar  b=glitch s9= s9=* "
./command-runner
+ command -a=foo '-b=bar glitch' '-s9= *'
+ :
+ set +x

如果您导入一个bash函数(例如,在您的bash启动文件中),则可以更好地利用数组。以下是一种方法:
# This goes into your bash startup file:
declare -a SAVED_ARGS
save_args() {
  SAVED_ARGS=("$@")
}

do_script() {
  /path/to/script.sh "${SAVED_ARGS[@]}" "$@"
}

为了说明,script.sh

#!/bin/bash
command() { :; }

set -x
command "${@/#/-}"
set +x

例子:

$ save_args x=3 y="a few words from our sponsor"
$ do_script a=3 b="arg2.0 arg2.1"
+ command -x=3 '-y=a few words from our sponsor' -a=3 '-b=arg2.0 arg2.1'
+ :
+ set +x
$ do_script a=42
+ command -x=3 '-y=a few words from our sponsor' -a=42
+ :
+ set +x

如果不是很明显:
command() { :; }

定义了一个名为command的bash函数,它几乎什么也不做(除了调用内置的:,这个命令什么也不做),并且

"${@/#/-}"

在IT技术中,使用#模式进行查找和替换时,可以将连字符插入到每个位置参数的开头。此模式实际上是一个空模式,仅匹配字符串的开头。


嗯,这是一个非常有趣的解决方案。但我正在尝试使用户更加直观,让他们将其视为简单地将其附加到传递给<command>的参数列表中。我对数组方法感兴趣的原因之一是,我发现如果我做类似于./script.sh -arg1="foo bar"的事情,并在脚本本身中执行<command> "$@",它的效果非常好。 - Ed Y
@EdY:如果您可以接受定义一个Bash函数来调用您的脚本,执行您的命令,那么数组解决方案是可行的。您需要这个解决方案吗? - rici
你说的“lay in the house that jack built”是什么意思?你是在说我的脚本my_script.sh -> bash函数中调用带参数的命令吗? - Ed Y
@EdY:抱歉,那只是一种非常特定于文化的笑话。http://en.wikipedia.org/wiki/This_Is_the_House_That_Jack_Built 。是的,我在谈论一个bash函数,它解释数组并调用您的my_script.sh,然后调用该命令。 - rici
哦,所以它就像是 my_script -> 获取环境变量 -> my_script env_variable_foramtted_for_cmd_line -> 传递 <command> "${@}" 这样的东西吗?它会像一些 if 语句一样检查是否是第一次或第二次调用吗?或者为什么它需要在一个 bash 函数中? - Ed Y
@EdY:它需要在bash函数中,因为正如我之前提到的,你无法导出数组。无论如何,我已经添加了它,这样你就可以看到它是如何工作的,希望能对你有所帮助。 - rici

4

对于上面答案中描述的简化问题,即将以下环境变量转换为bash脚本内的三个参数:

export OPTS="a=arg1 b=arg2.0 b=arg2.1"

只需按照以下步骤操作:
#!/bin/bash
opts=( $OPTS )
my-command "${opts[@]}"

# Use this for debugging:
echo "number of opts = ${#opts[@]}; opts are: ${opts[@]}"

0

将您的环境变量设置为: export abc=123

在需要将abc作为参数传递的脚本的执行过程中,请按照以下格式进行传递: ./testing.sh“$abc”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接