bash在目录和文件名中允许标点符号 [英] Allowing punctuation characters in directory and file names in bash

查看:204
本文介绍了bash在目录和文件名中允许标点符号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

还有空格?

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

解决方案

是的,/无效,空字节\0也是无效的.没有这种限制(除了文件系统黑客攻击之外).

所有其他字符都可以在文件名中使用,包括诸如换行符\n或制表符\t之类的令人惊讶的字符.有很多输入方法,以使外壳程序无法将它们理解为特殊字符.我只会提供一种实用的方法.

您可以使用单引号'来引用大多数 printable 字符:

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,这不会被理解为为cat赋予的选项-n(这意味着数字行").

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.

解决方案

You are right, / is not valid, as is the null-byte \0. There is no way around that limitation (besides file system hacking).

All other characters can be used in file names, including such surprising characters as a newline \n or a tab \t. There are many ways to enter them so that the shell does not understand them as special characters. I will give just a pragmatic approach.

You can enter most of the printable characters by using the singlequote ' to to quote them:

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

Of course, you cannot enter a singlequote this way, but for this you can use the doublequote ":

date > "foo'bar"

If you need to have both, you can end one quotation and start another:

date > "foo'bar"'"bloh'

Alternatively you also can use the backslash \ to escape the special character directly:

date > foo\"bar

The backslash also works as an escaper withing doublequotes, it does not work that way within singlequotes (there it is a simple character without special meaning).

If you need to enter non-printable characters like a newline, you can use the dollar-singlequote notation:

date > $'foo\nbar'

This is valid in bash, but not necessarily in all other shells. So take care!

Finally, it can make sense to use a variable to keep your strange name (in order not to have to spell it out directly:

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

This way you can keep the shell code readable.

BUT in general it is not a good idea to have such characters in file names because a lot of scripts cannot handle such files properly.

To write scripts fool-proof is not easy. The most basic rule is the quote variable usage in doublequotes:

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

This will solve 99% of the issues you are likely to encounter.

If you are using find to find directory entries which can contain special characters, you should use printf0 to separate the output not by spaces but by null-bytes. Other programs like xargs often can understand a list of null-byte separated file names.

If your file name can start with a dash - it often can be mistaken as an option. Some programs allow giving the special option -- to state that all following arguments are no options. The more general approach is to use a name which does not start with a dash:

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

This way, a file named -n will not run cat -n but cat ./-n which will not be understood as the option -n given to cat (which would mean "number lines").

这篇关于bash在目录和文件名中允许标点符号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