比方说,你有一个Bash别名:

alias rxvt='urxvt'

这很好。

然而:

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

不管用,也不管用:

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

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

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

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


当前回答

shell_escape () {
    printf '%s' "'${1//\'/\'\\\'\'}'"
}

实现说明:

双引号,这样我们可以很容易地输出换行单引号,并使用${…}语法 Bash的搜索和替换如下:${varname//search/replacement} 我们用“\”代替“\” '\ "编码单个',如下所示: 单引号结束 \'编码a '(需要反斜杠,因为我们不在引号内) 又开始了单引号 Bash自动连接字符串,中间没有空格 在每个\和`之前都有一个\,因为这是${…//…/…的转义规则。}。

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

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

其他回答

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

它是不可能的。

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

您需要使用其他字符串转义机制之一"或\

没有什么神奇的关于别名要求它使用单引号。

以下两种方法都可以在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"

如何逃脱单引号(')和双引号(")与十六进制和八进制字符

如果使用像echo这样的东西,我有一些非常复杂,非常奇怪和难以逃避(想想:非常嵌套)的情况下,我唯一能做的就是使用八进制或十六进制代码!

下面是一些基本的例子来演示它是如何工作的:

1. 单引号示例,其中'转义为十六进制\x27或八进制\047(其对应的ASCII码):

十六进制\ x27 echo -e“让\x27s开始编码!” #或 echo -e“让\x27s开始编码!” 结果: 让我们开始编码吧! 八进制\ 047 echo -e“让047s开始编码!” #或 echo -e“让047s开始编码!” 结果: 让我们开始编码吧!

2. 双引号示例,其中"转义为十六进制\x22或八进制\042(其对应的ASCII码)。

注意:bash太疯狂了!有时甚至!Char有特殊的含义,必须从双引号内删除,然后转义为“像这样”\!或者完全用单引号括起来,像这样!,而不是在双引号内。

# 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!"

注意,如果你在需要的时候没有正确地转义!,就像我上面展示的两种方法一样,你会得到一些奇怪的错误,像这样:

$ echo -e "She said, \x22Let\047s get coding! It\x27s waaay past time to begin!\042"
bash: !\042: event not found

OR:

$ echo -e "She said, \x22Let\x27s get coding!\x22"
bash: !\x22: event not found

另一种选择:这允许在同一个bash字符串中混合展开和非展开

这里是另一个替代逃逸技术的演示。

首先,阅读@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)")'"'"

样例输出:

Gs_set_title '$(basename "$(pwd)")' Gs_set_title '$(basename "$(pwd)")'

注意:对于我的gs_set_title bash函数,它在我的~/。Bash_aliases文件在这里,看到我的另一个答案。

引用:

https://en.wikipedia.org/wiki/ASCII#Printable_characters https://serverfault.com/questions/208265/what-is-bash-event-not-found/208266#208266 请参见我在这里的另一个回答:如何使用echo编写非ascii字符?

我并没有特别提到引用问题,因为,有时候,考虑另一种方法是合理的。

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

(哦,我想我确实提到了引用:)

下面是我的观点——如果一个人想要sh可移植,而不仅仅是特定于bash(解决方案不是很有效,但是,因为它启动了一个外部程序——sed):

把它放在你的PATH中的quote.sh(或者只是引用)中:

# this works with standard input (stdin)
quote() {
  echo -n "'" ;
  sed 's/\(['"'"']['"'"']*\)/'"'"'"\1"'"'"'/g' ;
  echo -n "'"
}

case "$1" in
 -) quote ;;
 *) echo "usage: cat ... | quote - # single-quotes input for Bourne shell" 2>&1 ;;
esac

一个例子:

$ echo -n "G'day, mate!" | ./quote.sh -
'G'"'"'day, mate!'

当然,它会转换回:

$ echo 'G'"'"'day, mate!'
G'day, mate!

解释:基本上我们必须用引号包围输入',然后也用这个微型怪物替换任何单引号:' ' ' ' '(以配对结束开头引号',通过双引号包装它来转义找到的单引号- "'",然后最后发出一个新的开头单引号',或者在伪符号中:' + "' ' + ' == ' ' ' ' ')

一种标准的方法是使用sed和下面的替换命令:

s/\(['][']*\)/'"\1"'/g 

但是,有一个小问题是,为了在shell中使用它,需要在sed表达式本身中转义所有这些单引号字符——这会导致类似的结果

sed 's/\(['"'"']['"'"']*\)/'"'"'"\1"'"'"'/g' 

(构建此结果的一个好方法是将原始表达式s/\(['][']*\)/'"\1"'/g提供给Kyle Rose'或George V. Reilly的脚本)。

最后,期望输入来自stdin是有意义的——因为通过命令行参数传递它可能已经太麻烦了。

(哦,也许我们想要添加一个小的帮助消息,这样当有人以。/quote.sh运行脚本时,脚本不会挂起——help想知道它是做什么的。)

以下是上面提到的唯一正确答案的详细说明:

有时我会在ssh上使用rsync下载,并且必须转义一个带有'两次!(天啊!)一次用于bash,一次用于ssh。这里也使用了相同的交替引用分隔符原则。

例如,假设我们想要:Louis Theroux的LA Stories……

首先,将Louis Theroux用单引号括起来表示bash,用双引号括起来表示ssh: “路易泰鲁”的 然后使用单引号转义双引号" " 使用双引号来转义撇号"'" 然后重复#2,使用单引号转义双引号“” 然后将LA Stories包含在bash的单引号中,ssh的双引号中:' ' LA Stories ' '

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

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

对一个人来说,这是一件可怕的事情——但你明白了吗