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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6306386/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 20:37:34  来源:igfitidea点击:

How can I escape an arbitrary string for use as a command line argument in Bash?

perlbash

提问by qntm

I have a list of strings and I want to pass those strings as arguments in a single Bash command line call. For simple alphanumeric strings it suffices to just pass them verbatim:

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

> script.pl foo bar baz yes no
foo
bar
baz
yes
no

I understand that if an argument contains spaces or backslashes or double-quotes, I need to backslash-escape the double-quotes and backslashes, and then double-quote the argument.

我知道如果一个参数包含空格或反斜杠或双引号,我需要反斜杠转义双引号和反斜杠,然后双引号参数。

> script.pl foo bar baz "\"yes\"\\"no\""
foo
bar
baz
"yes"\"no"

But when an argument contains an exclamation mark, this happens:

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

> script.pl !foo
-bash: !foo: event not found

Double quoting doesn't work:

双引号不起作用:

> script.pl "!foo"
-bash: !foo: event not found

Nor does backslash-escaping (notice how the literal backslash is present in the output):

也没有反斜杠转义(注意输出中的文字反斜杠是如何存在的):

> script.pl "\!foo"
\!foo

I don't know much about Bash yet but I know that there are other special characters which do similar things. What is the general procedure for safely escaping an arbitrary string for use as a command line argument in Bash?Let's assume the string can be of arbitrary length and contain arbitrary combinations of special characters. I would like an escape()subroutine that I can use as below (Perl example):

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

$cmd = join " ", map { escape($_); } @args;

Here are some more example strings which should be safely escaped by this function (I know some of these look Windows-like, that's deliberate):

下面是一些应该由这个函数安全转义的示例字符串(我知道其中一些看起来像 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$@#?-_       

EDIT:

编辑:

Would this do the trick? Escape every unusual character with a backslash, and omit single or double quotes. (Example is in Perl but any language can do this)

这能解决问题吗?用反斜杠转义每个不寻常的字符,并省略单引号或双引号。(示例在 Perl 中,但任何语言都可以执行此操作)

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

回答by l0b0

If you want to securely quote anythingfor Bash, you can use its built-in printf %qformatting:

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

cat strings.txt:

cat strings.txt

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

cat quote.sh:

cat quote.sh

#!/bin/bash
while IFS= read -r -d $'\n'
do
    printf %q "$REPLY"
    printf '\n'
done < strings.txt

./quote.sh:

./quote.sh

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

These strings can be copied verbatim to for example echoto output the original strings in strings.txt.

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

回答by Tanner Swett

What is the general procedure for safely escaping an arbitrary string for use as a command line argument in Bash?

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

Replace every occurrence of 'with '\'', then put 'at the beginning and end.

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

Every character except for a single quote can be used verbatim in a single-quote-delimited string. There's no way to put a single quote inside a single-quote-delimited string, but that's easy enough to work around: end the string ('), then add a single quote by using a backslash to escape it (\'), then begin a new string (').

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

As far as I know, this will always work, with no exceptions.

据我所知,这将始终有效,没有例外。

回答by jjmontes

You can use single quotes to escape strings for Bash. Note however this does not expand variables within quotes as double quotes do. In your example, the following should work:

您可以使用单引号为 Bash 转义字符串。但是请注意,这不会像双引号那样扩展引号内的变量。在您的示例中,以下内容应该有效:

script.pl '!foo'

From Perl, this depends on the function you are using to spawn the external process. For example, if you use the systemfunction, you can pass arguments as parameters so there"s no need to escape them. Of course you"d still need to escape quotes for Perl:

在 Perl 中,这取决于您用来生成外部进程的函数。例如,如果您使用该system函数,您可以将参数作为参数传递,因此无需转义它们。当然,您仍然需要为 Perl 转义引号:

system("/usr/bin/rm", "-fr", "/tmp/CGI_test", "/var/tmp/CGI");

回答by ikegami

sub text_to_shell_lit(_) {
   return $_[0] if $_[0] =~ /^[a-zA-Z0-9_\-]+\z/;
   my $s = $_[0];
   $s =~ s/'/'\''/g;
   return "'$s'";
}

See this earlier postfor an example.

有关示例,请参阅这篇较早的帖子

回答by Habib Karbasian

Whenever you see you don't get the desired output, use the following method:

每当您看到没有获得所需的输出时,请使用以下方法:

"""\special character"""

"""\special character"""

where special charactermay include ! " * ^ % $ # @....

其中特殊字符可能包括! " * ^ % $ # @....

For instance, if you want to create a bash generating another bash file in which there is a string and you want to assign a value to that, you can have the following sample scenario:

例如,如果您想创建一个 bash 生成另一个 bash 文件,其中有一个字符串,并且您想为其分配一个值,您可以使用以下示例场景:

Area="(1250,600),(1400,750)"
printf "SubArea="""\""""${Area}"""\""""\n" > test.sh
printf "echo """$"""{SubArea}" >> test.sh

Then test.shfile will have the following code:

然后test.sh文件将具有以下代码:

SubArea="(1250,600),(1400,750)"
echo ${SubArea}

As a reminder to have newline \n, we should use printf.

作为换行的提醒\n,我们应该使用printf.

回答by micans

This is not a complete answer, but I find it useful sometimes to combine two types of quote for a single string by concatenating them, for example echo "$HOME"'/foo!?.*'.

这不是一个完整的答案,但我发现有时通过连接它们来组合单个字符串的两种类型的引号很有用,例如echo "$HOME"'/foo!?.*'

回答by Benoit

Bash interprets exclamation marks only in interactive mode.

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

You can prevent this by doing:

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

set +o histexpand

Inside double quotes you must escape dollar signs, double quotes, backslashes and I would say that's all.

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