使用Bash时需要转义哪些字符?

fed*_*qui 173 unix bash shell escaping special-characters

是否有任何需要在Bash中转义的完整字符列表?可以用它来检查sed吗?

特别是,我正在检查是否%需要转义.我试过了

echo "h%h" | sed 's/%/i/g'
Run Code Online (Sandbox Code Playgroud)

工作得很好,没有逃脱%.这是否意味着%不需要逃脱?这是检查必要性的好方法吗?

而更普遍的:它们是相同的字符,以逃避shellbash

Jo *_* So 235

有两个简单而安全的规则,不仅适用于工作,sh也适用于bash.

1.将整个字符串放在单引号中

这适用于除单引号本身之外的所有字符.要逃避单引号,请关闭之前的引号,插入单引号,然后重新打开引号.

'I'\''m a s@fe $tring which ends in newline
'
Run Code Online (Sandbox Code Playgroud)

sed命令: sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"

2.用反斜杠逃脱每个字符

这适用于除换行符之外的所有字符.对于换行符,请使用单引号或双引号.仍然必须处理空字符串 - 替换为""

\I\'\m\ \a\ \s\@\f\e\ \$\t\r\i\n\g\ \w\h\i\c\h\ \e\n\d\s\ \i\n\ \n\e\w\l\i\n\e"
"
Run Code Online (Sandbox Code Playgroud)

sed命令:sed -e 's/./\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'.

2B.更易读的2版本

有一个简单安全的字符集,例如[a-zA-Z0-9,._+:@%/-],可以保留未转义的字符以使其更具可读性

I\'m\ a\ s@fe\ \$tring\ which\ ends\ in\ newline"
"
Run Code Online (Sandbox Code Playgroud)

sed命令:LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'.


请注意,在sed程序中,无法知道输入的最后一行是否以换行符结束(除非它是空的).这就是为什么上述sed命令都假定它没有.您可以手动添加引用的换行符.

请注意,shell变量仅为POSIX意义上的文本定义.未定义处理二进制数据.对于重要的实现,二进制工作除了NUL字节(因为变量是用C字符串实现的,并且意味着用作C字符串,即程序参数),但是你应该切换到"二进制"语言环境,例如latin1 .


(您可以通过阅读POSIX规范轻松验证规则sh.对于bash,请查看由@AustinPhillips链接的参考手册)

  • 请注意其他任何人(比如我!)努力让这些工作....看起来像你在OSX上获得的sed的味道不​​能正确运行这些sed命令.虽然它们在Linux上运行良好! (4认同)
  • 注意:#1 的一个很好的变体可以在这里看到:https://github.com/scop/bash-completion/blob/233421469b12d3b60e7595822cc9166016abe384/bash_completion#L138。它不需要运行`sed`,但需要`bash`。 (2认同)

F. *_*uri 47

可以作为shell输入重用的格式

为这种请求构建了一个特殊的 printf格式指令(%q):

printf [-v var] format [arguments]

 %q     causes printf to output the corresponding argument
        in a format that can be reused as shell input.
Run Code Online (Sandbox Code Playgroud)

一些样品:

read foo
Hello world
printf "%q\n" "$foo"
Hello\ world

printf "%q\n" $'Hello world!\n'
$'Hello world!\n'
Run Code Online (Sandbox Code Playgroud)

这也可以通过变量使用:

printf -v var "%q" "$foo
"
echo "$var"
$'Hello world\n'
Run Code Online (Sandbox Code Playgroud)

快速检查所有(128)ascii字节:

请注意,必须转义从128到255的所有字节.

for i in {0..127} ;do
    printf -v var \\%o $i
    printf -v var $var
    printf -v res "%q" "$var"
    esc=E
    [ "$var" = "$res" ] && esc=-
    printf "%02X %s %-7s\n" $i $esc "$res"
done |
    column
Run Code Online (Sandbox Code Playgroud)

这必须呈现如下:

