在 sh 中递归重命名文件

在 sh 中递归重命名文件

我使用 Synology 作为闭路电视摄像机影片的存储。将文件从 CCTV 系统复制到 Synology 后,我将其转换为 AVI 格式。所以我的文件的名称如下:

10.01.07-10.01.48[M][@0][0].dav.avi

我想从上面的名称递归地重命名它,如下所示:

10.01.07-10.01.48.avi 

请注意,每个文件名始终包含相同的部分[M][@0][0].dav.avi

rename但问题是Synology shell 中没有命令(sh不是bash

我尝试find以许多不同的语法使用命令,但没有成功。你能帮我找到解决方案吗?

答案1

你可以这样做:

find . -name '*\[M]\[@0]\[0].dav.avi' -type f -exec sh -c '
  for file do
    echo mv "$file" "${file%"[M][@0][0].dav.avi"}.avi"
  done' sh {} +

echo如果看起来没问题,请删除)。

或者,如果您想将所有.dav.avi重命名为.avi,但还要删除[M][@0][0]if :

find . -name '*.dav.avi' -type f -exec sh -c '
  for file do
    new=${file%.*.*}
    new=${new%"[M][@0][0]"}.avi
    echo mv "$file" "$new"
  done' sh +

这些是 POSIX 语法,也可以与 busybox 实用程序一起使用,因此应该可以在 Synology 上使用。

一些注释(基于您自己和其他答案的观察):

  • 传递给的模式find -name必须加引号,否则它可能会被 shell 扩展。
  • xargs除非您能保证这些文件名不包含空格、换行符、引号或反斜杠,否则不能在文件名上使用。
  • 使用printf代替echo输出任意数据
  • 在列表上下文中保留未加引号的变量扩展具有非常特殊的含义。你不想在这里这样做。
  • .字符是一个特殊的正则表达式运算符,如果您希望按字面意思处理它,则需要在正则表达式中对其进行转义。
  • 读取一行的语法readIFS= read -r line,但同样不能保证文件路径仅由一行组成。
  • (cd -P -- "$dir" && find . ... -exec)这样做通常比这样做更好,find -- "$dir" ... -exec因为它避免了恰好$dirfind谓词或以 and 开头的值的问题-,因为它缩短了传递到的文件路径-exec,从而允许传递更多内容。

答案2

这是使用sed重命名文件的快速解决方案:

echo "10.01.07-10.01.48[M][@0][0].dav.avi" | sed 's/\[.*dav//'
10.01.07-10.01.48.avi

虽然我对 Synology shell 一无所知,但我希望它sed可用!

在循环中使用(例如):

#!/bin/sh

for file in *avi; do
    newName=$(echo "$file" | sed 's/\[.*dav//')
    mv -v "$file" "$newName" 
done

前:

ls
09.01.07-13.11.48[M][@0][0].dav.avi
110.01.07-13.11.48[M][@0][0].dav.avi
12.01.07-13.11.48[M][@0][0].dav.avi

运行脚本:

./renameAvi.sh 
”09.01.07-13.11.48[M][@0][0].dav.avi” -> ”09.01.07-13.11.48.avi”
”110.01.07-13.11.48[M][@0][0].dav.avi” -> ”110.01.07-13.11.48.avi”
”12.01.07-13.11.48[M][@0][0].dav.avi” -> ”12.01.07-13.11.48.avi”

后:

ls
09.01.07-13.11.48.avi   12.01.07-13.11.48.avi
110.01.07-13.11.48.avi 


编辑: 如果你想使用find 实现方式如下:

find . -name "*.avi" | while read fileName; do newName=$(echo "$fileName" | sed 's/\[.*dav//'); mv -v "$fileName" "$newName"; done
”./01.01.07-13.11.38[M][@0][0].dav.avi” -> ”./01.01.07-13.11.38.avi”
”./01.01.07-13.11.39[M][@0][0].dav.avi” -> ”./01.01.07-13.11.39.avi”

sed --version
sed (GNU sed) 4.2.2

find --version
find (GNU findutils) 4.4.2

答案3

对于递归文件重命名,您应该使用以下命令。

find . -name "*dav.avi" | while read fileName; do newName=$(echo "$fileName" | sed 's/\[.*dav//'); mv -v "$fileName" "$newName"; done

从上面的脚本更改

(我无法添加上面的评论,因此在此处添加答案,并对 maulinglawns 已经提到的脚本进行小改动)

  • 用于搜索 *dav.avi,因为您的 Synology 存储中将有许多递归文件,因此一旦重命名此文件,就应该再次重命名。
  • 这是一个很小的更改,但如果您的实际系统有约 GB 的数据文件,则会产生影响。

答案4

最后我找到了解决方案。重命名分两步完成。这是因为其他闭路电视录像机可能会传输具有不同名称但始终为 DAV 格式的文件。因此,只需添加与第二行类似的附加行,就可以与其他类型的记录器配合:

find $katalog -type f -name *.dav.avi | sed -e "p;s/.dav.avi/\.avi/" | xargs -n2 mv 2>/dev/null
find $katalog -type f -name *.avi | sed -e "p;s/\[M\]\[@0\]\[0\].avi/\.avi/" | xargs -n2 mv 2>/dev/null

相关内容