在Bash中是否有需要转义的字符的完整列表?可以仅通过进行检查sed
吗?
特别是,我正在检查是否%
需要逃脱。我试过了
echo "h%h" | sed 's/%/i/g'
并且工作得很好,没有逃脱%
。这是否意味着%
不需要逃脱?这是检查必要性的好方法吗?
更笼统:它们是shell
和一起逃脱的相同字符bash
吗?
在Bash中是否有需要转义的字符的完整列表?可以仅通过进行检查sed
吗?
特别是,我正在检查是否%
需要逃脱。我试过了
echo "h%h" | sed 's/%/i/g'
并且工作得很好,没有逃脱%
。这是否意味着%
不需要逃脱?这是检查必要性的好方法吗?
更笼统:它们是shell
和一起逃脱的相同字符bash
吗?
Answers:
有两个工作,这不仅容易和安全规则sh
,但也bash
。
这适用于除单引号本身以外的所有字符。要转义单引号,请在其前关闭引号,插入单引号,然后重新打开引号。
'I'\''m a s@fe $tring which ends in newline
'
sed命令: sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"
这适用于除换行符以外的所有字符。对于换行符,请使用单引号或双引号。空字符串仍必须处理-替换为""
\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"
"
sed命令:sed -e 's/./\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
。
有一组容易安全的字符,例如[a-zA-Z0-9,._+:@%/-]
,可以不转义以使其更具可读性
I\'m\ a\ s@fe\ \$tring\ which\ ends\ in\ newline"
"
sed命令:LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
。
请注意,在sed程序中,无法知道输入的最后一行是否以换行符结尾(除非为空)。这就是上述两个sed命令都假定不这样做的原因。您可以手动添加带引号的换行符。
请注意,仅在POSIX意义上为文本定义了外壳变量。未定义处理二进制数据。对于重要的实现,二进制可以使用NUL字节(因为变量是使用C字符串实现的,并且打算用作C字符串,即程序参数),但是您应该切换到“二进制”语言环境,例如latin1 。
(您可以通过阅读的POSIX规范轻松地验证规则sh
。对于bash,请参阅@AustinPhillips链接的参考手册)
针对这种请求有一个特殊的 printf
格式指令(%q
):
printf [-v var]格式[参数]
%q causes printf to output the corresponding argument in a format that can be reused as shell input.
read foo
Hello world
printf "%q\n" "$foo"
Hello\ world
printf "%q\n" $'Hello world!\n'
$'Hello world!\n'
也可以通过变量使用它:
printf -v var "%q" "$foo
"
echo "$var"
$'Hello world\n'
请注意,必须转义从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
这必须呈现如下内容:
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
其中第一个字段是字节的六进制值,第二个包含E
是否需要转义字符,而第三个字段则显示字符的转义表示。
,
呢你可以看到一些角色,不总是需要进行转义,如,
,}
和{
。
因此,并非总是如此,但有时:
echo test 1, 2, 3 and 4,5.
test 1, 2, 3 and 4,5.
要么
echo test { 1, 2, 3 }
test { 1, 2, 3 }
但要注意:
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
subprocess.Popen(['bash', '-c', 'printf "%q\0" "$@"', '_', arbitrary_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()
将为您提供正确的带外壳引号的版本arbitrary_string
。
%q
损坏时间已经很长了-如果我的想法对我有益,那么在损坏了大约10年之后,2013年就修复了一个错误(但仍可能会损坏)。所以不要依赖它。
shlex.quote()
(> = 3.3,pipes.quote()
-未记录-对于较旧的版本)也可以完成此工作,并生成更易于理解的版本(如有必要,添加引号和转义),无需生成外壳。
,
。我惊讶地发现内置的Bash printf -- %q ','
给出\,
,但是/usr/bin/printf -- %q ','
给出,
(未转义)。同为其他字符:{
,|
,}
,~
。
为了节省别人不必RTFM ...在bash中:
在双引号包围的字符保留了引号中的所有字符的字面意义,例外
$
,`
,\
,和,启用了历史扩展的时候,!
。
...因此,如果您逃避了这些问题(当然还有引号本身),则可能还可以。
如果您采取较为保守的“不确定时逃脱”方法,则应避免不转义标识符字符(例如ASCII字母,数字或'_'),从而避免获取具有特殊含义的字符。它们极不可能(即,在某些类似于POSIX的怪异外壳中)具有特殊含义,因此需要转义。
使用该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
它给出以下输出:
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
一些结果,,
看起来有些可疑。获取@CharlesDuffy对此的输入将很有趣。
%q
不知道打算在外壳中的哪个位置使用该字符,因此它将转义所有可能在任何外壳上下文中具有特殊含义的字符。,
本身对shell没有特殊含义,但是正如@ F.Hauri在他的回复中指出的那样,它在{...}
括号扩展中确实具有特殊含义:gnu.org/savannah-checkouts/gnu/bash/manual / ...就像!这也仅需要在特定情况下进行扩展,而不是一般情况下:echo Hello World!
可以正常工作,但echo test!test
会失败。
在Bourne或POSIX Shell中,需要转义的字符与Bash不同。通常,(非常)Bash是这些shell的超集,因此您逃脱的任何东西shell
都应在Bash中逃逸。
一个好的一般规则是“如有疑问,请逃脱”。但是转义某些字符会赋予它们特殊的含义,例如\n
。这些列在man bash
下面的页面Quoting
和echo
。
除此之外,请转义任何非字母数字的字符,这样比较安全。我不知道一个明确的清单。
手册页将它们全部列出,而不是放在一个地方。学习语言,这是确定的方法。
吸引我的是!
。这是Bash(和csh)中的特殊字符(历史扩展),但在Korn Shell中不是。甚至echo "Hello world!"
给问题。照常使用单引号删除特殊含义。
sed
足够好以查看是否必须进行转义。感谢您的回答!
sed
不需要检查,您几乎可以检查任何东西。 sed
不是问题,bash
而是。单引号内没有特殊字符(单引号除外),您甚至无法在其中转义字符。一个sed
命令通常应该是单引号内,因为RE元字符与shell元字符太多的重叠是安全的。嵌入shell变量时是一个例外,必须谨慎进行。
echo
。如果您放出所放内容,则无需逃脱。:)
我认为您正在谈论bash字符串。有不同类型的字符串,对转义有不同的要求。例如。单引号字符串与双引号字符串不同。
最佳参考是bash手册的“ 报价”部分。
它说明了哪些字符需要转义。请注意,某些字符可能需要转义,具体取决于启用了哪些选项(例如历史记录扩展)。
我注意到bash在使用自动完成功能时会自动转义一些字符。
例如,如果您有一个名为的目录dir:A
,bash将自动完成以dir\:A
使用此工具,我使用ASCII表的字符进行了一些实验,并得出了以下列表:
bash在自动完成时转义的字符:(包括空格)
!"$&'()*,:;<=>?@[\]^`{|}
bash无法逃脱的字符:
#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~
(我排除了/
,因为它不能在目录名中使用)
printf %q
可以作为参数传递而不会修改-理想情况下,遍历整个字符集。