00 E ''         1A E $'\032'    34 - 4          4E - N          68 - h      
01 E $'\001'    1B E $'\E'      35 - 5          4F - O          69 - i      
02 E $'\002'    1C E $'\034'    36 - 6          50 - P          6A - j      
03 E $'\003'    1D E $'\035'    37 - 7          51 - Q          6B - k      
04 E $'\004'    1E E $'\036'    38 - 8          52 - R          6C - l      
05 E $'\005'    1F E $'\037'    39 - 9          53 - S          6D - m      
06 E $'\006'    20 E \          3A - :          54 - T          6E - n      
07 E $'\a'      21 E \!         3B E \;         55 - U          6F - o      
08 E $'\b'      22 E \"         3C E \<         56 - V          70 - p      
09 E $'\t'      23 E \#         3D - =          57 - W          71 - q      
0A E $'\n'      24 E \$         3E E \>         58 - X          72 - r      
0B E $'\v'      25 - %          3F E \?         59 - Y          73 - s      
0C E $'\f'      26 E \&         40 - @          5A - Z          74 - t      
0D E $'\r'      27 E \'         41 - A          5B E \[         75 - u      
0E E $'\016'    28 E \(         42 - B          5C E \\         76 - v      
0F E $'\017'    29 E \)         43 - C          5D E \]         77 - w      
10 E $'\020'    2A E \*         44 - D          5E E \^         78 - x      
11 E $'\021'    2B - +          45 - E          5F - _          79 - y      
12 E $'\022'    2C E \,         46 - F          60 E \`         7A - z      
13 E $'\023'    2D - -          47 - G          61 - a          7B E \{     
14 E $'\024'    2E - .          48 - H          62 - b          7C E \|     
15 E $'\025'    2F - /          49 - I          63 - c          7D E \}     
16 E $'\026'    30 - 0          4A - J          64 - d          7E E \~     
17 E $'\027'    31 - 1          4B - K          65 - e          7F E $'\177'
18 E $'\030'    32 - 2          4C - L          66 - f      
19 E $'\031'    33 - 3          4D - M          67 - g      
Run Code Online (Sandbox Code Playgroud)

第一个字段是byte的hexa值,第二E个字段包含if字符需要转义而第三个字段显示转义字符的转义.

为什么,

你可以看到一些角色,不总是需要进行转义,如,,}{.

所以不经常,但有时:

echo test 1, 2, 3 and 4,5.
test 1, 2, 3 and 4,5.
Run Code Online (Sandbox Code Playgroud)

要么

echo test { 1, 2, 3 }
test { 1, 2, 3 }
Run Code Online (Sandbox Code Playgroud)

但要小心:

echo test{1,2,3}
test1 test2 test3

echo test\ {1,2,3}
test 1 test 2 test 3

echo test\ {\ 1,\ 2,\ 3\ }
test  1 test  2 test  3

echo test\ {\ 1\,\ 2,\ 3\ }
test  1, 2 test  3 
Run Code Online (Sandbox Code Playgroud)

  • @ThorSummoner,如果您将字符串作为文字参数从不同的语言(您可能已经知道如何引用)传递给 shell,则不会。在 Python 中:`subprocess.Popen(['bash', '-c', 'printf "%q\0" "$@"', '_',任意字符串], stdin=subprocess.PIPE, stdout=subprocess.PIPE ).communicate()` 会给你一个正确的 shell 引用版本的 `arbitrary_string`。 (2认同)
  • 感谢您添加有关“,”的特别注释。我很惊讶地发现内置 Bash `printf -- %q ','` 给出了 `\,`,但是 `/usr/bin/printf -- %q ','` 给出了 `,` (未转义) )。其他字符相同:`{`、`|`、`}`、`~`。 (2认同)

Mat*_*hew 32

为了节省别人不必RTFM ...在bash中:

在双引号包围的字符保留了引号中的所有字符的字面意义,例外$,`,\,和,启用了历史扩展的时候,!.

...所以,如果你逃避那些(当然还有报价本身),你可能还可以.

如果你采取更保守的"有疑问,逃避它"的方法,应该可以通过不转义标识符字符(即ASCII字母,数字或'_')来避免获得具有特殊含义的字符.它们不太可能(即在一些奇怪的POSIX-ish shell中)具有特殊含义,因此需要进行转义.

  • 这是上面引用的手册:https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html (2认同)

cod*_*ter 23

使用这种print '%q' 技术,我们可以运行一个循环来找出特殊的字符:

