如何在Bash中转义任意字符串以用作命令行参数?

qnt*_*ntm 31 bash perl

我有一个字符串列表,我想在单个Bash命令行调用中将这些字符串作为参数传递.对于简单的字母数字字符串,只需逐字传递即可:

> script.pl foo bar baz yes no
foo
bar
baz
yes
no
Run Code Online (Sandbox Code Playgroud)

我理解如果一个参数包含空格或反斜杠或双引号,我需要反斜杠 - 转义双引号和反斜杠,然后双引号参数.

> script.pl foo bar baz "\"yes\"\\\"no\""
foo
bar
baz
"yes"\"no"
Run Code Online (Sandbox Code Playgroud)

但是当参数包含感叹号时,会发生以下情况:

> script.pl !foo
-bash: !foo: event not found
Run Code Online (Sandbox Code Playgroud)

双引号不起作用:

> script.pl "!foo"
-bash: !foo: event not found
Run Code Online (Sandbox Code Playgroud)

反斜杠也不会逃避(注意输出中的字面反斜杠如何):

> script.pl "\!foo"
\!foo
Run Code Online (Sandbox Code Playgroud)

我对Bash了解不多,但我知道还有其他特殊字符可以做类似的事情.在Bash中安全地转义任意字符串以用作命令行参数的一般过程是什么?假设字符串可以是任意长度并包含特殊字符的任意组合.我想要一个escape()子程序,我可以使用如下(Perl示例):

$cmd = join " ", map { escape($_); } @args;
Run Code Online (Sandbox Code Playgroud)

下面是一些应该通过此函数安全转义的示例字符串(我知道其中一些看起来像Windows,这是故意的):

yes
no
Hello, world      [string with a comma and space in it]
C:\Program Files\ [path with backslashes and a space in it]
"                 [i.e. a double-quote]
\                 [backslash]
\\                [two backslashes]
\\\               [three backslashes]
\\\\              [four backslashes]
\\\\\             [five backslashes]
"\                [double-quote, backslash]
"\T               [double-quote, backslash, T]
"\\T              [double-quote, backslash, backslash, T]
!1                
!A                
"!\/'"            [double-quote, exclamation, backslash, forward slash, apostrophe, double quote]
"Jeff's!"         [double-quote, J, e, f, f, apostrophe, s, exclamation, double quote]
$PATH             
%PATH%            
&                 
<>|&^             
*@$$A$@#?-_       
Run Code Online (Sandbox Code Playgroud)

编辑:

这会诀窍吗?使用反斜杠逃避每个不寻常的角色,并省略单引号或双引号.(例子是在Perl中,但任何语言都可以这样做)

sub escape {
    $_[0] =~ s/([^a-zA-Z0-9_])/\\$1/g;
    return $_[0];
}
Run Code Online (Sandbox Code Playgroud)

l0b*_*0b0 19

如果你想为Bash 安全地引用任何内容,你可以使用它的内置printf %q格式:

cat strings.txt:

yes
no
Hello, world
C:\Program Files\
"
\
\\
\\\
\\\\
\\\\\
"\
"\T
"\\T
!1
!A
"!\/'"
"Jeff's!"
$PATH
%PATH%
&
<>|&^
*@$$A$@#?-_
Run Code Online (Sandbox Code Playgroud)

cat quote.sh:

#!/bin/bash
while IFS= read -r -d $'\n'
do
    printf %q "$REPLY"
    printf '\n'
done < strings.txt
Run Code Online (Sandbox Code Playgroud)

./quote.sh:

yes
no
Hello\,\ world
C:\\Program\ Files\\
\"
\\
\\\\
\\\\\\
\\\\\\\\
\\\\\\\\\\
\"\\
\"\\T
\"\\\\T
\!1
\!A
\"\!\\/\'\"
\"Jeff\'s\!\"
\$PATH
%PATH%
\&
\<\>\|\&\^
\*@\$\$A\$@#\?-_
Run Code Online (Sandbox Code Playgroud)

可以逐字复制这些字符串,例如echo在strings.txt中输出原始字符串.

  • 如果该字符串已经单一转义,则它将在双重转义的命令行中打印,然后在单个转义的程序中可用.换句话说,程序中可用的字符串将完全是原始(单一转义)字符串,这正是我想要的. (2认同)

Tan*_*ett 11

在Bash中安全地转义任意字符串以用作命令行参数的一般过程是什么?

更换的每次出现''\'',然后把'在开头和结尾.

除单引号外的每个字符都可以在单引号分隔的字符串中逐字使用.没有办法在单引号分隔的字符串中放入单引号,但这很容易解决:结束字符串('),然后使用反斜杠添加单引号以逃避它(\'),然后开始一个新的string(').

据我所知,这将永远有效,没有例外.


Ben*_*oit 0

Bash 仅在交互模式下解释感叹号。

您可以通过执行以下操作来防止这种情况:

set +o histexpand
Run Code Online (Sandbox Code Playgroud)

在双引号内,您必须转义美元符号、双引号、反斜杠,我想说仅此而已。