比方说,你有一个 Bash alias 喜欢:

alias rxvt='urxvt'

效果很好。

然而:

alias rxvt='urxvt -fg '#111111' -bg '#111111''

不会起作用,也不会:

alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''

那么,一旦转义引号后,如何最终匹配字符串中的开始和结束引号呢?

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''

看起来很笨拙,尽管如果允许您像这样连接它们,它会表示相同的字符串。

有帮助吗?

解决方案

如果您确实想在最外层使用单引号,请记住您可以粘合两种引号。例子:

 alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
 #                     ^^^^^       ^^^^^     ^^^^^       ^^^^
 #                     12345       12345     12345       1234

如何解释 '"'"' 被解释为只是 ':

  1. ' 结束使用单引号的第一个引用。
  2. " 使用双引号开始第二个引用。
  3. ' 引用的字符。
  4. " 使用双引号结束第二个引用。
  5. ' 使用单引号开始第三个引用。

如果 (1) 和 (2) 之间或 (4) 和 (5) 之间没有放置任何空格,shell 会将该字符串解释为一个长单词。

其他提示

我总是只替换与序列每个嵌入式单引号:'\''(即:报价反斜线引用引用),其关闭所述字符串,追加转义单引号和重新打开该字符串。


我经常掀起“quotify”功能在我的Perl脚本为我做到这一点。的步骤是:

s/'/'\\''/g    # Handle each embedded quote
$_ = qq['$_']; # Surround result with single quotes.

这几乎花费所有病例治疗。

生活变得更有趣,当你介绍eval到你的shell的脚本。实际上需要再次重新quotify一切!

例如,创建名为quotify含有上述语句的Perl脚本:

#!/usr/bin/perl -pl
s/'/'\\''/g;
$_ = qq['$_'];

然后用它来产生一正确引号字符串:

$ quotify
urxvt -fg '#111111' -bg '#111111'

结果:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

然后可以复制/粘贴到别名命令:

alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

