2012-04-02 82 views
4

假设我有一个要运行的命令(cmd)和一个包含我想传递给该函数的参数的变量(如--foo 'bar baz' qux)。像这样:将shell转义的参数字符串传递给Bourne shell中的子命令

#!/bin/sh 
command=cmd 
args="--foo 'bar baz' qux" 

参数包含引号,就像上面显示的那样,它们将包含空格的参数组合在一起。那么我想运行命令:

$command $args 

这,当然,结果与参数运行命令:--foo'barbaz'qux。我习惯替代(即,使用"[email protected]"时)呈现出不同的问题:

$command "$args" 

此执行与一个参数的命令:--foo 'bar baz' qux

如何运行与参数(--foobar baz,并且qux)命令如预期?

+0

快速的职业生涯:现代'/ bin/sh'是POSIX sh,而不是Bourne。 (...并且不是,POSIX sh是**不是** 70年代Bourne的纯粹超集:例如,在Bourne中 - 但不是POSIX sh或现代衍生物,如灰,短跑,ksh或bash - ^'是一个有效的管道字符)。 – 2015-11-05 15:52:54

+0

我看到你的脚步,为你提供了另一点儿琐事:Solaris 10是“现代”(出现在21世纪,仍然在生产中使用,尽管幸运的是现在正在减少),然而它的'/ bin/sh'绝对不符合POSIX标准。 – mtraceur 2016-09-06 07:17:47

回答

4

一种可能性是使用eval

#!/bin/sh 

args="--foo 'bar baz' qux" 
cmd="python -c 'import sys; print sys.argv'" 

eval $cmd $args 

这样,你会在命令行进行解释,而不是仅仅根据IFS分裂。这给出了输出:

$ ./args.sh 
['-c', '--foo', 'bar baz', 'qux'] 

这样就可以看到参数按照您的意愿传递。

+1

不需要Python:在bash中,'printf%q“$ @”'会以明确的形式显示你的argv。 (对于所有读者来说 - 请仅在完全信任您的输入时使用eval,并且无法以其他方式获得所需结果;如果您正在评估的变量可能包含任何不可信用户可能创建的任何内容......说,'/ tmp'中的文件名称,使用eval打开自己的痛苦,痛苦和安全漏洞)。 – 2012-04-02 21:10:21

+1

@CharlesDuffy:你说的是'eval',但'printf%q'是Bashism,问题是关于Bourne Shell。 – l0b0 2012-04-03 11:28:57

+0

谢谢!这里的输入是100%可信的,所以这会很好地工作。 – adrian 2012-04-03 17:22:42

8

使用数组可以准确地指定您的参数列表,不串分裂(这是什么在这里做了错误的事情)在你的方式:

args=(--foo "bar baz" qux) 
command "${args[@]}" 

如果您需要动态地建立自己的参数列表,可以追加与+=到数组:

args=() 
while ...; do 
    args+=("$another_argument") 
done 
call_your_subprocess "${args[@]}" 

注意,使用引号,和[@]代替[*],是必不可少的。

+3

OP询问Bourne Shell(即'/ bin/sh')。这对'bash'来说是一个很好的解决方案,但我不相信bourne shell支持数组,是吗? – FatalError 2012-04-02 21:09:14

+0

糟糕 - 你说得对。 – 2012-04-02 21:10:44

+0

谢谢!这可能是切换到该程序的bash的原因。 – adrian 2012-04-03 16:34:18

1

如果你在表单中命令:

args="--foo 'bar baz' qux" 

,并得到命令在首位的阵列是不是一种选择,那么你就需要使用eval把它放回阵列:

$ args="--foo 'bar baz' qux" 
$ eval "arr=($args)" 

但要注意的这是不安全的,如果$args正在由非置信源提供的,因为它可被用于执行任意的命令,例如,它是重要的在使用arr之前,args='$(rm -rf /)'; eval "arr=($args)"将导致上述代码运行rm -rf /

然后你可以使用"${arr[@]}"扩大它作为参数传递给一个命令:

$ bash -c 'echo $0' "${arr[@]}" 
--foo 
$ bash -c 'echo $1' "${arr[@]}" 
bar baz 

或运行命令:

"$command" "${arr[@]}" 

注意,有${arr[*]}${arr[@]}"${arr[*]}"之间的差异"${arr[@]}",只有最后一个在大多数情况下做你想要的东西

+1

很好的建议,但是OP询问Bourne壳。 – 2012-04-02 21:17:56

5

如果你可以扔掉于当前位置的变量($1 ......),你可以使用以下内容:

set -- '--foo' 'bar baz' 'qux' 
echo "$#" # Prints "3" (without quotes) 
echo "$2" # Prints "bar baz" (without quotes) 
command "[email protected]" 

只是在#!/usr/bin/env sh脚本测试它,因此它可以至少在短跑,并应在任何Bourne Shell中的变体工作。否eval,Python或Bash必要。

相关问题