bash 搜索+替换文件名中的字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7171659/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Search+replace strings in filenames
提问by Cam
Using bash, how can I search for all occurrences of the substring 'foo' in all filenames (including folders) contained recursively in a directory and replace them them with 'bar'?
使用 bash,如何在目录中递归包含的所有文件名(包括文件夹)中搜索所有出现的子字符串 'foo' 并将它们替换为 'bar'?
For example, if the current structure looks like:
例如,如果当前结构如下所示:
-foo_test
- fooo.txt
- xfoo
- yfoo.h
- 1foo.c
It should look like this after running the bash script:
运行 bash 脚本后,它应该如下所示:
-bar_test
- baro.txt
- xbar
- ybar.h
- 1bar.c
回答by Adrian Pronk
Both variations shown here using work correctly on OPs test structure:
此处显示的两种变体都在 OP 测试结构上正常工作:
find . -depth -name '*foo*' -execdir bash -c 'mv -i "" "${1//foo/bar}"' bash {} \;
or, if you have a very large number of files and want it to run faster:
或者,如果您有大量文件并希望它运行得更快:
find . -depth -name '*foo*' -execdir bash -c 'for f; do mv -i "$f" "${f//foo/bar}"; done' bash {} +
EDIT: As noted in the comments, my earlier answer using a find
command that did not use the execdir
option and using rename
has problems renaming files in directories that contain foo in their name. As suggested, I have changed the find commands to use -execdir
, and I have deleted the variation using the rename
command since it is a non-standard command.
编辑:如评论中所述,我之前的回答使用find
未使用该execdir
选项的命令并使用在rename
重命名名称中包含 foo 的目录中的文件时出现问题。按照建议,我已将 find 命令更改为 use -execdir
,并且我已使用该rename
命令删除了变体,因为它是一个非标准命令。
回答by SSteve
This was tricky because of directorynames with multiple instances of "foo". When you change ./foo_test/xfoo
to ./bar_test/xbar
everything that was in ./foo_test
becomes inaccessible. So I changed the file names first then changed the last occurrence of "foo" in the directory names. I added echo statements to track what's going on during development. You can, of course, expunge them.
这很棘手,因为目录名称包含多个“foo”实例。当您更改./foo_test/xfoo
为无法访问的./bar_test/xbar
所有内容./foo_test
时。所以我首先更改了文件名,然后更改了目录名称中最后一次出现的“foo”。我添加了 echo 语句来跟踪开发过程中发生的事情。当然,您可以删除它们。
#!/bin/sh
#first change the file names
#append '.' to process files in current directory
for D in $(find -d . -name "*foo*" -type d ) '.'
do
pushd $D >> /dev/null
echo 'directory: ' "$D"
for file in $(find . -name "*foo*" -type f -maxdepth 1)
do
echo ' change' "$file" 'to' `echo "$file" | sed s/foo/bar/g`
mv "$file" `echo "$file" | sed s/foo/bar/g`
done
popd >> /dev/null
done
echo ''
#Now change the directory names
for D in $(find -d . -name "*foo*" -type d )
do
echo 'change' "$D" 'to' `echo "$D" | sed 's/\(.*\)foo/bar/'`
#change only the last occurance of foo
mv "$D" `echo "$D" | sed 's/\(.*\)foo/bar/'`
done
I have no doubt there are shorter, more elegant ways to do this (probably just by removing half of the lines in this script), but I'm pretty sure this works.
我毫不怀疑有更短、更优雅的方法来做到这一点(可能只是通过删除这个脚本中的一半行),但我很确定这是有效的。
EDITThe identical loops were a red flag. This version only loops once. You get a message attempting mv '.' '.'
, but it's safely ignored.
编辑相同的循环是一个危险信号。这个版本只循环一次。您收到一条消息尝试mv '.' '.'
,但它被安全地忽略了。
#!/bin/sh
#first change the file names
#append '.' to change file in current directory
for D in $(find -d . -name "*foo*" -type d ) '.'
do
pushd $D >> /dev/null
echo 'directory: ' "$D"
for file in $(find . -name "*foo*" -type f -maxdepth 1)
do
echo ' change' "$file" 'to' `echo "$file" | sed s/foo/bar/g`
mv "$file" `echo "$file" | sed s/foo/bar/g`
done
popd >> /dev/null
echo 'change' "$D" 'to' `echo "$D" | sed 's/\(.*\)foo/bar/'`
#change only the last occurence of foo
mv "$D" `echo "$D" | sed 's/\(.*\)foo/bar/'`
done