【问题标题】:Alternatives to xargs -lxargs -l 的替代品
【发布时间】:2012-02-04 06:26:01
【问题描述】:

我想将一堆目录从 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 列出精确调用 "*.y" 的文件(引号将传递给 find 并且 * 将由 shell 扩展,它什么也找不到,并且无论如何都通过了),我怀疑它存在。
  • busybox 的各种编译时选项包括CONFIG_FEATURE_FIND_PRINT0CONFIG_FEATURE_FIND_EXECCONFIG_FEATURE_FIND_EXEC_PLUS - 方法将或不会工作,具体取决于您的 /i> 副本已编译。

标签: bash shell find xargs busybox


【解决方案1】:

您可以使用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

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

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

【讨论】:

  • +1:find 命令带有-exec 选项。它比xargs 慢一点,因为它为找到的每个文件执行命令。但是,它可以工作,并且不存在 空格 问题,因为不涉及 shell。如果由于空格问题而无法使用xargs,请使用-exec。循环与-exec 参数一样低效,因为它们对每个文件执行一次,但存在xargs 的空白问题。
  • xargs 在这种情况下也会为每个文件执行命令,因此find 不会变慢。
  • 你是对的。我没有看命令。通常您使用 xargs 而不是 -exec,因为 xargs 在命令行上组合尽可能多的文件并且只执行几次命令。
  • 错误;这是因为 find 和 exec 不运行 shell,所以必须为每个文件执行 /bin/echo。如果我们修改脚本以使用 /bin/echo 那么时间与前两个选项相当;添加选项 find "$1" -printf "mv %p %p.old\n" 运行速度比内置 echo 快。
  • 这不像写的那样工作,因为 Busybox 不支持 -exec 选项来查找。 Jan Hudec 发布的 while 循环方法适用于 Busybox
【解决方案2】:
  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. 使用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

【讨论】:

  • Busybox 甚至不理解 print0。但是你的whie循环有效
【解决方案3】:

另一种方法是使用循环:

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
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-28
  • 2010-11-08
  • 2012-01-25
  • 2015-08-05
相关资源
最近更新 更多