使用sed重命名文件,转义问题

时间:2013-10-29 19:21:38

标签: regex bash shell sed awk

我正在尝试编写一个bash脚本来删除空格,下划线和点,并用短划线替换它们。我也设置为小写并删除括号。这是(长)第二个sed命令,似乎有效。

第一个sed调用使用带有'\'的空格来转义原始名称,就像我选项卡完成时一样,这就是我认为的问题。

如果我用'echo'替换'mv -i',我会得到我想要的东西:原始文件名使用反斜杠转义,然后是新名称。如果我将它粘贴到终端它可以工作,但在脚本中使用mv空格会导致问题。逃避不起作用。

#!/bin/bash

for a in "$@"; do
    mv -i $(echo "$a" | sed -e 's/ /\\\ /g') $(echo "$a" | sed -e 's/\(.*\)/\L\1/' -e 's/_/-/g' -e 's/ /-/g' -e 's/---/--/g' -e 's/(//g' -e 's/)//g' -e 's/\[//g' -e 's/\]//g' -e 's/\./-/g' -e 's/-\([^-]*\)$/\.\1/')
done

另一种解决方案是在名称周围加上引号,但我无法弄清楚如何做到这一点。我觉得我已经接近了,但我很难过。

我也考虑过'重命名'命令,但你不能像sed那样做多个操作。

请指出任何其他问题,这是我的第一个脚本之一。我不确定我的“$ @”或“$ a”位完全正确。

干杯。

编辑:

示例输入文件名

I am a Badly [named] (file) - PLEASE.rename_me.JPG

应该成为

i-am-a-badly-named-file--please-rename-me.jpg 

edit2:我的解决方案,从gniourf_gniourf调整的真正有用的纯粹bash答案:

#!/bin/bash
for a in "$@"; do
    b=${a,,}                       #lowercase
    b=${b//[_[:space:]\.]/-}       #subst dot,space,underscore with dash
    b=${b//---/--}                 #remove triple dash
    b=${b//[()\[\]]/}              #remove brackets
    if [ "${b%-*}" != "$b" ]; then #if there is a dash (prevents filename.filename)
        b=${b%-*}.${b##*-}         #replace final dash with a dot for extension
    fi                           
    if [ "$a" != "$b" ]; then      #if there has been a change
        echo '--->' "$b"           #
        #mv -i -- "$a" "$b"        #rename
    fi
done

如果文件有空格等且没有扩展名(例如this BAD_filename变为this-bad.filename,这只会失败。但这些是媒体文件,应该有扩展名,所以无论如何我都要对它们进行排序。 / p>

同样,欢迎更正和改进。我是这个东西的新手

2 个答案:

答案 0 :(得分:4)

尝试使用rename执行此操作:

rename 's/[_\s\.]/-/g' *files
来自shell提示符的

。它非常有用,如果需要,您可以在其中放入一些代码。

当您的测试成为值时,您可以删除-n(干运行模式开关)。

warning http://pix.toile-libre.org/upload/original/1377510865.png 还有其他同名工具可能会或可能不会这样做,所以要小心。

如果您运行以下命令(linux

$ file $(readlink -f $(type -p rename))

你有一个像

的结果
.../rename: Perl script, ASCII text executable

然后这似乎是正确的工具=)

如果没有,请将其设为Debian上的默认值(通常已经是这种情况)和Ubuntu之类的衍生物:

$ sudo update-alternatives --set rename /path/to/rename

(将/path/to/rename替换为perl's rename命令的路径。


最后但并非最不重要的是,这个工具最初是由Perl的父亲Larry Wall编写的。

答案 1 :(得分:0)

只是为了记录,请看:

$ a='I am a Badly [named] (file) - PLEASE.rename_me.JPG'
$ # lowercase that
$ echo "${a,,}"
i am a badly [named] (file) - please.rename_me.jpg
$ # Cool! let's save that somewhere
$ b=${a,,}
$ # substitution 's/[_ ]/-/g:
$ echo "${b//[_ ]/-}"
i-am-a-badly-[named]-(file)---please.rename-me.jpg
$ # or better, yet:
$ echo "${b//[_[:space:]]/-}"
i-am-a-badly-[named]-(file)---please.rename-me.jpg
$ # Cool! let's save that somewhere
$ c=${b//[_[:space:]]/-}
$ # substitution 's/---/--/g' (??)
$ echo "${c//---/--}"
i-am-a-badly-[named]-(file)--please.rename-me.jpg
$ d=${c//---/--}
$ # substitution 's/()[]//g':
$ echo "${d//[()\[\]]/}"
i-am-a-badly-named-file--please.rename-me.jpg
$ e="${d//[()\[\]]/}"
$ # substitution 's/\./-/g':
$ echo "${e//\./-}"
i-am-a-badly-named-file--please-rename-me-jpg
$ f=${e//\./-}
$ # substitution 's/-\([^-]*\)$/\.\1/':
$ echo "${f%-*}.${f##*-}"
i-am-a-badly-named-file--please-rename-me.jpg
$ # Done!

现在,这是你想要实现的100%bash实现:

#!/bin/bash
for a in "$@"; do
    b=${a,,}
    b=${b//[_[:space:]]/-}
    b=${b//---/--}
    b=${b//[()\[\]]/}
    b=${b//\./-}
    b=${b%-*}.${b##*-}
    mv -i -- "$a" "$b"
done
是的,完成了!

所有这一标准,称为shell parameter expansion

备注。对于更强大的脚本,您可以检查a是否有扩展名(读取:名称中的句点),否则算法的最后一次替换会失败。为此,请将以下行放在for语句下面:

[[ a != *.* ]] && { echo "Oh no, file \`$a' has no extension..."; continue; }

(这条线的*.*部分不是很可爱吗?)