【问题标题】:Allowing punctuation characters in directory and file names in bash在bash中允许目录和文件名中的标点符号
【发布时间】:2024-01-10 08:33:01
【问题描述】:

我应该在 bash 脚本中使用哪些技术或原则来处理允许包含尽可能多的目录和文件名

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

还有空间?

我猜/ 在大多数 linux/unix 系统中不是有效的文件名或目录名字符? 到目前为止,我在文件名中遇到了!;|(空格字符)和' 的问题。

【问题讨论】:

标签: bash special-characters


【解决方案1】:

你是对的,/ 无效,空字节 \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 的选项(这意味着“数字行”)。

【讨论】:

    【解决方案2】:

    始终引用您的变量替换。 IE。不是cp $source $target,而是cp "$source" "$target"。这样他们就不会受到分词和路径名扩展的影响。

    在文件操作命令的位置参数之前指定“--”。 IE。不是cp "$source" "$target",而是cp -- "$source" "$target"。这可以防止将以破折号开头的文件名解释为选项。

    是的,“/”不是文件/目录名称的有效字符。

    【讨论】: