请考虑以下事项:
#!/bin/tcsh
set thing = 'marker:echo "quoted argument"'
set a = `echo "$thing" | sed 's/\([^:]*\):\(.*\)/\1/'`
set b = `echo "$thing" | sed 's/\([^:]*\):\(.*\)/\2/'`
echo $a
echo $b
$b
echo "quoted argument"
这给出了
marker
echo "quoted argument"
"quoted argument"
quoted argument
如果$b
为echo "quoted argument"
,为什么评估$b
会得出echo "quoted argument"
的不同结果?
因为我知道tcsh
很糟糕(但这是我必须使用的工作),Bash中存在同样的问题:
thing='marker:echo "quoted argument"'
a=`echo "$thing" | sed 's/\(.*\):\([^:]*\)/\1/'`
b=`echo "$thing" | sed 's/\(.*\):\([^:]*\)/\2/'`
echo $a
echo $b
$b
echo "quoted argument"
输出相同。请注意,如果我在Bash中这样做,我肯定会使用地图。我没有那么奢侈:)
。解决方案必须适用于tcsh
。
我希望$b
的行为就像我在自己输入命令一样:
marker
echo "quoted argument"
quoted argument
quoted argument
答案 0 :(得分:1)
命令替换必须记住的一件事是,每个pipe
和每个command
字符串一起在其自己的子shell中执行。每次发生这种情况,shell都会处理您提供的命令或字符串:
如果$ b是echo“quoted argument”,为什么评估$ b会给出一个 echo“引用参数”的结果不同?
set thing = 'marker:echo "quoted argument"'
set b = `echo "$thing" | sed 's/\([^:]*\):\(.*\)/\2/'`
echo $b
echo "quoted argument"
对于b
,您要将sed
的回报与返回b
的回报完全相同,包括引号。他们成为b
的一部分。因此echo $b
相当于echo '"quoted argument"'
。然而,您的echo "quoted argument"
会将字符串打印为引号中包含的字符,而shell会删除文字引号。
抱歉最初的混乱。
答案 1 :(得分:1)
是的,eval
是这里的“解决方案”(解决方法是首先不要在字符串中输入命令,请参阅http://mywiki.wooledge.org/BashFAQ/050了解更多信息。)
运行$b
时看到引号的原因是由于shell命令的评估顺序。在所有其他扩展之后,shell执行的最后一件事是远程引号(但它不会删除任何扩展引起的引号)。
所以当你有b='echo "quoted arguments"'
并运行$b
作为命令行时,会发生变量扩展所以你得到echo "quoted arguments"
然后按原样运行。
$ c ()
{
printf 'argc: %s\n' "$#";
printf 'argv: %s\n' "$@"
}
$ b='echo "quoted arguments"'
$ c "quoted arguments"
argc: 1
argv: quoted arguments
$ c $b
argc: 3
argv: echo
argv: "quoted
argv: arguments"
$ c "$b"
argc: 1
argv: echo "quoted arguments"
$ eval c $b
argc: 2
argv: echo
argv: quoted arguments
$ eval c "$b"
argc: 2
argv: echo
argv: quoted arguments