【问题标题】:Renaming files with sed, escaping issues使用 sed 重命名文件,转义问题
【发布时间】:2013-10-29 19:21:37
【问题描述】:

我正在尝试编写一个 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。但这些是媒体文件,应该有扩展名,所以无论如何我都必须对它们进行排序。

再次,欢迎更正和改进。我是这方面的新手

【问题讨论】:

  • 现在你有两个问题。
  • 我知道,需要详细说明吗?
  • 没有。看看我的回答,你会看到如何以一种好的和理智的方式实现你的算法。
  • 谢谢! (当我回复时,您的答案不存在)。我仍然不确定为什么我有两个问题。
  • mv -i -- "$a" $(echo "$a" | sed .... 似乎可以在没有转义的情况下工作,也许我读了很多关于这个的内容,以至于我没有尝试明显的内容。

标签: regex bash shell sed awk


【解决方案1】:

尝试使用rename 执行此操作:

rename 's/[_\s\.]/-/g' *files

来自shell 提示。非常好用,需要的话可以在里面放一些代码。

当您的测试有效时,您可以移除-n(试运行模式开关)。

还有其他同名的工具可能会也可能不会,所以要小心。

如果您运行以下命令 (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 编写的。

【讨论】:

  • 谢谢。正如我所说的重命名问题(并且我有 Perl 版本)是我无法像使用 sed 那样进行多次替换。您的第一个示例完成了一些事情,但是我需要将最后的“-”作为文件扩展名的点放回去,并进行小写操作、括号和方括号并删除出现的“---”从' - '
  • 完成,抱歉遗漏。 sed 表达式表明了这一点,但我不应该期望任何人解码它们。
  • 我需要保存那个停车标志。
【解决方案2】:

只是为了记录,看:

$ 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; }

(这行的*.* 部分是不是很可爱?)

【讨论】:

  • 太棒了。你给了我一个全新的(更好的)方法。移动命令中的“--”是什么意思。它不在 man 文件中。
  • -- 表示选项结束。以防文件以连字符开头,它会混淆mv 试图将其解释为一个选项。如果您的mv 版本支持它,请使用它!它会让你的脚本更加健壮。
  • 它似乎也将扩展名放在文件名的开头,因此需要交换两位。
  • @lipidicman 哦,我打错了最后一个替换语句……现在已经修复了,对此感到抱歉。
  • 别抱歉,解决方案正是我所需要的。现在我仍然有点困惑,如果我把 echo 放在 mv 命令前面,我会看到文件名没有转义。使用mv(不是echo mv)时“”够不够,为什么我原来的stab在这方面失败了?
猜你喜欢
  • 2011-01-23
  • 2011-08-06
  • 2013-06-12
  • 2021-06-04
  • 2019-01-09
  • 2021-06-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多