xargs -l 的替代品

发布于 2024-12-25 19:19:57 字数 291 浏览 5 评论 0原文

我想将一堆目录从 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 脚本中执行它们的常见替代方法有哪些?

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

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

诗笺 2025-01-01 19:19:57

您可以使用 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,在其他答案中建议(一个两个),就是你的方式。

You can use -exec and {} features of the find command so you don't need any pipes at all:

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.

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

$ 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

I think it's because find and xargs invokes additional /bin/sh (actually exec(3) does it) every time for execute a command, while shell while loop do not.

Upd: If your busybox version was compiled without -exec option support for the find command then the while loop or xargs, suggested in the other answers (one, two), is your way.

快乐很简单 2025-01-01 19:19:57
  1. 使用for循环。不幸的是,我认为 busybox 也不理解 read -0 ,因此您将无法正确处理换行符。如果您不需要,最简单的方法是:

    <前><代码>查找 . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print |读取文件时; do mv -- "$file" "$file".old;完毕

  2. 使用 sh -c 作为命令。请注意,使用 $0 来命名第一个参数(通常是脚本名称,并且转到 $0 ,当您使用 - 抑制脚本时,这有点奇怪) c,参数仍然转到$0)并使用-n 1来避免批处理。

    <前><代码>查找 . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print0 | xargs -0 -r -n 1 sh -c 'mv -- "$0" "$0".old'

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

  1. Use 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
    
  2. 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'
    

Edit Oops: I forgot about the find -exec again.

[浮城] 2025-01-01 19:19:57

另一种方法是使用循环:

find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while IFS= read file
do
    mv "$file" "$file".old
done

An alternative is to use a loop:

find . -maxdepth 1 -type d -name \"*.y\" -mtime +`expr 2 \* 365` -print | while IFS= read file
do
    mv "$file" "$file".old
done
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文