以bash字符串转义引号和管道

时间:2017-01-17 18:10:56

标签: bash

如何逃避报价和管道?

++ VBoxManage showvminfo --machinereadable d667 '|' grep '\'\''VMState="poweroff"\'\'''

执行命令:

Syntax error: Invalid parameter '|'

最后得到这个错误:

window

2 个答案:

答案 0 :(得分:7)

你没有;您需要使用eval在常规字符串参数中嵌入任意管道。

MYCMD="VBoxManage showvminfo --machinereadable \"$1\" | grep 'VMState=\"poweroff\"'"
eval "$MYCMD"

但是,除非您某些认为$1的值不会导致问题,否则不建议这样做。 (如果您需要解释这些风险可能是什么,那么您不应该使用eval。)

相反,定义一个shell函数:

mycmd () {
    VBoxManage showvminfo --machinereadable "$1" | grep 'VMState="poweroff"'
}

mycmd "$1"

答案 1 :(得分:0)

一种非常简单的方法是使用数组或位置参数。

基于阵列的解决方案:

# Build command
declare -a CMD_AND_ARGS=(command and args with normal quoting)

# Append arguments
CMD_AND_ARGS+=(more arguments quoted the normal way)

# Execute command
"${CMD_AND_ARGS[@]}"

基于位置参数的解决方案:

# Create command
set -- command and args with normal quoting

# Append arguments
set -- "$@" more arguments quoted the normal way

# Execute command
"$@"

这两个解决方案的优点是你不需要在引号内加引号,因为扩展位置参数或由双引号括起来的数组不会导致分词和扩展再次执行。

示例:

declare -a CMD=()
CMD=(ls "/dir/with spaces/in its name")
"$CMD"

set -- ls "/dir/with spaces/in its name"
"$@"

请注意,在这两种情况下,您都可以逐步构建命令,例如,根据脚本的流程,使用条件表达式(例如if / case)选择添加不同的参数。

如果要将命令传递给另一个命令,则必须单独构建每个命令(例如,两个数组),因为|符号不能在未引用的数组声明中使用,并且一旦引用将被处理作为字符串参数,不会导致管道发生。