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

brqmpdu1  于 2022-11-04  发布在  Unix
关注(0)|答案(7)|浏览(208)

在Bash中有没有需要转义的字符的完整列表?可以用sed来检查吗?
特别是,我检查了%是否需要转义。

echo "h%h" | sed 's/%/i/g'

并且运行良好,没有转义%。这是否意味着%不需要转义?这是检查必要性的好方法吗?
还有更一般的:它们是否与shellbash中要转义的字符相同?

rjjhvcjd

rjjhvcjd1#

有两个简单而安全的规则,它们不仅在sh中有效,而且在bash中也有效。

1.将整个字符串用单引号括起来

这适用于除单引号本身之外的所有字符。要转义单引号,请关闭它前面的引号,插入单引号,然后重新打开引号。

'I'\''m a s@fe $tring which ends in newline
'

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

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

sed命令:LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/' .
注意,在sed程序中,我们不知道输入的最后一行是否以换行符结束(除非它是空的),这就是为什么上面的两个sed命令都假设它不以换行符结束。
注意,shell变量只定义了POSIX意义上的文本。没有定义处理二进制数据。对于重要的实现,二进制除了NUL字节之外都可以工作(因为变量是用C字符串实现的,并且打算用作C字符串,即程序参数),但是您应该切换到“二进制”语言环境,例如latin 1。
(You通过阅读sh的POSIX规范,我可以很容易地验证规则。

hlswsv35

hlswsv352#

可重复用作shell输入的格式

编辑2021年2月:bash${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'

旧答案

有一个 specialprintf指令(%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)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

这必须呈现如下内容:

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
t2a7ltrp

t2a7ltrp3#

为了让其他人不必在 bash 中进行RTFM......:
将字符括在双引号中会保留引号内所有字符的文字值,但$、```、\!(启用历史记录扩展时)除外。
......所以如果你避开这些(当然还有引语本身),你可能就没事了。
如果你采取更保守的“当有疑问时,转义它”的方法,通过不转义标识符字符(如ASCII字母、数字或“_”),应该可以避免得到具有特殊含义的字符。这些字符(如在一些奇怪的POSIX类shell中)不太可能有特殊含义,因此需要转义。

taor4pac

taor4pac4#

使用print '%q'technique,我们可以运行一个循环来找出哪些字符是特殊字符:


# !/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在这方面的意见,会很有趣。

lstz6jyr

lstz6jyr5#

在Bourne或POSIX shell中需要转义的字符与Bash不同。通常(非常)Bash是这些shell的超集,所以在shell中转义的任何字符都应该在Bash中转义。
一个很好的通用规则是“如果有疑问,就转义它”。但是转义一些字符会给它们带来特殊的含义,比如\n。这些字符列在man bash页面的Quotingecho下。
除此之外,转义任何不是字母数字的字符,这样更安全。我不知道一个单一的明确的名单。
手册页在某个地方列出了它们,但不是在一个地方。学习语言,这是确保的方法。
其中一个让我感到困惑的是!。这是Bash(和csh)中的一个特殊字符(历史扩展),但在Korn shell中却不是。即使是echo "Hello world!"也会出现问题。像往常一样,使用单引号会消除这个特殊含义。

h4cxqtbf

h4cxqtbf6#

我想你说的是bash字符串。不同类型的字符串对转义有不同的要求。例如,单引号字符串不同于双引号字符串。
最好的参考资料是bash手册的报价部分。
它解释了哪些字符需要转义。请注意,某些字符可能需要转义,这取决于启用了哪些选项,如历史记录扩展。

scyqe7ek

scyqe7ek7#

我注意到bash在使用自动完成时会自动转义一些字符。
例如,如果您有一个名为dir:A的目录,bash将自动完成为dir\:A
使用这个方法,我使用ASCII表的字符运行了一些实验,并得出了以下列表:

  • 在自动完成时进行转义的字符 *:(包括空格)
!"$&'()*,:;<=>?@[\]^`{|}
  • bash不转义的字符 *:

# %+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~

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

相关问题