8

我想将一堆目录从 DIR 重命名为 DIR.OLD。理想情况下,我会使用以下内容:

find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print0 | xargs -0 -r -I file mv file file.old

但是我要执行此操作的机器安装了 BusyBox,并且 BusyBox xargs 不支持“-I”选项。

有哪些常见的替代方法可以收集文件数组,然后在 shell 脚本中对它们执行?

4

3 回答 3

12

您可以使用命令的-exec{}功能,find因此您根本不需要任何管道:

find -maxdepth 1 -type d -name "*.y" -mtime +`expr 2 \* 365` -exec mv "{}" "{}.old" \;

你也不需要指定'.' 路径 - 这是find. 你在"*.y". 当然,如果您的文件名实际上不包含引号。

公平地说,应该注意的是,带有while read循环的版本是这里提出的最快的版本。以下是一些示例测量:

$ cat measure 
#!/bin/sh
case $2 in
  1) find "$1" -print0 | xargs -0 -I file echo mv file file.old ;;

  2) find "$1" -exec echo mv '{}' '{}.old' \; ;;

  3) find "$1" | while read file; do
       echo mv "$file" "$file.old"
     done;;
esac
$ time ./measure android-ndk-r5c 1 | wc
   6225   18675  955493
real    0m6.585s
user    0m18.933s
sys     0m4.476s
$ time ./measure android-ndk-r5c 2 | wc
   6225   18675  955493
real    0m6.877s
user    0m18.517s
sys     0m4.788s
$ time ./measure android-ndk-r5c 3 | wc
   6225   18675  955493
real    0m0.262s
user    0m0.088s
sys     0m0.236s

我认为这是因为每次执行命令时都会调用额外的 /bin/sh (实际上是这样做的),而 shellfind循环xargs则不会。exec(3)while

更新:如果您的busybox版本是在不-exec支持该find命令的选项的情况下编译的,那么while循环或xargs,在其他答案()中建议,是您的方式。

于 2012-01-06T14:40:37.890 回答
3
  1. 使用for循环。不幸的是,我认为busybox 也不理解read -0,因此您将无法正确处理换行符。如果您不需要,最简单的方法是:

    find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while read file; do mv -- "$file" "$file".old; done
    
  2. 使用 ash -c作为命令。请注意使用$0来命名第一个参数有点奇怪(它通常是脚本名称,$0并且当您使用 抑制脚本时-c,参数仍然转到$0)以及-n 1避免批处理的使用。

    find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print0 | xargs -0 -r -n 1 sh -c 'mv -- "$0" "$0".old'
    

编辑 哎呀:我又忘记了find -exec

于 2012-01-06T14:38:12.563 回答
1

另一种方法是使用循环:

find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while IFS= read file
do
    mv "$file" "$file".old
done
于 2012-01-06T14:35:51.253 回答