我有一个使用for循环的脚本,它会重命名文件夹和文件。该脚本将获取文件和文件夹列表并有条件地重命名它们。我将使用以下命令调用该文件:
find test/* -exec ./replace.sh {} \;
我的replace.sh脚本将包含类似于:
的内容for i in $@
mv $OLDFILE $NEWFILE
done
之前已经设置了当我遇到子目录时,我的问题出现了。最初,我会有像这样的文件夹:
folder_1
-file1
-file2
当我的脚本将folder_1更改为folderX1时,下一个参数folder_1 / file1将无效,因为更改的路径将是folderX1 / file1。我想我可以创建一个堆栈,其中包含正在更改的文件夹列表,稍后将其弹出以重命名文件,但这在bash上看起来很难。有没有更好的方法让我失踪?
P.S我可以多次运行该程序来浏览所有子目录,但这看起来效率不高。
答案 0 :(得分:2)
您可以将-depth
添加到find命令。这将在目录本身之前处理目录的文件。有关详细信息,请参阅man find
。
答案 1 :(得分:1)
您的find
用法存在问题。第一个选项是搜索的起始位置,因此您不希望在那里使用glob。如果您只想要test/
中的文件而不是其任何子目录中的文件,请使用-depth
选项,如Olaf建议的那样。
您实际上不需要使用单独的脚本来处理此重命名。它可以在find
命令行中完成,如果你不介意有点乱。
要处理顶级文件,您可以这样做:
$ touch foo.txt bar.txt baz.ext
$ find test -depth 1 -type f -name \*.txt -exec bash -c 'f="{}"; mv -v "{}" "${f/.txt/.csv}"' \;
./foo.txt -> ./foo.csv
./bar.txt -> ./bar.csv
$
但您的问题是有效的 - find
会建立匹配列表,如果您的-exec
更改了find
下的列表,则有些重命名会失败。
我怀疑你最快的解决方案是在两个阶段(而不是几个阶段)执行此操作:一个用于文件,一个用于目录。 (或者改变顺序,我认为不应该重要。)
$ mkdir foo_1; touch red_2 foo_1/blue_3
$ find . -type f -name \*_\* -exec bash -c 'f="{}"; mv -v "{}" "${f%_?}X${f##*_}"' \;
./foo_1/blue_3 -> ./foo_1/blueX3
./red_2 -> ./redX2
$ find . -type d -name \*_\* -exec bash -c 'f="{}"; mv -v "{}" "${f%_?}X${f##*_}"' \;
./foo_1 -> ./fooX1
Bash参数扩展将为您提供很长的路要走。
根据您find
的实施情况,另一个选项是-d
选项:
-d Cause find to perform a depth-first traversal, i.e., directories
are visited in post-order and all entries in a directory will be
acted on before the directory itself. By default, find visits
directories in pre-order, i.e., before their contents. Note, the
default is not a breadth-first traversal.
所以:
$ mkdir -p foo_1/bar_2; touch red_3 foo_1/blue_4 foo_1/bar_2/green_5
$ find . -d -name \*_\* -exec bash -c 'f="{}"; mv -v "{}" "${f%_?}X${f##*_}"' \;
./foo_1/bar_2/green_5 -> ./foo_1/bar_2/greenX5
./foo_1/bar_2 -> ./foo_1/barX2
./foo_1/blue_4 -> ./foo_1/blueX4
./foo_1 -> ./fooX1
./red_3 -> ./redX3
$