搜索+替换文件名中的字符串

时间:2011-08-24 07:04:32

标签: bash

使用bash,如何在目录中递归包含的所有文件名(包括文件夹)中搜索所有出现的子字符串'foo',并用'bar'替换它们?

例如,如果当前结构如下:

-foo_test
    - fooo.txt
    - xfoo
        - yfoo.h
- 1foo.c

运行bash脚本后应该如下所示:

-bar_test
    - baro.txt
    - xbar
        - ybar.h
- 1bar.c

2 个答案:

答案 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