在 Linux 中使用 bash 脚本查找并重命名多个文件
Find and rename multiple files using a bash script in Linux
例如,目录/home/hel/files/
中有数千个文件和数百个目录。
应用程序将其输出文件保存在那里,文件名中包含特殊字符。
我想在所有文件名中用下划线替换这些特殊字符。例如-:"<>@
我写了一个 bash 脚本,它只是重复一个命令来使用 Linux/Unix 'rename'.
重命名文件
示例:文件名:rename.sh
#!/bin/bash
rename "s/\'/_/g" *
rename 's/[-:"<>@\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/_/g' *
rename 'y/A-Z/a-z/' *
rename 's/\.(?=[^.]*\.)/_/g' *
rename 's/[_]{2,}/_/g' *
我执行以下查找命令:
find /home/hel/files/ -maxdepth 1 -type f -execdir /home/hel/scripts/rename.sh {} \+
现在问题:
这很好用,除了它还会重命名子目录,如果它们的名称中包含搜索到的字符。
find 命令只搜索文件而不搜索目录。
我尝试了一些其他的查找变体,例如:
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} \+
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} +
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} \;
它们都在工作,但结果相同。
什么不起作用:
find /home/hel/files/ -maxdepth 1 -type f -exec sh /home/hel/scripts/rename.sh {} \+
这个很危险,因为它会重命名当前目录中的目录和文件,您也将在该目录中调用 find 命令。
也许有人知道为什么会发生这种情况或有更好的解决方案。
脚本 rename.sh
根本没有使用其命令行参数,而是使用 glob *
.
自行搜索文件和目录 (!)
将您的脚本更改为以下内容。
#!/bin/bash
rename -d s/\''/_/g;
s/[-:"<>@\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/_/g;
y/A-Z/a-z/;
s/\.(?=[^.]*\.)/_/g;
s/[_]{2,}/_/g' "$@"
然后使用find ... -maxdepth 1 -type f -exec sh .../rename.sh {} +
.
所做的更改
- 使用
"$@"
而不是 *
来处理作为参数给出的文件而不是当前目录中的所有内容。
- 只执行一次
rename
,因为在第一个rename
重命名后,第二个rename
找不到用"$@"
指定的文件。
- 使用
-d
选项只修改基本名称。 find
总是在文件前面放一个路径,至少 ./
。如果没有此选项,rename
会将 ./filename
更改为 mangledPath/newFilename
,从而将文件移动到另一个目录。
注意man rename
有点误导
--path, --fullpath
Rename full path: including any directory component. DEFAULT
-d, --filename, --nopath, --nofullpath
Do not rename directory: only rename filename component of path.
对于给定路径 rename -d 's...' some/path/basename
只处理 basename
并忽略前导组件 some/path/
。如果 basename
是一个目录,尽管有 -d
选项,它仍然会被重命名。
例如,目录/home/hel/files/
中有数千个文件和数百个目录。
应用程序将其输出文件保存在那里,文件名中包含特殊字符。
我想在所有文件名中用下划线替换这些特殊字符。例如-:"<>@
我写了一个 bash 脚本,它只是重复一个命令来使用 Linux/Unix 'rename'.
重命名文件示例:文件名:rename.sh
#!/bin/bash
rename "s/\'/_/g" *
rename 's/[-:"<>@\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/_/g' *
rename 'y/A-Z/a-z/' *
rename 's/\.(?=[^.]*\.)/_/g' *
rename 's/[_]{2,}/_/g' *
我执行以下查找命令:
find /home/hel/files/ -maxdepth 1 -type f -execdir /home/hel/scripts/rename.sh {} \+
现在问题:
这很好用,除了它还会重命名子目录,如果它们的名称中包含搜索到的字符。
find 命令只搜索文件而不搜索目录。
我尝试了一些其他的查找变体,例如:
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} \+
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} +
find /home/hel/files/ -maxdepth 1 -type f -execdir sh /home/hel/scripts/rename.sh {} \;
它们都在工作,但结果相同。
什么不起作用:
find /home/hel/files/ -maxdepth 1 -type f -exec sh /home/hel/scripts/rename.sh {} \+
这个很危险,因为它会重命名当前目录中的目录和文件,您也将在该目录中调用 find 命令。
也许有人知道为什么会发生这种情况或有更好的解决方案。
脚本 rename.sh
根本没有使用其命令行参数,而是使用 glob *
.
将您的脚本更改为以下内容。
#!/bin/bash
rename -d s/\''/_/g;
s/[-:"<>@\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/_/g;
y/A-Z/a-z/;
s/\.(?=[^.]*\.)/_/g;
s/[_]{2,}/_/g' "$@"
然后使用find ... -maxdepth 1 -type f -exec sh .../rename.sh {} +
.
所做的更改
- 使用
"$@"
而不是*
来处理作为参数给出的文件而不是当前目录中的所有内容。 - 只执行一次
rename
,因为在第一个rename
重命名后,第二个rename
找不到用"$@"
指定的文件。 - 使用
-d
选项只修改基本名称。find
总是在文件前面放一个路径,至少./
。如果没有此选项,rename
会将./filename
更改为mangledPath/newFilename
,从而将文件移动到另一个目录。
注意man rename
有点误导
--path, --fullpath
Rename full path: including any directory component. DEFAULT
-d, --filename, --nopath, --nofullpath
Do not rename directory: only rename filename component of path.
对于给定路径 rename -d 's...' some/path/basename
只处理 basename
并忽略前导组件 some/path/
。如果 basename
是一个目录,尽管有 -d
选项,它仍然会被重命名。