bash:如何传递包含特殊字符的命令行参数


31

我已经为自己编写了一个program需要正则表达式作为输入的Linux程序。

我想在bash外壳中调用程序并将该正则表达式作为命令行参数传递给程序(还有其他命令行参数)。一个典型的正则表达式看起来像

[abc]\_[x|y]

不幸的是,人物[]以及|在特殊字符bash。因此,

program [abc]\_[x|y] anotheragument

不起作用。是否可以通过使用某种转义符或引号等来传递表达式?

(调用program "[abc]\_[x|y] anotheragument"也不起作用,因为它将两个参数解释为一个。)

Answers:


27

你可以

  1. 用反斜杠转义每个特殊符号(如中的\[abc\]_\[x\|y\])或
  2. 将整个参数双引号(如"[abc]_[x|y]")。

编辑:正如一些人指出的那样,dobleqouting不会阻止变量扩展或命令替换。因此,如果您的正则表达式包含可以被bash解释为其中之一的内容,请改用单引号


4
在bash,双引用并没有旁通膨胀变量"$HOME"或参数"${USER:-root}",命令替换在任一形式"$(date)""`date`",算术扩展"$((1 + 2))",历史扩展"!!"或反斜杠"\\"。请改用单引号。请参见bash手册的手册页,标题为“报价”。
Flimm 2013年

25

使用单引号。单引号确保没有字符被解释。

$ printf %s 'spaces  are  not  interpreted away
neither are new lines
nor variable names $TESTING
nor square brackets [TESTING]
nor pipe characters or redirection symbols | > <
nor the semicolon ;
nor backslashes \a \b \c \\
the only thing that does not work is the single quote itself
'

如果需要嵌入单引号,则有两种解决方案:

$ printf '%s\n' '[ Don'"'"'t worry, be happy! ]'
[ Don't worry, be happy! ]
$ printf '%s\n' '[ Don'\''t worry, be happy! ]'
[ Don't worry, be happy! ]

你是对的。+1
antichris

6

man bash

共有三种报价机制:转义符,单引号和双引号。

转义字符是不带引号的反斜杠(\) 。除了<newline>之外,它将保留下一个字符的文字值。如果出现\ <newline>对,并且反斜杠本身未加引号,则\ <newline>将被视为行的延续(即,它已从输入流中删除并被有效忽略)。

将字符括在单引号中可保留引号内每个字符的字面值。即使在单引号之前加反斜杠,也不能在单引号之间引起单引号。

用双引号引起来的字符将保留所有引号内的字符的字面值,但$`\和除外,如果启用了历史记录扩展,则。字符$`在双引号中保留其特殊含义。反斜杠仅在其后跟随以下字符之一时才保留其特殊含义:$`“”\<newline>。在双引号中可以在反引号之前加上反斜杠。除非执行出现在双引号中的使用反斜杠进行转义。前面的反斜杠 未删除。

在双引号中,特殊参数*@具有特殊含义(请参见下面的参数)。

$' string '形式的单词会被特殊对待。该单词扩展为string,并按ANSI C标准的规定替换了反斜杠转义的字符。反斜杠转义序列(如果存在)的解码方式如下:

       \一个      警报(钟形)
        \ b      退格
        。\ E 
       。\ E      转义字符
        \˚F      形式进料
        \ n      新行
        \ r      回车
        \吨      水平制表
        符\ v      垂直制表
        \\      反斜杠
        \”      单引号
        \”      双引号
        \ NNN    的八位字符,其值为八进制值nnn
              (一到三位数)
       \ x HH    八位字符,其值为十六进制值HH
              (一个或两个十六进制数字)
       \ u HHHH Unicode(ISO / IEC 10646)字符,其值为
              十六进制值HHHH(一到四个十六进制数字)
        \ U HHHHHHHH
              Unicode(ISO / IEC 10646)字符,其值为
              十六进制值HHHHHHHH(1到8个十六进制数字)
        \ c x     a控件-x字符

扩展结果是单引号,好像没有美元符号。

用双引号引起来的字符串前面带有一个美元符号($“ string )将导致该字符串根据当前语言环境进行翻译。如果当前语言环境为CPOSIX,则忽略美元符号。如果字符串被翻译和替换,替换将被双引号引起来。


2

您可以\在特殊字符前面使用反斜杠()来使它们转义,如下所示:

john @ awesome:〜#回声\&
和

2

尽管它可能不可用作正则表达式,但某些字符序列可能会解释为Bash变量名称。为了防止这种情况发生并避免扩展它们,请使用单引号而不是双引号:

program '[abc]_[x|y]' anotherargument

分别用引号引起来(如果需要引号),因此它们被解释为独立的引数。在某些情况下,您还可以使用数组:

param_array=('[abc]_[x|y]' anotherargument)    # create an array
param_array+=(yetanother)     # append another element to the array
program "${param_array[@]}"   # use the array elements as arguments to program


0

转义它们应该可以正常工作:

  programm \[abc\]_\[x\|y\]

0

模式从何而来?是固定的还是来自用户的?是在本地系统上调用脚本的用户还是远程的某个人?

您可以使用引号将数据包装起来,以防止外壳解释它。有两种选择:

  1. 双引号,仍然可以进行一些解释($ expand和`backticks`)
  2. 单引号,将所有内容逐字传递

因为$在regexp(行尾/缓冲区)中是有效字符,所以除非您存储在变量中,否则您可能希望使用单引号将regexp保留。如果要从不受信任的人那里获取任意数据,则需要替换''"'"',然后用单引号引起来。

请注意,[abc]_[x|y]看起来您想要匹配xy,而实际上却匹配了三个字符之一xy|。方括号匹配-范围内的字符,仅用于范围,^否定开头的字符与a 匹配。因此,[abc]_(x|y)可能是您的意思,并且括号是Shell专用的字符。方括号不是外壳专用的,看起来就像是。双方括号[[ ... ]]是特殊的。


这是最正确的答案的一个在这里(我特别欣赏的指示更换''"'"'),但是,它仍然是不正确的。[这是Shell的特殊字符,在进行路径扩展时(在Shell中,所有未引用的内容都会用到通配符)使用通配符。
2011年

在某些情况下,这是很特殊的,例如变量下标或用于通配符,但是您仍然可以先键入foo=a[b]然后再echo $foo看到该字符串不需要引用。您说得对,我太简短了。
Phil P

如果您不走运,则ab当前目录中有一个文件,然后foo将包含ab而不是a[b]。引用方括号,人民。
clacke

(为清楚起见:我确实引用了(因为最初的答案很清楚,我一直在努力引用),这是我要解决的一个小问题。这个断言使我感到惊讶,因此我进行了测试。在zsh或bash中不是这样,而在BSD / bin / sh中是这样。这违反了POSIX,并且属于非标准行为,因此您需要引用它来处理它。在zsh中,您也可以setopt glob_assign启用此行为,因此引用是最安全的答案。
Phil P
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.