(如果需要插入命令到一个eval,再次运行quotify:

 $ quotify
 alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

结果:

'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

其可以是复制/粘贴到一个eval:

eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

由于击 2.04 语法$'string'(而不是仅仅'string';警告:不要混淆与$('string'))是另一种引用机制,其允许 ANSI C状转义序列和做扩展到单引号的版本。

简单示例:

  $> echo $'aa\'bb'
  aa'bb

  $> alias myvar=$'aa\'bb'
  $> alias myvar
  alias myvar='aa'\''bb'

在你的情况:

$> alias rxvt=$'urxvt -fg \'#111111\' -bg \'#111111\''
$> alias rxvt
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

普通的逸出序列作品如预期:

\'     single quote
\"     double quote
\\     backslash
\n     new line
\t     horizontal tab
\r     carriage return

下面是拷贝+粘贴相关的文档从man bash(4.4版):

形式$“字串”的词被特殊处理。字扩展为字符串,如由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

膨胀的结果是单引号,仿佛美元符号不在场。


请参阅行情和逸出:ANSI C像串上的bash-黑客的。组织维基的更多细节。还要注意的是“击变” 文件(这里 概述)提到很多关于有关$'string'引用机制的变化和bug修复。

据unix.stackexchange.com 如何使用特殊字符作为一个正常?的它应该工作(有一些变化)在bash,zsh中,mksh,ksh93的和FreeBSD和busybox的SH。

我没有看到他的博客上的条目(链接请?),但根据的 GNU参考手册

  

括在单引号字符   (“'”)保留的字面值   引号内的每个字符。一种   单引号之间可能不发生   单引号,即使前面有一个   反斜杠。

所以bash将不明白:

alias x='y \'z '

不过,你可以,如果你用双引号包围做到这一点:

alias x="echo \'y "
> x
> 'y

我可以证实,使用'\''一个单引号字符串内的单引号确实在猛砸工作,并能以同样的方式为“胶”的说法,从较早的线程来解释。假设我们有一个带引号的字符串:'A '\''B'\'' C'(这里所有报价均为单引号)。如果它被传递给回声,它打印以下内容:A 'B' C。 在每个'\''第一次报价关闭当前的单引号字符串,下面\'胶水一个单引号以前的字符串(\'是指定一个单引号,而无需启动一个引号的字符串的方式),最后报价打开另一个单引号的字符串。

在外壳逸出引号简单示例:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

它是由整理已经打开的一个(')完成后,放置一个转义(\'),然后打开另一个(')。此语法适用于所有命令。这是非常相似的方法来第一个答案。

两个版本都“由包围所述单引号字符双引号内(或者与级联“”)的工作,无论是与级联通过使用转义单引号字符(\)”

这个问题的作者没有注意到,有一个额外的单引号(')在他最后一次逃跑尝试的结束:

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
           │         │┊┊|       │┊┊│     │┊┊│       │┊┊│
           └─STRING──┘┊┊└─STRIN─┘┊┊└─STR─┘┊┊└─STRIN─┘┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      └┴─────────┴┴───┰───┴┴─────────┴┘│
                          All escaped single quotes    │
                                                       │
                                                       ?

可以在前面的漂亮的片ASCII / Unicode的现有技术见,最后逃脱单引号(\“)之后是不必要的单引号(”)。使用语法荧光笔等在记事本++所述一个本可以证明非常有益的。

这同样适用于类似以下另一示例真:

alias rc='sed '"'"':a;N;$!ba;s/\n/, /g'"'"
alias rc='sed '\'':a;N;$!ba;s/\n/, /g'\'

别名这两个美丽的实例显示在一个非常复杂和模糊的方式文件如何被内衬下来。也就是说,从很多行的文件,你只能得到一个与前行的内容之间的逗号和空格线。为了使先前的评论的意义,下面是一个例子:

$ cat Little_Commas.TXT
201737194
201802699
201835214

$ rc Little_Commas.TXT
201737194, 201802699, 201835214

我不是专门针对该报价问题,因为,有时候,它只是合理考虑一种替代方法。

rxvt() { urxvt -fg "#${1:-000000}" -bg "#${2:-FFFFFF}"; }

然后可以调用为:

rxvt 123456 654321

的想法是,你现在可以别名这一点没有行情关注:

alias rxvt='rxvt 123456 654321'

或者,如果你需要在出于某种原因所有呼叫的#

rxvt() { urxvt -fg "${1:-#000000}" -bg "${2:-#FFFFFF}"; }

然后可以调用为:

rxvt '#123456' '#654321'

然后,当然,别名是:

alias rxvt="rxvt '#123456' '#654321'"

(糟糕,我想种我没有解决引用:)

我只是用壳码..例如\x27\\x22适用。没有麻烦,曾经真的。

由于一个不能把单引号字符串内单引号,最简单和最可读选择是使用一个HEREDOC串

command=$(cat <<'COMMAND'
urxvt -fg '#111111' -bg '#111111'
COMMAND
)

alias rxvt=$command

在上面的代码中,HEREDOC经由命令替换符号cat发送到$(..)命令和其输出被分配给一个变量

把围绕HEREDOC单引号需要,因为它是一个$()

恕我直言,真正的答案是,你无法逃避单引号字符串中的单引号。

其是不可能的。

如果我们假设我们使用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.

您需要使用另一个串逃逸机制的一个“或\

有什么神奇的约alias,要求它使用单引号。

两者在bash以下工作。

alias rxvt="urxvt -fg '#111111' -bg '#111111'"
alias rxvt=urxvt\ -fg\ \'#111111\'\ -bg\ \'#111111\'

后者是使用\逃脱空格字符。

有也没有什么神奇的有关#111111,需要单引号。

以下选项实现相同的结果的其他两个选项,在于:所述的rxvt别名按预期方式工作。

alias rxvt='urxvt -fg "#111111" -bg "#111111"'
alias rxvt="urxvt -fg \"#111111\" -bg \"#111111\""

您也可以直接逸出麻烦#

alias rxvt="urxvt -fg \#111111 -bg \#111111"

大多数答案都针对您所询问的具体案例。我和一个朋友开发了一种通用方法,如果您需要通过多层 shell 扩展(例如通过 ssh)引用 bash 命令,则允许任意引用, su -c, bash -c, , ETC。您需要一个核心原语,在本机 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
}

这正是它所说的:它单独对每个参数进行 shell 引用(当然是在 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'

它对于一层扩展做了显而易见的事情:

$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2

(请注意,周围的双引号 $(quote_args ...) 有必要将结果变成单个参数 bash -c.)并且它可以更普遍地用于通过多层扩展来正确引用:

$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2

上面的例子:

  1. shell 将每个参数引用到内部 quote_args 单独,然后将结果输出组合成带有内部双引号的单个参数。
  2. shell 引号 bash, -c, ,以及步骤 1 中已被引用一次的结果,然后将结果组合成带有外部双引号的单个参数。
  3. 将混乱作为参数发送到外部 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

在第一个示例中,bash 立即展开 quote_args cd /; pwd 1>&2 分成两个单独的命令, quote_args cd /pwd 1>&2, ,所以 CWD 仍然是 /tmp 当。。。的时候 pwd 命令被执行。第二个示例说明了类似的通配问题。事实上,所有 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'

这里的问题是你过度引用了。您需要的是将运算符作为封闭的输入不加引号 bash -c, ,这意味着它们需要位于 $(quote_args ...) 命令替换。

因此,从最一般的意义上来说,您需要做的是对命令中不打算在命令替换时单独扩展的每个单词进行 shell 引用,并且不对 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

完成此操作后,整个字符串就可以进一步引用任意级别的评估:

$ 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

ETC。

鉴于像这样的词,这些例子可能看起来过度紧张 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 "$@"
    "$@"
}

这将在执行命令之前枚举命令的每个参数:

$ 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

在给定示例中,简单地用于双引号代替单引号作为外逃逸机制:

alias rxvt="urxvt -fg '#111111' -bg '#111111'"

此方法适用于很多情况下,你只是想一个固定字符串传递到命令:只要检查有壳将通过echo解释双引号字符串,并在必要时逃生用反斜杠字符

在这个例子中,你会看到的是双引号足以保护字符串:

$ echo "urxvt -fg '#111111' -bg '#111111'"
urxvt -fg '#111111' -bg '#111111'

以下是对上面提到的“唯一正确答案”的详细阐述:

有时我会通过 ssh 使用 rsync 下载,并且必须两次转义带有 ' 的文件名!(天哪!)一次用于 bash,一次用于 ssh。交替引用分隔符的相同原理在这里也起作用。

例如,假设我们想要得到:路易斯·塞洛克斯的《洛杉矶故事》...

  1. 首先,将 Louis Theroux 括在单引号(对于 bash)和双引号(对于 ssh):''路易斯·塞洛克斯''
  2. 然后使用单引号来转义双引号 '"'
  3. 使用双引号来转义撇号“'”
  4. 然后重复 #2,使用单引号转义双引号 '"'
  5. 然后将 LA Stories 用单引号(对于 bash)和双引号(对于 ssh)括起来:《洛杉矶故事》

看哪!你最终会得到这样的结果:

rsync -ave ssh '"Louis Theroux"''"'"'"'"''"s LA Stories"'

这对一个小孩子来说是一项艰巨的工作——但是你知道了

<强>的另一种方法来解决嵌套报价太多层的问题:

您正试图太多塞进太渺小了一个空间,所以使用bash函数。

问题是你想有嵌套的层次太多,基本别名技术是没有强大到足以容纳。使用这样的bash函数,以使它所以单,双引号反引号和参数传递都是正常处理,如我们所期望的:

lets_do_some_stuff() {
    tmp=$1                       #keep a passed in parameter.
    run_your_program $@          #use all your passed parameters.
    echo -e '\n-------------'    #use your single quotes.
    echo `date`                  #use your back ticks.
    echo -e "\n-------------"    #use your double quotes.
}
alias foobarbaz=lets_do_some_stuff

然后你可以使用你的$ 1和$ 2变量和单,双引号和反勾不用担心别名功能冲倒其完整性。

此程序打印:

el@defiant ~/code $ foobarbaz alien Dyson ring detected @grid 10385
alien Dyson ring detected @grid 10385
-------------
Mon Oct 26 20:30:14 EDT 2015
-------------
shell_escape () {
    printf '%s' "'${1//\'/\'\\\'\'}'"
}

实现说明:

  • 双引号,这样我们就可以轻松输出包裹单引号并使用 ${...} 句法

  • bash 的搜索和替换如下所示: ${varname//search/replacement}

  • 我们正在替换 ''\''

  • '\'' 编码单个 ' 像这样:

    1. ' 结束单引号

    2. \' 编码一个 ' (需要反斜杠,因为我们不在引号内)

    3. ' 再次启动单引号

    4. bash 自动连接字符串,字符串之间没有空格

  • 有一个 \ 在每个之前 \' 因为这是转义规则 ${...//.../...} .

string="That's "'#@$*&^`(@#'
echo "original: $string"
echo "encoded:  $(shell_escape "$string")"
echo "expanded: $(bash -c "echo $(shell_escape "$string")")"

附:始终编​​码为单引号字符串,因为它们比双引号字符串简单得多。

如果已安装GNU并行则可以使用其内部引用:

$ parallel --shellquote
L's 12" record
<Ctrl-D>
'L'"'"'s 12" record'
$ echo 'L'"'"'s 12" record'
L's 12" record

从20190222版本可以甚至--shellquote多次:

$ parallel --shellquote --shellquote --shellquote
L's 12" record
<Ctrl-D>
'"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
$ eval eval echo '"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
L's 12" record

有将引述在所有支持的壳中的字符串(不仅bash)。

此功能:

quote () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

允许内部' '的引用。使用,因为这

$ quote "urxvt -fg '#111111' -bg '#111111'"
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

如果该行报价变得更加复杂,如单引号混合双引号,就可能成为相当棘手的字符串到变量里面引用。当这样的情况出现,写出你需要一个脚本(与此类似)内引用确切的行。

#!/bin/bash

quote ()
{
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

while read line; do
    quote "$line"
done <<-\_lines_to_quote_
urxvt -fg '#111111' -bg '#111111'
Louis Theroux's LA Stories
'single quote phrase' "double quote phrase"
_lines_to_quote_

将输出:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
'Louis Theroux'\''s LA Stories'
''\''single quote phrase'\'' "double quote phrase"'

单引号内的所有正确地引用的字符串。

显然,这将是更容易简单地用双引号包围,哪来的挑战是什么?这是只使用单引号的答案。我使用的是可变的,而不是alias所以这是它更容易为打印证明,但它与使用alias

$ rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'
$ echo $rxvt
urxvt -fg '#111111' -bg '#111111'

<强>解释

关键是,你可以关闭单引号和你想重新打开它多次。例如foo='a''b'相同foo='ab'。所以,你可以关闭单引号,扔在一个单引号\',然后重新打开下一个单引号。

<强>击穿图

此图清楚地通过使用括号来表示使单引号被打开和关闭。行情不是“嵌套”像括号即可。您也可以注意颜色标示,这是正确应用。所引用的字符串是栗色,而\'是黑色的。

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'    # original
[^^^^^^^^^^] ^[^^^^^^^] ^[^^^^^] ^[^^^^^^^] ^    # show open/close quotes
 urxvt -fg   ' #111111  '  -bg   ' #111111  '    # literal characters remaining

(这基本上是相同的答案阿德里安的,但我觉得这更好的解释了吧。还有他的回答有在最后2个多余的单引号。)

下面是另一种解决方案。该函数将带一个参数,并适当地使用单引号字符引用它,正如上面的投票答案说明:

single_quote() {
  local quoted="'"
  local i=0
  while [ $i -lt ${#1} ]; do
    local ch="${1:i:1}"
    if [[ "$ch" != "'" ]]; then
      quoted="$quoted$ch"
    else
      local single_quotes="'"
      local j=1
      while [ $j -lt ${#1} ] && [[ "${1:i+j:1}" == "'" ]]; do
        single_quotes="$single_quotes'"
        ((j++))
      done
      quoted="$quoted'\"$single_quotes\"'"
      ((i+=j-1))
    fi
    ((i++))
  done
  echo "$quoted'"
}

所以,你可以使用这种方式:

single_quote "1 2 '3'"
'1 2 '"'"'3'"'"''

x="this text is quoted: 'hello'"
eval "echo $(single_quote "$x")"
this text is quoted: 'hello'

如果要生成的Python内2或Python 3壳串,以下可有助于引用参数:

#!/usr/bin/env python

from __future__ import print_function

try:  # py3
    from shlex import quote as shlex_quote
except ImportError:  # py2
    from pipes import quote as shlex_quote

s = """foo ain't "bad" so there!"""

print(s)
print(" ".join([shlex_quote(t) for t in s.split()]))

此将输出:

foo ain't "bad" so there!
foo 'ain'"'"'t' '"bad"' so 'there!'
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top