我在我的小公司里做 IT 工作;尽管我发出了严厉的警告,但每个人都在服务器上放置了名称可怕的文件,包括前导和尾随空格、坏字符(包括\ ; / + . < > -
等等!)
他们通过 Mac 上的 AFP 访问(FreeBSD/FreeNAS)服务器来实现这一点,因此系统的任何部分都不会抱怨。
是否有一个脚本可以用来遍历整个目录树并修复错误的文件名?
基本上用 ... 替换所有空格和错误的 ASCII _
,如果文件已经存在,则只需_2
在末尾加上 a 或其他内容。
我不认为有办法让系统执行有好的文件命名约定吗?
谢谢!
答案1
我会使用 bash 和 find。我确信有更简单的选择,但以下是我想到的方法:
这可以处理包含“/”的文件名(find 会给出警告,忽略它),但是它只对当前目录中的文件起作用(无子目录)。我无法弄清楚如何告诉 bash 或 find 区分文件名中的“/”和路径中的“/”。
for i in $(find . -maxdepth 1 -type f -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" | sed 's/\.\///'); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}; done
这个不能处理包含“/”的文件名,但它将对当前目录中的所有文件起作用及其子目录:
for i in $(find . -type f -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%]/_}; done
确保运行前测试这些。在我进行的几次测试中,它们运行良好,但我并没有进行彻底的测试。另外请记住,我使用的是 Linux 系统。find 和 bash 的具体实现可能与您的不同。
编辑:将mv $i
命令更改为“mv -i $i”将导致 mv 在覆盖现有文件之前提示您。
EDIT2:要处理带有空格的文件名,您可以像这样更改 bash IFS(输入字段分隔符)变量(改编自这里):
SAVEIFS=$IFS; IFS=$(echo -en "\n\b"); for i in $(find . -type f -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%\ ]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%\ ]/_}; done; IFS=$SAVEIFS
我还修改了正则表达式以匹配/替换下划线中的空格。SAVEIFS 位只是将 IFS 变量恢复为其原始配置。
解释:
for i in $(command); do something $i; done
这是一个通用的 bash 循环。它将遍历命令的输出,按顺序将变量 $i 设置为命令返回的每个值,并对其执行某些操作。
find . -maxdepth 1 -type f -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" '
查找当前目录中名称包含以下字符之一的所有文件::;><@$#&()\/%
。要添加更多文件,只需使用“\”(例如“\¿”)对其进行转义,然后将其添加到括号([ ])内的列表中。可能并非所有这些字符都需要转义,但我永远记不住哪些是哪个环境中的特殊变量,所以我会转义所有内容,以防万一。
sed 's/\.\///
从 find 的输出中删除当前目录,打印“foo”而不是“./foo”。
mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}
每次这个小脚本循环时,$i 都会变成一个错误命名的文件的名称。此命令将移动(重命名)该文件,将所有不需要的字符更改为“_”。查找 bash 替换以获取更多信息。