我想将一些目录从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脚本中收集文件数组并对其执行的一些常见替代方法是什么?
find
命令的-exec
和{}
功能,这样就不需要使用管道了: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
我认为这是因为find
和xargs
每次执行命令时都会调用其他的/bin/sh (实际上是exec(3)
),而shell的while
循环则不会。
更新:如果你的busybox版本编译时没有支持-exec
选项的find
命令,则另外两个答案(one,two)中建议的while
循环或xargs
就是你的选择。
xargs
在这种情况下也会为每个文件执行命令,因此 find
不会变慢。 - praetorian droid-exec ... {} +
的行为与 xargs 相同(在最小化调用次数方面),并且自 2006 年以来一直是 find
POSIX 标准的一部分。 - Charles DuffyUse a for
loop. Unfortunately I don't think busybox understands read -0
either, so you won't be able to handle newlines properly. If you don't need to, it's easiest to just:
find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while read file; do mv -- "$file" "$file".old; done
Use a sh -c
as the command. Note the slightly weird use of $0
to name the first argument (it would normally be the script name and that goes to $0
and while you are suppressing script with -c
, the argument still goes to $0
) and the use of -n 1
to avoid batching.
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
的事情。
另一种方法是使用循环:
find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while IFS= read file
do
mv "$file" "$file".old
done
read
使用换行符作为分隔符。你需要使用 read -0
(但我不确定它是否在 busybox 中实现)或者只需要使用 -print
。 - Jan Hudec
"*.y"
的文件(引号将被传递给find,而*将由shell扩展,但它将找不到任何内容并继续传递),我怀疑这样的文件不存在。 - Jan HudecCONFIG_FEATURE_FIND_PRINT0
、CONFIG_FEATURE_FIND_EXEC
和CONFIG_FEATURE_FIND_EXEC_PLUS
-- 这些方法是否可行取决于您的副本编译的具体细节。 - Charles Duffy