bash查找执行程序:重命名文件并保留可选扩展名?

时间:2019-01-11 13:48:01

标签: bash batch-rename

我想查找所有与模式匹配的文件,并将字符串附加到前缀,并保留扩展名(如果存在)。有些文件带有扩展名,而其他文件则没有。

所需的转换:

tools-win/foo.exe => tools-win/foo_bar.exe
tools-osx/foo     => tools-osx/foo_bar

是否有一种方法可以使用bash参数表达式?我目前的尝试是:

find . -path 'tools-*/*' \
    -execdir sh -c 'mv "$1" "${1%.*}_$2.${1##.}"' _ {} bar \;`

这适用于具有扩展名的文件,但会捕获不具有扩展名的文件的整个前缀:

tools-win/foo.exe => tools-win/foo_bar.exe
tools-osx/foo     => tools-osx/foo_bar.foo

在这里可以使用单个参数表达式来处理这两种情况吗?

3 个答案:

答案 0 :(得分:1)

第一次简化:

格式化:

find | 
  while read -r f
  do case $f in
     *.???) echo mv "$f" "${f%.???}_bar${f##${f%.???}}" ;;
         *) echo mv "$f" "${f}_bar"                     ;;
     esac
  done

神奇的混乱是"${f%.???}_bar${f##${f%.???}}"-
${f%.???}是不带扩展名的文件名。 ${f##${f%.???}}是一个简单定义的扩展名,用于从文件开头删除所有 else ,因此它 是上述(复杂派生的)前面提到的“简单定义”延期”。 :)

除了find之外,这不应该创建任何子外壳,因此它应该非常有效。


注意脚本

重大缺陷在于.???,当它遇到文件名x.v1.2.3并将其重命名为x.v1_bar.2.3时,可能不会做您想要的事情。这可能是固定的,但是在没有看到您的数据的情况下,我不想对它进行详细说明。


仍然可以压缩到一行-

  find | while read -r f; do case $f in *.???) echo mv "$f" "${f%.???}_bar${f##${f%.???}}" ;; *) echo mv "$f" "${f}_bar";; esac; done

我积极避免尝试将所有应用于查找。我建议将整个内容通过管道传输到文件中,并在执行前扫描疯狂性。如果一切正常,或者只有很少的例外,您可以手动编辑它们,然后就可以执行文件。

答案 1 :(得分:1)

您可以使用rename(也称为Perl rename)非常简单地进行操作。它会在不同的程序包管理器/操作系统中以不同的名称伪装。

它具有一个-X开关,该开关删除扩展名,然后再将其添加回去;还有一个-a开关,允许您将字符串作为后缀添加到当前名称。因此,要在扩展名之前的文件名的基础部分中添加_bar,请在所有PNG文件上使用:

rename -X -a "_bar" *.png

它可以做一百万件事:

  • 添加--dry-run来查看在不实际执行任何操作的情况下,这很漂亮
  • 使用$N将顺序计数器引入文件名
  • 当两项更改导致文件被覆盖时,它会自动检测到冲突,并在对您造成任何损害之前警告您-这是非常宝贵的
  • 您可以将整个Perl脚本传递给它,以您能想到的最复杂的方式处理文件名

您可以测试您的rename是否是我所指的Perl:

file $(which rename)

,如果正确,您将看到它是Perl可执行文件。如果您找到适合您的操作系统的软件包,也许您会在此答案中添加注释,说明您安装了哪个软件包来获取它。


在macOS上,您可以安装自制软件所指的rename工具,如下所示:

brew install rename 

答案 2 :(得分:0)

内部shell脚本可以通过以下方式来解析前缀:删除所有包含最后.及其后的内容,然后通过将前缀从原始字符串中删除而删除后缀。最终的字符串可以使用标准串联进行组装:

PREFIX=${1%.*}
SUFFIX=${1##"${PREFIX}"}
FINAL=${PREFIX}_bar${SUFFIX}

请注意,如果${PREFIX}与输入字符串相同,则${SUFFIX}将为空。

因此,虽然它不是sh中的单行代码,但是调用只调用一次find -exec而没有管道的调用看起来像这样:

find "${PATH_TO_SEARCH}" -path "${PATH_TO_SEARCH}/tools-*/*" \
    -execdir sh -c 'p=${1%.*};s=${1##"${p}"};mv "$1" "${p}_$2${s}"' sh {} bar \;`