con*_*ons 936 syntax bash quoting
比方说,你有一个alias像bash 一样:
alias rxvt='urxvt'
Run Code Online (Sandbox Code Playgroud)
哪个工作正常.
然而:
alias rxvt='urxvt -fg '#111111' -bg '#111111''
Run Code Online (Sandbox Code Playgroud)
不会起作用,也不会:
alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''
Run Code Online (Sandbox Code Playgroud)
那么,一旦转义了引号,你最终如何在字符串中匹配开头和结尾的引号?
alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
Run Code Online (Sandbox Code Playgroud)
看起来很笨拙虽然如果你允许这样连接它们就会代表相同的字符串.
lio*_*ori 1344
如果你真的想在最外层使用单引号,请记住你可以粘合两种报价.例:
alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
# ^^^^^ ^^^^^ ^^^^^ ^^^^
# 12345 12345 12345 1234
Run Code Online (Sandbox Code Playgroud)
解释如何'"'"'被解释为':
' 结束使用单引号的第一个引用." 使用双引号开始第二次引用.' 引用字符." 结束第二次报价,使用双引号.' 使用单引号启动第三个引号.如果不在(1)和(2)之间,或者在(4)和(5)之间放置任何空格,shell将把该字符串解释为一个长字.
Adr*_*onk 243
我总是用序列替换每个嵌入的单引号:( '\''即:引用反斜杠引用引号),它关闭字符串,附加转义的单引号并重新打开字符串.
我经常在我的Perl脚本中添加一个"quotify"函数来为我做这个.步骤将是:
s/'/'\\''/g # Handle each embedded quote
$_ = qq['$_']; # Surround result with single quotes.
Run Code Online (Sandbox Code Playgroud)
这几乎照顾了所有情况.
引入evalshell脚本时,生活会变得更有趣.你基本上必须再次重新报价!
例如,创建一个名为quotify的Perl脚本,其中包含以上语句:
#!/usr/bin/perl -pl
s/'/'\\''/g;
$_ = qq['$_'];
Run Code Online (Sandbox Code Playgroud)
然后用它来生成一个正确引用的字符串:
$ quotify
urxvt -fg '#111111' -bg '#111111'
Run Code Online (Sandbox Code Playgroud)
结果:
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
Run Code Online (Sandbox Code Playgroud)
然后可以将其复制/粘贴到alias命令中:
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
Run Code Online (Sandbox Code Playgroud)
(如果需要将命令插入eval,请再次运行quotify:
$ quotify
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
Run Code Online (Sandbox Code Playgroud)
结果:
'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''
Run Code Online (Sandbox Code Playgroud)
可以复制/粘贴到eval中:
eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''
Run Code Online (Sandbox Code Playgroud)
mj4*_*j41 175
由于Bash 2.04语法$'string'(而不仅仅是'string';警告:不要混淆$('string'))是另一种引用机制,它允许ANSI C类转义序列并扩展到单引号版本.
简单的例子:
$> echo $'aa\'bb'
aa'bb
$> alias myvar=$'aa\'bb'
$> alias myvar
alias myvar='aa'\''bb'
Run Code Online (Sandbox Code Playgroud)
在你的情况下:
$> alias rxvt=$'urxvt -fg \'#111111\' -bg \'#111111\''
$> alias rxvt
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
Run Code Online (Sandbox Code Playgroud)
常见的转义序列按预期工作:
\' single quote
\" double quote
\\ backslash
\n new line
\t horizontal tab
\r carriage return
Run Code Online (Sandbox Code Playgroud)
以下是man bash(版本4.4)的复制+粘贴相关文档:
$'string'形式的单词是专门处理的.单词扩展为字符串,替换为ANSI C标准指定的反斜杠转义字符.反斜杠转义序列(如果存在)按如下方式解码:
\a alert (bell)
\b backspace
\e
\E an escape character
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\' single quote
\" double quote
\? question mark
\nnn the eight-bit character whose value is the octal
value nnn (one to three digits)
\xHH the eight-bit character whose value is the hexadecimal
value HH (one or two hex digits)
\uHHHH the Unicode (ISO/IEC 10646) character whose value is
the hexadecimal value HHHH (one to four hex digits)
\UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value
is the hexadecimal value HHHHHHHH (one to eight
hex digits)
\cx a control-x character
Run Code Online (Sandbox Code Playgroud)
扩展结果是单引号,好像美元符号不存在一样.
有关更多详细信息,请参阅bash-hackers.org wiki上的引用和转义:ANSI C类似字符串.另请注意,"Bash Changes"文件(此处概述)提到了很多与$'string'引用机制相关的更改和错误修复.
根据unix.stackexchange.com 如何使用特殊字符作为普通字符?它应该在bash,zsh,mksh,ksh93和FreeBSD以及busybox sh中工作(有一些变化).
Ste*_* B. 48
我没有看到他博客上的条目(链接请参阅?)但是根据gnu参考手册:
用单引号(''')括起字符可以保留引号中每个字符的字面值.单引号之间可能不会出现单引号,即使前面有反斜杠也是如此.
所以bash不会理解:
alias x='y \'z '
但是,如果用双引号括起来,你可以这样做:
alias x="echo \'y "
> x
> 'y
Run Code Online (Sandbox Code Playgroud)
Mik*_*yte 29
我可以确认'\''在单引号字符串中使用单引号确实可以在Bash中使用,并且它可以用与线程早期的"粘合"参数相同的方式来解释.假设我们有一个带引号的字符串:( 'A '\''B'\'' C'这里的所有引号都是单引号).如果传递给echo,则打印以下内容:A 'B' C.在每个'\''第一个引号中关闭当前单引号字符串,下面\'将单引号粘合到前一个字符串(\'是一种指定单引号而不启动引用字符串的方式),最后一个引号打开另一个单引号字符串.
Gab*_*les 27
For most cases, the main answer with the '"'"' markers really is the best answer. But, for cases where it's not, here's my answer:
') and double quotes (") with hex and octal charsIf using something like echo, I've had some really complicated and really weird and hard-to-escape (think: very nested) cases where the only thing I could get to work was using octal or hex codes!
Here are some basic examples just to demonstrate how it works. Be sure to add the -e option to echo to process these escape sequences:
' is escaped with hex \x27 or octal \047 (its corresponding ASCII code):hex \x27
echo -e "Let\x27s get coding!"
# OR
echo -e 'Let\x27s get coding!'
Run Code Online (Sandbox Code Playgroud)
Result:
Run Code Online (Sandbox Code Playgroud)Let's get coding!
octal \047
echo -e "Let\047s get coding!"
# OR
echo -e 'Let\047s get coding!'
Run Code Online (Sandbox Code Playgroud)
Result:
Run Code Online (Sandbox Code Playgroud)Let's get coding!
" is escaped with hex \x22 or octal \042 (its corresponding ASCII code).Note: bash is nuts! Sometimes even the ! char has special meaning, and must either be removed from within the double quotes and then escaped "like this"\! or put entirely within single quotes 'like this!', rather than within double quotes.
# 1. hex; also escape `!` by removing it from within the double quotes
# and escaping it with `\!`
$ echo -e "She said, \x22Let\x27s get coding"\!"\x22"
She said, "Let's get coding!"
# OR put it all within single quotes:
$ echo -e 'She said, \x22Let\x27s get coding!\x22'
She said, "Let's get coding!"
# 2. octal; also escape `!` by removing it from within the double quotes
$ echo -e "She said, \042Let\047s get coding"\!"\042"
She said, "Let's get coding!"
# OR put it all within single quotes:
$ echo -e 'She said, \042Let\047s get coding!\042'
She said, "Let's get coding!"
# 3. mixed hex and octal, just for fun
# also escape `!` by removing it from within the double quotes when it is followed by
# another escape sequence
$ echo -e "She said, \x22Let\047s get coding! It\x27s waaay past time to begin"\!"\042"
She said, "Let's get coding! It's waaay past time to begin!"
# OR put it all within single quotes:
$ echo -e 'She said, \x22Let\047s get coding! It\x27s waaay past time to begin!\042'
She said, "Let's get coding! It's waaay past time to begin!"
Run Code Online (Sandbox Code Playgroud)
Note that if you don't properly escape !, when needed, as I've shown two ways to do above, you'll get some weird errors, like this:
$ echo -e "She said, \x22Let\047s get coding! It\x27s waaay past time to begin!\042"
bash: !\042: event not found
Run Code Online (Sandbox Code Playgroud)
OR:
$ echo -e "She said, \x22Let\x27s get coding!\x22"
bash: !\x22: event not found
Run Code Online (Sandbox Code Playgroud)
Here is another demo of an alternative escaping technique.
首先,阅读@liori 的主要答案,看看下面的第二种形式是如何工作的。现在,阅读这两种转义字符的替代方法。下面的两个示例的输出是相同的:
CMD="gs_set_title"
# 1. 1st technique: escape the $ symbol with a backslash (\) so it doesn't
# run and expand the command following it
echo "$CMD '\$(basename \"\$(pwd)\")'"
# 2. 2nd technique (does the same thing in a different way): escape the
# $ symbol using single quotes around it, and the single quote (') symbol
# using double quotes around it
echo "$CMD ""'"'$(basename "$(pwd)")'"'"
Run Code Online (Sandbox Code Playgroud)
示例输出:
Run Code Online (Sandbox Code Playgroud)gs_set_title '$(basename "$(pwd)")' gs_set_title '$(basename "$(pwd)")'
注意:对于我的gs_set_titlebash 函数,我在~/.bash_aliases文件中的某个位置有该函数,请参阅我的其他答案。
小智 16
两个版本都可以正常工作,可以通过使用转义的单引号字符(\')进行连接,也可以通过将单引号字符括在双引号("'")中进行连接.
该问题的作者没有注意到在他最后一次逃避尝试结束时有一个额外的单引号('):
alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
? ???| ???? ???? ????
??STRING???????STRIN??????STR??????STRIN?????
?? ?? ?? ???
?? ?? ?? ???
??????????????????????????????????
All escaped single quotes ?
?
?
Run Code Online (Sandbox Code Playgroud)
正如您在上一篇优秀的ASCII/Unicode艺术作品中所看到的,最后一个转义的单引号(\')后跟一个不必要的单引号(').使用类似于Notepad ++中的语法高亮显示器可以证明非常有用.
对于另一个例子,如下所示,情况也是如此:
alias rc='sed '"'"':a;N;$!ba;s/\n/, /g'"'"
alias rc='sed '\'':a;N;$!ba;s/\n/, /g'\'
Run Code Online (Sandbox Code Playgroud)
这两个漂亮的别名实例以非常复杂和混淆的方式显示文件如何排列.也就是说,从包含大量行的文件中,只能在前一行的内容之间使用逗号和空格.为了理解之前的评论,以下是一个例子:
$ cat Little_Commas.TXT
201737194
201802699
201835214
$ rc Little_Commas.TXT
201737194, 201802699, 201835214
Run Code Online (Sandbox Code Playgroud)
ken*_*orb 16
在shell中转义引号的简单示例:
$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc
Run Code Online (Sandbox Code Playgroud)
这是通过完成已经打开的one('),放置一个(\'),然后打开另一个(')来完成的.此语法适用于所有命令.这与第一个答案非常相似.
use*_*550 16
需要一个最小的答案,这样人们就可以开始工作,而不必花费大量时间,因为我不得不筛选那些口若悬河的人。
没有任何方法可以转义单引号或单引号内的其他任何内容。
也许令人惊讶的是,以下是一个完整的命令:
echo '\'
Run Code Online (Sandbox Code Playgroud)
其输出是:
\
Run Code Online (Sandbox Code Playgroud)
令 Bash 的长期用户感到惊讶的是,反斜杠在单引号内没有任何意义。也没有其他任何事情。
nic*_*bot 14
我并没有专门解决引用问题,因为有时,考虑替代方法是合理的.
rxvt() { urxvt -fg "#${1:-000000}" -bg "#${2:-FFFFFF}"; }
Run Code Online (Sandbox Code Playgroud)
您可以将其称为:
rxvt 123456 654321
Run Code Online (Sandbox Code Playgroud)
这个想法是你现在可以别名,而不用担心引号:
alias rxvt='rxvt 123456 654321'
Run Code Online (Sandbox Code Playgroud)
或者,如果#由于某种原因需要包括所有呼叫:
rxvt() { urxvt -fg "${1:-#000000}" -bg "${2:-#FFFFFF}"; }
Run Code Online (Sandbox Code Playgroud)
您可以将其称为:
rxvt '#123456' '#654321'
Run Code Online (Sandbox Code Playgroud)
那么,当然,别名是:
alias rxvt="rxvt '#123456' '#654321'"
Run Code Online (Sandbox Code Playgroud)
(哎呀,我想我确实解决了引用:)
Rob*_*ens 10
我只是使用shell代码...例如\x27或\\x22适用.没有麻烦,真的.
由于不能在单引号字符串中放置单引号,因此最简单且最易读的选项是使用HEREDOC字符串
command=$(cat <<'COMMAND'
urxvt -fg '#111111' -bg '#111111'
COMMAND
)
alias rxvt=$command
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,HEREDOC被发送到cat命令,并通过命令替换表示法将其输出分配给变量$(..)
需要在HEREDOC周围添加单引号,因为它位于a $()
恕我直言,真正的答案是你无法在单引号字符串中转义单引号.
不可能.
如果我们假设我们正在使用bash.
从bash手册...
Enclosing characters in single quotes preserves the literal value of each
character within the quotes. A single quote may not occur
between single quotes, even when preceded by a backslash.
Run Code Online (Sandbox Code Playgroud)
你需要使用其他一个字符串转义机制"或\
关于alias使用单引号的要求没有什么神奇之处.
以下两个都在bash中工作.
alias rxvt="urxvt -fg '#111111' -bg '#111111'"
alias rxvt=urxvt\ -fg\ \'#111111\'\ -bg\ \'#111111\'
Run Code Online (Sandbox Code Playgroud)
后者正在使用\来逃避空间角色.
#111111也没有什么神奇之处需要单引号.
以下选项与其他两个选项的结果相同,因为rxvt别名按预期工作.
alias rxvt='urxvt -fg "#111111" -bg "#111111"'
alias rxvt="urxvt -fg \"#111111\" -bg \"#111111\""
Run Code Online (Sandbox Code Playgroud)
你也可以直接逃避麻烦的#
alias rxvt="urxvt -fg \#111111 -bg \#111111"
Run Code Online (Sandbox Code Playgroud)
大多数答案都是针对您所询问的具体案例.有一种普遍的做法,我和一个朋友已经开发了允许任意的情况下,引用您需要引用通过shell扩展,例如,通过ssh的多层次的bash命令,su -c,bash -c,等,有一个核心的基本需要,在这里在本地bash中:
quote_args() {
local sq="'"
local dq='"'
local space=""
local arg
for arg; do
echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
space=" "
done
}
Run Code Online (Sandbox Code Playgroud)
这正是它所说的:它单独引用每个参数(当然是在bash扩展之后):
$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'
Run Code Online (Sandbox Code Playgroud)
对于一层扩展,它显而易见:
$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2
Run Code Online (Sandbox Code Playgroud)
(注意,使用双引号$(quote_args ...)是将结果转换为单个参数所必需的bash -c.)并且它可以更普遍地用于通过多个扩展层正确引用:
$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2
Run Code Online (Sandbox Code Playgroud)
上面的例子:
quote_args单独引用内部的每个参数,然后将结果输出组合成具有内部双引号的单个参数.bash,-c以及步骤1中已经引用过的结果,然后将结果与外部双引号组合成一个参数.bash -c.这就是简单的想法.你可以用这个来做一些非常复杂的事情,但你必须要小心评估的顺序以及引用哪些子串.例如,以下做错事(对于"错误"的某些定义):
$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure
Run Code Online (Sandbox Code Playgroud)
在第一示例中,bash的立即膨胀quote_args cd /; pwd 1>&2成两个单独的命令,quote_args cd /并且pwd 1>&2,因此,CWD仍/tmp的时pwd被执行的命令.第二个例子说明了一个类似于globbing的问题.实际上,所有bash扩展都会出现同样的基本问题.这里的问题是命令替换不是函数调用:它实际上是在评估一个bash脚本并将其输出作为另一个bash脚本的一部分.
如果你试图简单地转义shell运算符,你就会失败,因为传递给bash -c它的结果字符串只是一系列单独引用的字符串,然后不会被解释为运算符,如果你回显字符串就很容易看到已经传递给bash:
$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'
Run Code Online (Sandbox Code Playgroud)
这里的问题是你过度引用.您需要的是操作符不被引用作为封闭的输入bash -c,这意味着它们需要在$(quote_args ...)命令替换之外.
因此,在最一般意义上,您需要做的是在命令替换时单独引用命令的每个单词并不打算扩展,并且不对shell运算符应用任何额外的引用:
$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success
Run Code Online (Sandbox Code Playgroud)
一旦你完成了这个,整个字符串是公平的游戏,以进一步引用任意级别的评估:
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success
Run Code Online (Sandbox Code Playgroud)
等等
这些例子可能看起来过于紧张,因为单词喜欢success,sbin并且pwd不需要被shell引用,但是在编写任意输入的脚本时要记住的关键点是你要引用你并不是绝对确定的所有内容.牛逼需要报价,因为你永远不知道什么时候,用户将在一个扔Robert'; rm -rf /.
为了更好地理解幕后的内容,您可以使用两个小助手函数:
debug_args() {
for (( I=1; $I <= $#; I++ )); do
echo -n "$I:<${!I}> " 1>&2
done
echo 1>&2
}
debug_args_and_run() {
debug_args "$@"
"$@"
}
Run Code Online (Sandbox Code Playgroud)
在执行命令之前,它将枚举命令的每个参数:
$ debug_args_and_run echo a'"'b"'"c arg2
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
Run Code Online (Sandbox Code Playgroud)
显然,简单地用双引号引起来会更容易,但是其中的挑战在哪里?这是仅使用单引号的答案。我使用变量而不是这样alias更容易打印证明,但它与使用alias.
$ rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'
$ echo $rxvt
urxvt -fg '#111111' -bg '#111111'
Run Code Online (Sandbox Code Playgroud)
解释
关键是您可以关闭单引号并根据需要多次重新打开它。例如foo='a''b'与 相同foo='ab'。因此,您可以关闭单引号,放入文字单引号\',然后重新打开下一个单引号。
分解图
该图通过使用括号来清楚地显示单引号的打开和关闭位置。引号不像括号那样“嵌套”。您还可以注意正确应用的颜色突出显示。带引号的字符串是栗色的,而\'是黑色的。
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\' # Original
[^^^^^^^^^^] ^[^^^^^^^] ^[^^^^^] ^[^^^^^^^] ^ # Show open/close quotes
urxvt -fg ' #111111 ' -bg ' #111111 ' # Literal characters remaining
Run Code Online (Sandbox Code Playgroud)
(这本质上与阿德里安的答案相同,但我觉得这更好地解释了它。而且他的答案末尾有两个多余的单引号。)