是否有需要在 Bash 中转义的完整字符列表?可以检查sed吗?
特别是,我正在检查是否%需要转义。我试过
echo "h%h" | sed 's/%/i/g'
并且工作正常,没有逃脱%。这是否意味着%不需要转义?这是检查必要性的好方法吗?
更笼统地说:它们是要在shelland中转义的相同字符bash吗?
是否有需要在 Bash 中转义的完整字符列表?可以检查sed吗?
特别是,我正在检查是否%需要转义。我试过
echo "h%h" | sed 's/%/i/g'
并且工作正常,没有逃脱%。这是否意味着%不需要转义?这是检查必要性的好方法吗?
更笼统地说:它们是要在shelland中转义的相同字符bash吗?
有两个简单且安全的规则不仅适用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 命令都假定它没有。您可以手动添加带引号的换行符。
请注意,shell 变量仅为 POSIX 意义上的文本定义。未定义处理二进制数据。对于重要的实现,除了 NUL 字节外,二进制工作(因为变量是用 C 字符串实现的,并且打算用作 C 字符串,即程序参数),但是您应该切换到“二进制”语言环境,例如 latin1 .
(您可以通过阅读 POSIX 规范轻松验证规则sh。对于 bash,请查看@AustinPhillips 链接的参考手册)
${var@Q}在 bash 下,您可以使用Parameter Expansion的Parameter transformation@命令存储变量内容:
${parameter@operator} Parameter transformation. The expansion is either a transforma‐ tion of the value of parameter or information about parameter itself, depending on the value of operator. Each operator is a single letter: Q The expansion is a string that is the value of parameter quoted in a format that can be reused as input. ... A The expansion is a string in the form of an assignment statement or declare command that, if evaluated, will recreate parameter with its attributes and value.
样本:
$ var=$'Hello\nGood world.\n'
$ echo "$var"
Hello
Good world.
$ echo "${var@Q}"
$'Hello\nGood world.\n'
$ echo "${var@A}"
var=$'Hello\nGood world.\n'
为这种请求构建了一个特殊 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
为了避免其他人不得不在bash中使用 RTFM... :
将字符括在双引号中会保留引号内所有字符的字面值,但
$,`,\, 和启用历史扩展时除外!。
...因此,如果您逃避这些(当然还有报价本身),您可能还可以。
如果您采取更保守的“如有疑问,请转义”方法,应该可以通过不转义标识符字符(即 ASCII 字母、数字或“_”)来避免获取具有特殊含义的字符。这些(即在一些奇怪的 POSIX-ish shell 中)不太可能具有特殊含义,因此需要转义。
使用该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 对此的意见会很有趣。
Bourne 或 POSIX shell 中需要转义的字符与 Bash 中的字符不同。通常(非常)Bash 是这些 shell 的超集,因此您在其中转义的任何内容都shell应该在 Bash 中转义。
一个很好的一般规则是“如果有疑问,请避开它”。但是转义某些字符会赋予它们特殊的含义,例如\n. 这些在和man bash下的页面中列出。Quotingecho
除此之外,转义任何不是字母数字的字符,这样更安全。我不知道一个明确的清单。
手册页在某个地方列出了它们,但不是在一个地方。学习语言,这是确定的方法。
一个让我失望的是!。这是 Bash(和 csh)中的特殊字符(历史扩展),但在 Korn shell 中不是。甚至echo "Hello world!"会出问题。像往常一样使用单引号会删除特殊含义。
我想你在谈论 bash 字符串。有不同类型的字符串对转义有不同的要求。例如。单引号字符串与双引号字符串不同。
最好的参考是 bash 手册的引用部分。
它解释了哪些字符需要转义。请注意,某些字符可能需要转义,具体取决于启用了哪些选项,例如历史扩展。
我注意到 bash 在使用自动完成时会自动转义一些字符。
例如,如果您有一个名为 的目录dir:A,bash 将自动完成dir\:A
使用它,我使用 ASCII 表的字符进行了一些实验,并得出以下列表:
bash 在自动完成时转义的字符:(包括空格)
!"$&'()*,:;<=>?@[\]^`{|}
bash 不会转义的字符:
#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~
(我排除/了 ,因为它不能用于目录名称)