#!/bin/bash
special=$'`!@#$%^&*()-_+={}|[]\\;\':",.<>?/ '
for ((i=0; i < ${#special}; i++)); do
    char="${special:i:1}"
    printf -v q_char '%q' "$char"
    if [[ "$char" != "$q_char" ]]; then
        printf 'Yes - character %s needs to be escaped\n' "$char"
    else
        printf 'No - character %s does not need to be escaped\n' "$char"
    fi
done | sort
Run Code Online (Sandbox Code Playgroud)

它给出了这个输出:

No, character % does not need to be escaped
No, character + does not need to be escaped
No, character - does not need to be escaped
No, character . does not need to be escaped
No, character / does not need to be escaped
No, character : does not need to be escaped
No, character = does not need to be escaped
No, character @ does not need to be escaped
No, character _ does not need to be escaped
Yes, character   needs to be escaped
Yes, character ! needs to be escaped
Yes, character " needs to be escaped
Yes, character # needs to be escaped
Yes, character $ needs to be escaped
Yes, character & needs to be escaped
Yes, character ' needs to be escaped
Yes, character ( needs to be escaped
Yes, character ) needs to be escaped
Yes, character * needs to be escaped
Yes, character , needs to be escaped
Yes, character ; needs to be escaped
Yes, character < needs to be escaped
Yes, character > needs to be escaped
Yes, character ? needs to be escaped
Yes, character [ needs to be escaped
Yes, character \ needs to be escaped
Yes, character ] needs to be escaped
Yes, character ^ needs to be escaped
Yes, character ` needs to be escaped
Yes, character { needs to be escaped
Yes, character | needs to be escaped
Yes, character } needs to be escaped
Run Code Online (Sandbox Code Playgroud)

一些结果,,看起来有点可疑.获得@ CharlesDuffy的投入会很有趣.

  • 您可能会在[我的答案](/sf/answers/1947225311/)的最后一段中看到*`的答案,看起来有点可疑*。 (2认同)
  • 请记住,`%q`不知道您打算在shell中使用哪个字符,因此它将在所有可能的shell上下文中转义所有具有特殊含义的字符。`,`本身对她的shell没有特殊意义,但正如@ F.Hauri在他的回复中指出的那样,它在`{...}`花括号扩展中确实具有特殊含义:https://www.gnu.org /savannah-checkouts/gnu/bash/manual/bash.html#Brace-Expansion就像!这也只需要在特定情况下进行扩展,而不是一般情况下:“ echo Hello World!”效果很好,但是“ echo test!test”将失败。 (2认同)

cda*_*rke 18

需要转义的字符在Bourne或POSIX shell中与Bash不同.通常(非常)Bash是这些shell的超集,所以你逃脱的任何东西都shell应该在Bash中转义.

一个很好的一般规则是"如果有疑问,就逃避它".但逃避一些角色给了他们一个特殊的意义,比如\n.这些列在man bash下面的页面Quotingecho.

除此之外,逃避任何不是字母数字的字符,它更安全.我不知道一个明确的清单.

手册页将它们列在某处,但不在一个地方.学习语言,这是确定的方法.

一个让我感到困惑的是!.这是Bash(和csh)中的特殊字符(历史扩展),但不是Korn shell中的特殊字符.甚至echo "Hello world!"出问题.像往常一样使用单引号删除了特殊含义.

  • 用`echo`检查.如果你把它放进去,它就不需要转义.:) (5认同)
  • @fedorqui:没有必要用`sed`检查,几乎可以检查任何东西.`sed`不是问题,'bash`是.在单引号内没有特殊字符(单引号除外),你甚至无法转义那里的字符.`sed`命令通常应该在单引号内,因为RE元字符与shell元字符的重叠太多是安全的.嵌入shell变量的例外情况是必须仔细完成的. (2认同)

Aus*_*ips 6

我想你说的是 bash 字符串。有不同类型的字符串对转义有不同的要求。例如。单引号字符串不同于双引号字符串。

最好的参考是bash 手册的引用部分。

它解释了哪些字符需要转义。请注意,根据启用的选项(例如历史扩展),某些字符可能需要转义。

  • 因此,它确认转义是一种没有简单解决方案的 _jungle_,必须检查每种情况。谢谢! (3认同)

小智 5

我注意到 bash 在使用自动完成功能时会自动转义一些字符。

例如,如果您有一个名为 的目录dir:A,bash 将自动完成dir\:A

使用它,我使用 ASCII 表的字符运行了一些实验并得出以下列表:

bash 在自动完成时转义的字符:(包括空格)

 !"$&'()*,:;<=>?@[\]^`{|}
Run Code Online (Sandbox Code Playgroud)

bash 不会转义的字符

#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~
Run Code Online (Sandbox Code Playgroud)

(我排除了/,因为它不能用于目录名称)

  • 如果您真的想要一个完整的列表,我建议您查看哪些字符 `printf %q` 作为参数传递时会修改和不会修改 - 理想情况下,遍历整个字符集。 (2认同)