无效字符串:Bash必须使用从U+0000到U+001F的控制字符进行转义。

14 浏览
0 Comments

无效字符串:Bash必须使用从U+0000到U+001F的控制字符进行转义。

在shell脚本中,我是否应该在变量周围加引号?

例如,以下是否正确:

xdg-open $URL
[ $? -eq 2 ]

还是

xdg-open "$URL"
[ "$?" -eq "2" ]

如果是,为什么?

admin 更改状态以发布 2023年5月23日
0
0 Comments

简而言之,在您不需要shell执行单词拆分和通配符扩展的情况下,请引用所有内容。

单引号会逐字保护它们之间的文本。 当您需要确保shell完全不触及字符串时,它是正确的工具。 通常,当您不需要变量插值时,它是首选的引用机制。

$ echo 'Nothing \t in here $will change'
Nothing \t in here $will change
$ grep -F '@&$*!!' file /dev/null
file:I can't get this @&$*!! quoting right.

双引号适用于需要变量插值的情况。通过适当的调整,当您需要字符串中的单引号时,它也是一个不错的解决方法。 (在单引号中无法直接转义单引号,因为单引号内部没有转义机制 - 如果有,它们就不会完全引用逐字。)

$ echo "There is no place like '$HOME'"
There is no place like '/home/me'

当您明确需要shell执行单词拆分和/或通配符扩展时,不要使用引号。

单词拆分(也称为令牌拆分);

 $ words="foo bar baz"
 $ for word in $words; do
 >   echo "$word"
 > done
 foo
 bar
 baz

相比之下:

 $ for word in "$words"; do echo "$word"; done
 foo bar baz

(循环仅运行一次,针对单个引用字符串。)

 $ for word in '$words'; do echo "$word"; done
 $words

(循环仅运行一次,针对逐字单引号字符串。)

通配符扩展:

$ pattern='file*.txt'
$ ls $pattern
file1.txt      file_other.txt

相比之下:

$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory

(不存在命名为 file*.txt 的文件。)

$ ls '$pattern'
ls: cannot access $pattern: No such file or directory

(也不存在名为 $pattern 的文件!)

更具体地说,任何包含文件名的内容通常都应该加引号(因为文件名可能包含空格和其他shell元字符)。 任何包含URL的内容通常都应该加引号(因为许多URL包含像?&这样的shell元字符)。 任何包含正则表达式的内容通常都需要加引号(同上)。 需要引用任何包含重要空格(即非空格字符之间的单个空格以外的任何空格)的内容,否则shell将将空格混合成实质上的单个空格,并修剪任何前导或尾随的空格。

当您知道变量只能包含不包含shell元字符的值时,引用是可选的。 因此,未引用的$?基本上没有问题,因为该变量只能包含一个数字。 但是,"$?"也是正确的,并且出于一般性和正确性的考虑建议使用它(尽管这是我的个人建议,而不是广泛认可的政策)。

不是变量的值基本上遵循相同的规则,尽管您还可以转义任何元字符而不是将其引用。 例如,具有&的URL​​将被shell解析为后台命令,除非转义或引用元字符:

$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found

(当然,如果URL在未被引用的变量中,也会发生这种情况。)对于静态字符串,单引号是最合适的选择,尽管任何引用或转义形式都适用。

wget 'http://example.com/q&uack'  # Single quotes preferred for a static string
wget "http://example.com/q&uack"  # Double quotes work here, too (no $ or ` in the value)
wget http://example.com/q\&uack   # Backslash escape
wget http://example.com/q'&'uack  # Only the metacharacter really needs quoting

最后一个例子还提出了另一个有用的概念,我喜欢称之为“蹦蹦床引用”。如果你需要混合使用单引号和双引号,你可以将它们相邻使用。例如,以下引用字符串

'$HOME '
"isn't"
' where `<3'
"' is."

可以一个接一个地组合在一起,在分词和引用删除后形成一个单独的长字符串。

$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.

虽然这不是特别易读,但它是一种常见的技巧,因此值得知道。

顺便提一下,脚本通常不应将ls用于任何事情。为了扩展通配符,只需...使用它即可。

$ printf '%s\n' $pattern   # not ``ls -1 $pattern''
file1.txt
file_other.txt
$ for file in $pattern; do  # definitely, definitely not ``for file in $(ls $pattern)''
>  printf 'Found file: %s\n' "$file"
> done
Found file: file1.txt
Found file: file_other.txt

(在后面的示例中,循环完全是多余的;printf可以很好地处理多个参数。 stat也是如此。但循环遍历通配符匹配是一个常见问题,经常出错。)

包含要循环遍历的令牌列表或要扩展的通配符的变量不太常见,因此我们有时会缩写为“除非你确切知道你在做什么,否则引用一切”。

0
0 Comments

通用准则:如果字符串可能为空或包含空格(或任何空白字符)或特殊字符(通配符),则需要引用它。不引用带有空格的字符串通常会导致shell将单个参数拆分为多个参数。 \n$? 不需要引用,因为它是一个数字值。是否需要对$URL进行引用取决于其中允许什么,并且是否仍希望有一个参数(即使它为空)。\n我经常习惯性地对字符串进行引用,因为这样更安全。

0