bash 如何处理嵌套引号?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25941394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does bash deal with nested quotes?
提问by user1833028
I need to run a command with a syntax like this:runuser -l userNameHere -c '/path/to/command arg1 arg2'
我需要使用这样的语法运行命令:runuser -l userNameHere -c '/path/to/command arg1 arg2'
Unfortunately, I have to nest additional '
characters into the command itself and I can't tell bash to interpret these correctly. The command I would like to run is actually:
不幸的是,我必须'
在命令本身中嵌套其他字符,而且我无法告诉 bash 正确解释这些字符。我想运行的命令实际上是:
runuser -l miner -c 'screen -S Mine -p 0 -X eval 'stuff "pwd"\015''
Unfortunately, bash seems to be hitting the second '
and puking. This is the error: -bash: screen -S Mine -p 0 -X eval stuff: No such file or directory
, so obviously it's not getting past the '
.
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
,所以显然它没有超过'
.
How can I nest this as one command? Thank you!
如何将其作为一个命令嵌套?谢谢!
回答by chepner
You can use another type of quoting supported by bash
, $'...'
. This can contain escaped single quotes.
您可以使用另一种类型的引述的支持bash
,$'...'
。这可以包含转义的单引号。
runuser -l miner $'screen -S Mine -p 0 -X eval \'stuff "pwd"5\''
Note that within $'...'
, the \015
will be treated replaced with the actual ASCII character at codepoint 015, so if that's not what you want, you'll need to escape the backslash as well.
请注意,在 中$'...'
,\015
将被替换为代码点 015 处的实际 ASCII 字符,因此如果这不是您想要的,您还需要转义反斜杠。
runuser -l miner $'screen -S Mine -p 0 -X eval \'stuff "pwd"\015\''
I think you can take advantage of the $'...'
to remove the need for eval
as well:
我认为您也可以利用$'...'
来消除对以下方面的需求eval
:
runuser -l miner $'screen -S Mine -p 0 -X stuff "pwd"5'
回答by kojiro
The command itself doesn't see the outer quotes. The shell uses those to avoid wordsplitting, but doesn't let the command know they were there. So if you have:
命令本身看不到外部引号。shell 使用这些来避免分词,但不会让命令知道它们在那里。所以如果你有:
./command foo bar "baz biz"
The command sees three args, foo, barand baz bizwith whitespace intact, but no quotes. Thus, if you need to actually send quotes, you can do that by wrapping the argument with the other kind of quote:
该命令看到三个参数foo、bar和baz biz,空格完好无损,但没有引号。因此,如果您需要实际发送引号,您可以通过用另一种引号包裹参数来实现:
./command "foo'bar"
The command sees one arg: foo'bar. But if you need to send bothkinds of quotes, you have a harder problem to solve. You can solve it with leaning toothpicks, quote-swapping or variables:
该命令看到一个参数:foo'bar。但是,如果您需要同时发送两种报价,那么您将面临一个更难解决的问题。您可以使用倾斜牙签、引用交换或变量来解决它:
Quote swapping
报价交换
Even though the shell uses quotes to avoid wordsplitting, if you put the quoted arguments next to each other without whitespace the command will see it as one word:
即使 shell 使用引号来避免分词,如果您将带引号的参数彼此相邻放置而没有空格,命令也会将其视为一个词:
./command "foo""bar"
The command sees one arg: foobar. So if you use two different kinds of quotes:
该命令看到一个参数:foobar。因此,如果您使用两种不同类型的引号:
./command 'foo"bar'"baz'quux"
The command sees one arg: foo"barbaz'quux.
该命令看到一个参数:foo"barbaz'quux。
Leaning toothpicks
倾斜的牙签
There are two kinds of leaning toothpicks. One is really just quote swapping except you don't use quotes to wrap one of the …quotes.
有两种倾斜的牙签。一个实际上只是引号交换,除非您不使用引号来包装 ...quotes 之一。
./command 'foo"barbaz'\'quux
The command sees one arg: foo"barbaz'quux. The other is (hat tip: chepner) to use the special $'string'
form of word expansion, which allows ANSI C strings:
该命令看到一个参数:foo"barbaz'quux。另一个是(提示:chepner)使用特殊$'string'
形式的词扩展,它允许 ANSI C 字符串:
./command $'foo"barbaz\'quux'
The command sees one arg: foo"barbaz'quux.
该命令看到一个参数:foo"barbaz'quux。
Variables
变量
doublequote=\" singlequote=\'
./command "foo${doublequote}barbaz${singlequote}quux"
The command sees one arg: foo"barbaz'quux.
该命令看到一个参数:foo"barbaz'quux。
回答by Charles Duffy
Instead of escaping things manually, you can ask the shell to do it for you and avoid the trouble (if your shell is bash
; this is an extension not available in POSIX sh, so your shebang needs to be #!/bin/bash
, not #!/bin/sh
).
您可以要求 shell 为您执行此操作并避免麻烦,而不是手动转义(如果您的 shell 是bash
;这是 POSIX sh 中不可用的扩展,因此您的 shebang 需要是#!/bin/bash
,而不是#!/bin/sh
)。
For instance:
例如:
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"
...will put a string in "$ssh_command"
which, if evaluated, will run the inner command inside of runasuser
inside ssh
.
...将投入一个字符串"$ssh_command"
,如果评估的,将运行的内部命令内runasuser
内ssh
。
To provide some examples of how to use these variables, once constructed:
提供一些关于如何使用这些变量的示例,一旦构建:
# 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
To provide some counterexamples of how NOTto use these variables, once constructed:
提供一些关于如何不使用这些变量的反例,一旦构造:
# DO NOT DO THESE: WILL NOT WORK
$ssh_command # see http://mywiki.wooledge.org/BashFAQ/050
"$ssh_command" # likewise
sudo "$ssh_command" # likewise
回答by Etan Reisner
You cannot nest single quotes within single quotes. You can nest double quotes within double quotes by escaping them though.
不能在单引号内嵌套单引号。您可以通过转义双引号在双引号中嵌套双引号。
The best you can do with single quotes is to use '\''
wherever you need an embedded single quote.
使用单引号可以做的最好的事情是'\''
在需要嵌入单引号的任何地方使用。
That's a single quote to end the single quoted string. An unquoted, but escaped, single quote. And a single quote to start the next single quoted string.
这是结束单引号字符串的单引号。未加引号但已转义的单引号。和一个单引号开始下一个单引号字符串。
回答by Mark Reed
See my answer here. Basically, you can't put single quotes inside single quotes - but you don't have to, because quotation marks aren't word delimiters, so you can step out of quotes, with a close '
, add a literal single quote now that you're outside of the quotes with \'
, and then go back into quotes with a new open '
, all without terminating the current shell word.
在这里看到我的答案。基本上,您不能将单引号放在单引号内 - 但您不必这样做,因为引号不是单词分隔符,因此您可以退出引号,使用 close '
,现在添加文字单引号' 在引号之外\'
,然后使用新的 open 返回引号'
,所有这些都不会终止当前的 shell 单词。