bash如何处理嵌套引号?

时间:2014-09-19 19:49:04

标签: linux bash command-line quotes gnu-screen

我需要使用如下语法运行命令:
runuser -l userNameHere -c '/path/to/command arg1 arg2'

不幸的是,我必须在命令本身中嵌入额外的'个字符,我不能告诉bash正确解释这些字符。我想要运行的命令实际上是:

runuser -l miner -c 'screen -S Mine -p 0 -X eval 'stuff "pwd"\015''

不幸的是,bash似乎正在击中第二个'并且呕吐。这是错误:
-bash: screen -S Mine -p 0 -X eval stuff: No such file or directory,显然它没有超越'

如何将此作为一个命令嵌套?谢谢!

5 个答案:

答案 0 :(得分:7)

您可以使用bash$'...'支持的其他类型的引用。这可以包含转义的单引号。

runuser -l miner $'screen -S Mine -p 0 -X eval \'stuff "pwd"\015\''

请注意,在$'...'中,\015将被替换为代码点015处的实际ASCII字符,因此,如果这不是您想要的,则还需要转义反斜杠。

runuser -l miner $'screen -S Mine -p 0 -X eval \'stuff "pwd"\\015\''

我认为您可以利用$'...'来消除对eval的需求:

runuser -l miner $'screen -S Mine -p 0 -X stuff "pwd"\015'

答案 1 :(得分:5)

命令本身没有看到外部引号。 shell使用那些来避免单词分裂,但不会让命令知道它们在那里。所以如果你有:

./command foo bar "baz biz"

该命令看到三个args, foo bar baz biz ,其中空格完整,但没有引号。因此,如果你需要实际发送引号,你可以通过用另一种引用包装参数来做到这一点:

./command "foo'bar"

该命令会看到一个arg: foo' bar 。但是如果你需要发送两种类型的引号,你就有一个难以解决的问题。你可以用倾斜的牙签,报价交换或变量解决它:

引用交换

即使shell使用引号来避免单词分裂,如果你将引用的参数放在彼此旁边而没有空格,命令会将它看作一个单词:

./command "foo""bar"

该命令会看到一个arg: foobar 。因此,如果您使用两种不同的报价:

./command 'foo"bar'"baz'quux"

命令会看到一个arg: foo" barbaz' quux

倾斜的牙签

有两种倾斜的牙签。一个是真正的报价交换,除非你不使用引号来包装其中一个...引用。

./command 'foo"barbaz'\'quux

命令会看到一个arg: foo" barbaz' quux 。另一个是(帽子提示:chepner)使用特殊的$'string'形式的单词扩展,它允许ANSI C字符串:

./command $'foo"barbaz\'quux'

命令会看到一个arg: foo" barbaz' quux

变量

doublequote=\" singlequote=\'
./command "foo${doublequote}barbaz${singlequote}quux"

命令会看到一个arg: foo" barbaz' quux

答案 2 :(得分:1)

您不能在单引号中嵌套单引号。您可以通过转义双引号来嵌套双引号。

使用单引号可以做的最好的事情就是在需要嵌入单引号的地方使用'\''

这是结束单引号字符串的单引号。一个不带引号但却逃脱的单引号。并使用单引号开始下一个单引号字符串。

答案 3 :(得分:1)

请参阅我的回答here。基本上,你不能将单引号放在单引号内 - 但是你不必这样做,因为引号不是单词分隔符,所以你可以跳出引号,关闭{{1现在,您使用'在引号之外添加一个文字单引号,然后使用新的\'返回引号,所有这些都不会终止当前的shell字。

答案 4 :(得分:1)

不是手动转义,而是可以让shell为你做这件事并避免麻烦(如果你的shell是bash;这是POSIX sh中没有的扩展,所以你的shebang需要是#!/bin/bash,而非#!/bin/sh)。

例如:

printf -v command '%q ' /path/to/command arg1 arg2
printf -v outer_command '%q ' runasuser -l userNameHere -c "$command"
printf -v ssh_command '%q ' ssh hostname "$outer_command"

...会在"$ssh_command"中添加一个字符串,如果进行评估,它将在runasuser内的ssh内运行内部命令。


提供一些构造如何使用这些变量的例子:

# this evaluates the command in the current shell in a sane way
ssh hostname "$outer_command"

# this evaluates the command in the current shell in an inefficient way
eval "$ssh_command"

# this evaluates the command in a new shell
bash -c "$ssh_command"

# this evaluates the command in a new shell as a different user
sudo -u username bash -c "$ssh_command"

# this writes the command to a script, and makes it executable
printf '%s\n' "#!/bin/bash" "$ssh_command" >run_ssh
chmod +x run_ssh

提供一些示例,说明 NOT 如何使用这些变量:

# DO NOT DO THESE: WILL NOT WORK
$ssh_command        # see http://mywiki.wooledge.org/BashFAQ/050
"$ssh_command"      # likewise
sudo "$ssh_command" # likewise