使用bash,如何在目录中递归包含的所有文件名(包括文件夹)中搜索所有出现的子字符串'foo',并用'bar'替换它们?
例如,如果当前结构如下:
-foo_test
- fooo.txt
- xfoo
- yfoo.h
- 1foo.c
运行bash脚本后应该如下所示:
-bar_test
- baro.txt
- xbar
- ybar.h
- 1bar.c
答案 0 :(得分:47)
此处显示的两种变体都在OPs测试结构上正确使用:
find . -depth -name '*foo*' -execdir bash -c 'mv -i "$1" "${1//foo/bar}"' bash {} \;
或者,如果您有大量文件并希望它运行得更快:
find . -depth -name '*foo*' -execdir bash -c 'for f; do mv -i "$f" "${f//foo/bar}"; done' bash {} +
编辑:如评论中所述,我之前使用find
命令未使用execdir
选项并使用rename
的答案在重命名时出现问题目录中包含foo的文件。根据建议,我已将find命令更改为使用-execdir
,并且我已使用rename
命令删除了变体,因为它是非标准命令。
答案 1 :(得分:3)
由于带有多个“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/\1bar/'`
#change only the last occurance of foo
mv "$D" `echo "$D" | sed 's/\(.*\)foo/\1bar/'`
done
我毫不怀疑有更简短,更优雅的方法(可能只是通过删除此脚本中的一半行),但我很确定这是有效的。
修改强>
相同的循环是一面红旗。此版本仅循环一次。您收到一条尝试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/\1bar/'`
#change only the last occurence of foo
mv "$D" `echo "$D" | sed 's/\(.*\)foo/\1bar/'`
done