我的意思是摆脱文件名中的特殊字符等。
我制作了一个脚本,可以递归重命名文件[http://pastebin.com/raw.php?i=kXeHbDQw]:
例如:之前:
THIS i.s my file (1).txt
运行脚本后:
This-i-s-my-file-1.txt
确定。这是:
但是:当我想“完全”测试它时,文件名如下:
¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÂÃÄÅÆÇÈÊËÌÎÏÐÑÒÔÕ×ØÙUÛUÝÞßàâãäåæçèêëìîïðñòôõ÷øùûýþÿ.txt
áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&'()*+,:;<=>?@[\]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£.txt
它失败[http://pastebin.com/raw.php?i=iu8Pwrnr]:
$ sh renamer.sh directorythathasthefiles
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†....and so on
$
所以“mv”无法处理特殊字符..:\
我工作了好几个小时..
有人有工作吗? [也可以处理2行中的字符[文件名]?]
答案 0 :(得分:18)
mv
处理特殊字符就好了。你的剧本没有。
没有特别的顺序:
您正在使用find
分别查找所有目录和ls
每个目录。
为什么使用for DEPTH in...
如果 命令完全
find -maxdepth 100 -type d
这使得不需要任意深度限制
find -type d
永远解析ls
,尤其是的输出,如果你也可以find
处理1> p>
find -not -type d
确保它在最糟糕的情况下有效:
find -not -type d -print0 | while read -r -d '' FILENAME; do
这会阻止read
吃掉某些转义符并使用换行符阻塞文件名。
您正在为每个字符重复整个 ls | replace
周期。 不要 - 它会影响性能。遍历每个目录所有文件一次,并在一个sed
命令中使用多个sed
或多个替换。
sed 's/á/a/g; s/í/i/g; ...'
(我打算建议sed 'y/áí/ai/'
,但不幸的是,这似乎不适用于Unicode。也许perl -CS -Mutf8 -pe 'y/áí/ai/'
会。)
您仍在考虑ASCII:“其他特殊字符 - ASCII代码33 .. .255”。不。
目前,大多数系统都使用UTF-8编码的Unicode,它具有多范围更广的“特殊”字符 - 如此之大以至于逐个列出它们变得毫无意义。 (甚至多字节 - “e”是一个字节,“ė”是三个字节。)
True ASCII有128个字符。您目前的想法是ISO 8859字符集(有时称为“ANSI”) - 特别是ISO 8859-1。但它们一直到8859-16,只有“ASCII”部分保持不变。
echo -n $(command)
毫无用处。
在给定路径的情况下,有更简单的方法可以找到目录和基本名称。例如,你可以做
directory=$(dirname "$path")
oldnname=$(basename "$path")
# filter $oldname
mv "$path" "$directory/$newname"
不使用egrep
检查错误。检查程序的返回代码。 (就像你已经使用cd
一样。)
而不是过滤掉其他错误,请执行...
if [[ -e $directory/$newname ]]; then
echo "target already exists, skipping: $oldname -> $newname"
continue
else
mv "$path" "$directory/$newname"
fi
可以将sed 's/------------/-/g'
次调用更改为单个正则表达式:
sed -r 's/-{2,}/-/g'
[ ]
中的tr [foo] [bar]
是不必要的。他们只需tr
将[
替换为[
,将]
替换为]
。
真的?
echo "$FOLDERNAME" | sed "s/$/\//g"
相反怎么样?
echo "$FOLDERNAME/"
最后,使用detox
。
答案 1 :(得分:6)
尝试类似:
find . -print0 -type f | awk 'BEGIN {RS="\x00"} { printf "%s\x00", $0; gsub("[^[:alnum:]]", "-"); printf "%s\0", $0 }' | xargs -0 -L 2 mv
使用xargs(1)将确保每个文件名完全作为一个参数传递。 awk(1)用于在旧文件名之后添加新文件名。
还有一个技巧:sed -e's / - + / - / g'将只用一个“ - ”代替一组“ - ”。
答案 2 :(得分:4)
假设您的其他脚本是正确的,那么您的问题是您使用的是read
,但您应该使用read -r
。注意反斜杠是如何消失的:
áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&'()*+,:;<=>?@[\]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£.txt
áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£
答案 3 :(得分:1)
啊...
清理脚本的一些提示:
**使用sed一次对多个字符进行翻译,这样可以清理并简化管理:
dev:~$ echo 'áàaieeé!.txt' | sed -e 's/[áàã]/a/g; s/[éè]/e/g'
aaaieee!.txt
**而不是重命名每次更改的文件,运行所有过滤器,然后执行一次移动
$ NEWNAME='áàaieeé!.txt'
$ NEWNAME="$(echo "$NEWNAME" | sed -e 's/[áàã]/a/g; s/[éè]/e/g')"
$ NEWNAME="$(echo "$NEWNAME" | sed -e 's/aa*/a/g')"
$ echo $NEWNAME
aieee!.txt
**而不是进行ls | read ...
循环,请使用:
for OLDNAME in $DIR/*; do
blah
blah
blah
done
**分离出你的路径遍历并将逻辑重命名为两个脚本。一个脚本找到需要重命名的文件,一个脚本处理单个文件的规范化。一旦你学会了'find'命令,你就会发现你可以抛出第一个脚本:)