bash如何处理嵌套引号?

use*_*028 5 linux bash quotes command-line 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,显然它没有超越'.

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

che*_*ner 8

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

runuser -l miner $'screen -S Mine -p 0 -X eval \'stuff "pwd"\015\''
Run Code Online (Sandbox Code Playgroud)

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

runuser -l miner $'screen -S Mine -p 0 -X eval \'stuff "pwd"\\015\''
Run Code Online (Sandbox Code Playgroud)

我认为你可以利用它$'...'来消除这种需要eval:

runuser -l miner $'screen -S Mine -p 0 -X stuff "pwd"\015'
Run Code Online (Sandbox Code Playgroud)

  • 很好,我不知道你可以用'$''来做到这一点 (2认同)

koj*_*iro 6

该命令本身看不到外部引号。外壳程序使用它们来避免单词拆分,但是不让命令知道它们在那里。因此,如果您有:

./command foo bar "baz biz"
Run Code Online (Sandbox Code Playgroud)

该命令将看到三个args,foobarbaz biz,这些空格完整无缺,但没有引号。因此,如果您需要实际发送引号,则可以通过将参数包装在另一种引号上来实现:

./command "foo'bar"
Run Code Online (Sandbox Code Playgroud)

该命令看到一个arg:foo'bar。但是,如果您需要同时发送两种报价,则您将面临一个更难解决的问题。您可以使用倾斜的牙签,引号交换或变量来解决它:

报价交换

即使外壳程序使用引号来避免单词拆分,但是如果您将带引号的参数彼此相邻而没有空格,则命令会将其视为一个单词:

./command "foo""bar"
Run Code Online (Sandbox Code Playgroud)

该命令看到一个arg:foob​​ar。因此,如果您使用两种不同的引号:

./command 'foo"bar'"baz'quux"
Run Code Online (Sandbox Code Playgroud)

该命令看到一个arg:foo“ barbaz'quux

倾斜的牙签

有两种倾斜的牙签。一种是实际上只是引用交换,只是您不使用引号来包装…引号之一。

./command 'foo"barbaz'\'quux
Run Code Online (Sandbox Code Playgroud)

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

./command $'foo"barbaz\'quux'
Run Code Online (Sandbox Code Playgroud)

该命令看到一个arg:foo“ barbaz'quux

变数

doublequote=\" singlequote=\'
./command "foo${doublequote}barbaz${singlequote}quux"
Run Code Online (Sandbox Code Playgroud)

该命令看到一个arg:foo“ barbaz'quux


Eta*_*ner 5

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

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

这是结束单引号字符串的单引号。未加引号但已转义的单引号。和一个单引号开始下一个单引号字符串。


Cha*_*ffy 5

您可以要求 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"
Run Code Online (Sandbox Code Playgroud)

...将放入一个字符串,如果计算,将在inside"$ssh_command"中运行内部命令。runasuserssh


提供一些如何使用这些变量(一旦构建)的示例:

# 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
Run Code Online (Sandbox Code Playgroud)

提供一些反例,说明如何在构造后使用这些变量:

# DO NOT DO THESE: WILL NOT WORK
$ssh_command        # see http://mywiki.wooledge.org/BashFAQ/050
"$ssh_command"      # likewise
sudo "$ssh_command" # likewise
Run Code Online (Sandbox Code Playgroud)