bash xargs -l 的替代方案

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8759285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 01:15:26  来源:igfitidea点击:

Alternatives to xargs -l

bashshellfindxargsbusybox

提问by eatloaf

I want to rename a bunch of dirs from DIR to DIR.OLD. Ideally I would use the following:

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

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

But the machine I want to execute this on has BusyBox installed and the BusyBox xargs doesn't support the "-I" option.

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

What are some common alternative methods for collecting an array of files and then executing on them in a shell script?

收集文件数组然后在 shell 脚本中对它们执行的一些常见替代方法是什么?

回答by praetorian droid

You can use -execand {}features of the findcommand so you don't need any pipes at all:

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

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

Also you don't need to specify '.' path - this is default for find. And you used extra slashes in "*.y". Of course if your file names do not really contain quotes.

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

In fairness it should be noted, that version with while readloop is the fastest of proposed here. Here are some example measurements:

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

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

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

  3) find "" | 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

I think it's because findand xargsinvokes additional /bin/sh (actually exec(3)does it) every time for execute a command, while shell whileloop do not.

我想这是因为findxargs所调用额外的/ bin / sh的(实际上exec(3)确实是)为执行命令每一次,而壳while循环不。

Upd:If your busybox version was compiled without -execoption support for the findcommand then the whileloop or xargs, suggested in the other answers (one, two), is your way.

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

回答by Jan Hudec

  1. Use a forloop. Unfortunately I don't think busybox understands read -0either, 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
    
  2. Use a sh -cas the command. Note the slightly weird use of $0to name the first argument (it would normally be the script name and that goes to $0and while you are suppressing script with -c, the argument still goes to $0) and the use of -n 1to avoid batching.

    find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print0 | xargs -0 -r -n 1 sh -c 'mv -- "
    find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while read file; do mv -- "$file" "$file".old; done
    
    " "
    find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print0 | xargs -0 -r -n 1 sh -c 'mv -- "
    find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while IFS= read file
    do
        mv "$file" "$file".old
    done
    
    " "##代码##".old'
    ".old'
  1. 使用for循环。不幸的是,我认为busybox 也不理解read -0,因此您将无法正确处理换行符。如果您不需要,最简单的方法是:

    ##代码##
  2. 使用 ash -c作为命令。请注意$0命名第一个参数的稍微奇怪的用法(它通常是脚本名称,$0并且当您使用 抑制脚本时-c,参数仍然转到$0)以及使用-n 1避免批处理。

    ##代码##

EditOops: I forgot about the find -execagain.

编辑糟糕:我又忘记find -exec了。

回答by dogbane

An alternative is to use a loop:

另一种方法是使用循环:

##代码##