在Linux中使用bash脚本查找和重命名多个文件

在Linux中使用bash脚本查找和重命名多个文件,bash,file-rename,batch-rename,Bash,File Rename,Batch Rename,例如,在目录/home/hel/files/中有数千个文件和数百个目录。 应用程序在文件名中使用特殊字符保存其输出文件。 我想在所有文件名中用下划线替换这些特殊字符。e、 g.-:“@ 我编写了一个bash脚本,它简单地重复一个命令,使用Linux/Unix“rename”重命名文件 示例:文件名:rename.sh #!/bin/bash rename "s/\'/_/g" * rename 's/[-:"<>@\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/

例如,在目录
/home/hel/files/
中有数千个文件和数百个目录。 应用程序在文件名中使用特殊字符保存其输出文件。 我想在所有文件名中用下划线替换这些特殊字符。e、 g.
-:“@

我编写了一个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命令只搜索文件,不搜索目录

我尝试了其他一些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' "$@"

对于给定的路径
rename-d's...some/path/basename
只处理
basename
并忽略主要组件
some/path/
。如果
basename
是一个目录,尽管有
-d
选项,它仍将被重命名。

脚本
rename.sh
没有使用其命令行参数可以,但是可以使用glob
*
单独搜索文件和目录(!)

将脚本更改为以下内容

#!/bin/bash
rename -d s/\''/_/g;
s/[-:"<>@\,&\s\(\)\[\]?!–~%„“;│\´\’\+#]/_/g;
y/A-Z/a-z/;
s/\.(?=[^.]*\.)/_/g;
s/[_]{2,}/_/g' "$@"

对于给定的路径
rename-d's...some/path/basename
只处理
basename
并忽略主要组件
some/path/
。如果
basename
是一个目录,尽管有
-d
选项,它仍将被重命名。

在重命名文件的脚本中,请测试输入是否为文件。
[[-f filename]]
在重命名文件的脚本中进行测试,以检查输入是否为文件。
[[-f filename]]
感谢您的快速回答。我尝试了您的建议。我将“*”替换为“$@“在rename.sh脚本中,它确实可以解决这个问题,目录没有被重命名,但我需要一次又一次地重复整个命令,直到完成替换。对于200个测试文件,我做了大约15次手动重复。错误消息表示当前更改的文件不可用。我认为,在更改文件名替换的一部分后,下一步找不到该文件,因为它的名称不同。@Helmut如果您只是将五个
*
中的每一个替换为
$@
,那么您就猜对了。然而,我发布的脚本应该不会有任何问题(我写的
是错误的,其余的只是为了效率
)。在这个答案的脚本中,
rename.sh
中只有一个
rename
命令,它在内部执行所有重命名步骤,而不是实际重命名每个步骤的文件。我非常感谢您的回答。经过两次修改后,您的脚本工作正常。我使用UTF8文本替换单引号字符。它是:
rename's/\x27/\ug。另一个修改是使用-exec操作代替-execdir。目前,这是让圆点替代品发挥作用的唯一方法<代码>s/\(?=[^.]*\)/
使用-execdir,在模式正在搜索的文件名的开头用./查找结果文件名。也许我错了,但我会发现的。谢谢你的帮助。@Helmut哦,对了。我忘记了
find
在所有东西前面加上
/
,甚至加上
-execdir
。很高兴我能帮忙。谢谢你的快速回答。我尝试了你的建议。我在rename.sh脚本中用“$@”替换了“*”,它确实可以解决这个问题,目录没有重命名,但我需要一次又一次地重复整个命令,直到完成替换。对于200个测试文件,我做了大约15次手动重复。错误消息表示当前更改的文件不可用。我认为,在更改文件名替换的一部分后,下一步找不到该文件,因为它的名称不同。@Helmut如果您只是将五个
*
中的每一个替换为
$@
,那么您就猜对了。然而,我发布的脚本应该不会有任何问题(我写的
是错误的,其余的只是为了效率
)。在这个答案的脚本中,
rename.sh
中只有一个
rename
命令,它在内部执行所有重命名步骤,而不是实际重命名每个步骤的文件。我非常感谢您的回答。经过两次修改后,您的脚本工作正常。我使用UTF8文本替换单引号字符。它是:
rename's/\x27/\ug。另一个修改是使用-exec操作代替-execdir。目前,这是让圆点替代品发挥作用的唯一方法<代码>s/\(?=[^.]*\)/
使用-execdir,在模式正在搜索的文件名的开头用./查找结果文件名。也许我错了,但我会发现的。谢谢你的帮助。@Helmut哦,对了。我忘记了
find
在所有东西前面加上
/
,甚至加上
-execdir
。很高兴我能帮忙。
--path, --fullpath
        Rename full path: including any directory component.  DEFAULT

-d, --filename, --nopath, --nofullpath
        Do not rename directory: only rename filename component of path.