假设我有以下目录树:
.
|-- foo
`-- foodir
|-- bardir
| |-- bar
| `-- foo
|-- foo -> bardir/foo
`-- foodir
|-- bar
`-- foo
3 directories, 6 files
如何将所有foo
重命名为buz
,包括符号链接?喜欢:
.
|-- buz
`-- buzdir
|-- bardir
| |-- bar
| `-- buz
|-- buz -> bardir/buz
`-- buzdir
|-- bar
`-- buz
3 directories, 6 files
我认为乍一看相对容易,但事实证明这是出乎意料的困难。
首先,我尝试使用mv
对所有文件进行git ls-files
:
$ for file in $(git ls-files '*foo*'); do mv "$file" "${file//foo/buz}"; done
这给了我很多错误,他们说我必须先创建新目录:
mv: cannot move 'foodir/bardir/bar' to 'buzdir/bardir/bar': No such file or directory
mv: cannot move 'foodir/bardir/foo' to 'buzdir/bardir/buz': No such file or directory
mv: cannot move 'foodir/foo' to 'buzdir/buz': No such file or directory
mv: cannot move 'foodir/foodir/bar' to 'buzdir/buzdir/bar': No such file or directory
mv: cannot move 'foodir/foodir/foo' to 'buzdir/buzdir/buz': No such file or directory
我不想在复制后清理空目录,所以我尝试find -exec
期望它可以在根据文件名查找文件时处理文件重命名。
$ find . -path .git -prune -o -name '*foo*' -exec bash -c 'mv "$0" "${0//foo/buz}"' "{}" \;
但是find
似乎仍尝试从重命名的路径重命名文件。
find: ./foodir: No such file or directory
我的最终解决方案是为每个find
命令使用mv
第一个文件/目录。
#!/bin/bash
# Rename file paths recursively
while :; do
path=$(find . -path .git -prune -o -name '*foo*' -print -quit)
if [ -z "$path" ]; then
break
fi
if ! mv "$path" "${path/foo/buz}"; then
break
fi
done
# Change symlink targets as well
find . -path .git -prune -o -type l -exec bash -c '
target=$(readlink "$0")
if [ "$target" != "${target//foo/buz}" ]; then
ln -sfn "${target//foo/buz}"
fi
' "{}" \;
这有点la脚,但按我的预期工作。所以我的问题是:
find
总是在其子目录/文件之前输出目录吗?find
?谢谢。