1

What techniques or principles should I use in a bash script to handle directories and filenames that are allowed to contain as many as possible of

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

and space?

I guess / is not a valid filename or directory name character in most linux/unix systems? So far I have had problems with !, ;, |, (a space character) and ' in filenames.

4

2 回答 2

3

您是对的,/无效, null-byte 也是如此\0。没有办法绕过这个限制(除了文件系统黑客)。

所有其他字符都可以在文件名中使用,包括换行符\n或制表符等令人惊讶的字符\t。输入它们的方法有很多,因此 shell 不会将它们理解为特殊字符。我只会给出一个务实的方法。

您可以通过使用单引号来引用它们来输入大多数可打印字符:'

date > 'foo!bar["#$%&()*+,-.:;<=>?@[\]^_`{|}~'

当然,您不能以这种方式输入单引号,但为此您可以使用双引号"

date > "foo'bar"

如果你需要两者,你可以结束一个报价并开始另一个:

date > "foo'bar"'"bloh'

或者,您也可以使用反斜杠\直接转义特殊字符:

date > foo\"bar

反斜杠也可以用作带有双引号的转义符,它在单引号中不起作用(它是一个没有特殊含义的简单字符)。

如果需要输入换行符等不可打印字符,可以使用美元单引号表示法:

date > $'foo\nbar'

这在 bash 中有效,但不一定在所有其他 shell 中。所以保重!

最后,使用变量来保留你的奇怪名字是有意义的(为了不必直接拼写出来:

strangeName=$(xxd -r <<< "00 41 42 43 ff 45 46")
date > "$strangeName"

这样你就可以保持 shell 代码的可读性。

总的来说,在文件名中包含此类字符并不是一个好主意,因为许多脚本无法正确处理此类文件。

编写脚本万无一失并非易事。最基本的规则是双引号中的引号变量用法:

for i in *
do
    cat "$i" | wc -l
done

这将解决您可能遇到的 99% 的问题。

如果您find用于查找可以包含特殊字符的目录条目,则应使用printf0空字节而不是空格来分隔输出。其他程序xargs通常可以理解空字节分隔的文件名列表。

如果您的文件名可以以破折号开头,-则通常会被误认为是一个选项。一些程序允许给出特殊选项--来声明所有以下参数都是没有选项的。更通用的方法是使用不以破折号开头的名称:

for i in *
do
    cat ./"$i" | wc -l
done

这样,一个名为的文件-n将不会运行cat -n,但cat ./-n不会被理解为-n给定的选项cat(这意味着“数字行”)。

于 2013-06-17T09:13:34.633 回答
0

Always quote your variable substitutions. I.e. not cp $source $target, but cp "$source" "$target". This way they won't be subject to word splitting and pathname expansion.

Specify "--" before positional arguments to file operation commands. I.e. not cp "$source" "$target", but cp -- "$source" "$target". This prevents interpreting file names starting with dash as options.

And yes, "/" is not a valid character for file/directory names.

于 2013-06-17T09:09:55.353 回答