bash - shell空格转义 - 终端转义字符




如何在单引号字符串中转义单引号? (13)

shell中转义引号的简单例子:

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

这是通过完成已经打开的一个( ' ),放置一个( \' ),然后打开另一个( ' )。 此语法适用于所有命令。 这与第一个答案非常相似。

比方说,你有一个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'\''

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


解决太多嵌套引用层问题的另一种方法是:

你试图把太多的东西塞进太小的空间,所以使用bash函数。

问题是你试图有太多的嵌套层次,而基本的别名技术不够强大。 使用像这样的bash函数来使它成为单引号,双引号返回ticks并传入参数都是按照我们的预期正常处理的:

lets_do_some_stuff() {
    tmp=$1                       #keep a passed in parameter.
    run_your_program [email protected]          #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变量以及单引号,双引号和后勾号,而不用担心别名函数破坏其完整性。

这个程序打印:

[email protected] ~/code $ foobarbaz alien Dyson ring detected @grid 10385
alien Dyson ring detected @grid 10385
-------------
Mon Oct 26 20:30:14 EDT 2015
-------------

在给定的例子中,简单地使用双引号而不是单引号作为外部转义机制:

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

这种方法适用于很多情况下只需要将固定字符串传递给命令的情况:只需检查shell如何通过echo解释双引号字符串,并在必要时使用反斜杠转义字符。

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

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

如果您在Python 2或Python 3中生成shell字符串,以下内容可能有助于引用参数:

#!/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!'

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

不可能。

如果我们假设我们正在使用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代码。例如\x27\\x22 。 没有麻烦,真的。


我并没有专门解决报价问题,因为有时候,考虑采用另一种方法是合理的。

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'"

(哎呀,我想我有点解决报价:)


我总是用序列'\''替换每个嵌入的单引号(即:引号反斜杠引号引用),它会关闭字符串,附加一个转义的单引号并重新打开字符串。 我经常在我的Perl脚本中调用“quotify”函数来为我做这件事。 步骤是:

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

这几乎照顾了所有情况。

当您将eval引入shell脚本时,生活会变得更加有趣。 你基本上不得不重新引用所有的东西!

例如,创建一个名为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 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

显然,简单地用双引号括起来会更容易些,但挑战在哪里呢? 这里是只使用单引号的答案。 我使用的是一个变量而不是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个多余的单引号。)


由于Bash 2.04语法$'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)复制粘贴的相关文档:

特殊处理$'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

扩大的结果是单引号的,就好像美元符号不存在一样。

有关更多详细信息,请参阅引用和转义:ANSI C像 bash-hackers.org wiki上的字符串 。 另外请注意, “Bash Changes”文件( 2.04 )提到了与$'string'引用机制相关的更改和错误修复。

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


这两个版本都可以工作,可以通过使用转义单引号字符(\')进行连接,也可以通过将单引号字符括在双引号(“'”)中进行连接。

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

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
           |         ||||       ||||     ||||       ||||
           +-STRING--+||+-STRIN-+||+-STR-+||+-STRIN-+|||
                      ||         ||       ||         |||
                      ||         ||       ||         |||
                      ++---------++-------++---------++|
                          All escaped single quotes    |
                                                       |
                                                       ?

正如您在前一篇漂亮的ASCII艺术文章中看到的那样,最后一个转义单引号(\')之后是一个不必要的单引号(')。 使用类似Notepad ++中的语法突出显示器可以证明非常有用。

另一个例子也是如此,如下所示:

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

这个功能:

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"'

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


这是另一种解决方案。 该函数将采用单个参数,并使用单引号字符适当地引用它,就像上面投票的答案所解释的那样:

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'






quoting