1

我有一个使用 for 循环的脚本,可以重命名文件夹和文件。该脚本将获取文件和文件夹列表并有条件地重命名它们。我将使用以下命令调用该文件:

find test/* -exec ./replace.sh {} \;

我的 replace.sh 脚本将包含类似于:

for i in $@
mv $OLDFILE $NEWFILE
done

$OLDFILE 和 $NEWFILE 之前已经设置好了,我相信它们不会出现任何问题。

当我遇到子目录时,我的问题就出现了。最初,我会有如下文件夹:

folder_1

 -file1

 -file2

当我的脚本将 folder_1 更改为 folderX1 时,下一个参数 folder_1/file1 将无效,因为更改后的路径将是 folderX1/file1。我想我可以创建一个包含正在更改的文件夹列表的堆栈,然后将它们弹出以重命名文件,但这在 bash 上似乎很难。我缺少更好的方法吗?

PS 我可以多次运行程序来遍历所有子目录,但这似乎效率不高。

4

2 回答 2

2

您可以添加-depth到 find 命令。这将在目录本身之前处理目录的文件。详情请参阅man find

于 2013-04-12T23:41:25.370 回答
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从 under 更改列表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
$ 
于 2013-04-13T00:17:30.230 回答