我想将一堆dirs从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脚本中执行它们?
答案 0 :(得分:9)
您可以使用-exec
命令的{}
和find
功能,因此您根本不需要任何管道:
find -maxdepth 1 -type d -name "*.y" -mtime +`expr 2 \* 365` -exec mv "{}" "{}.old" \;
此外,您无需指定'。' path - 这是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
我认为这是因为find
和xargs
每次执行命令都调用额外的/ bin / sh(实际上exec(3)
执行它),而shell while
循环执行不
更新:如果编译的busybox版本没有-exec
命令的find
选项支持,则建议while
循环或xargs
在其他答案中(one,two),是你的方式。
答案 1 :(得分:2)
使用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
使用sh -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
。
答案 2 :(得分:1)
另一种方法是使用循环:
find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while IFS= read file
do
mv "$file" "$file".old
done