【问题标题】:How to use substitution in xargs?如何在 xargs 中使用替换?
【发布时间】:2022-02-16 23:24:00
【问题描述】:

我想做的是

  1. 查找所有带有.txt 扩展名的文件
  2. cp 到.dat 文件

它可以这样做:

for f in `find . -type f -name "*.txt"`; do cp $f ${f%.txt}.dat; done

我想用 xargs 来做这个,我试过这个:

find . -type f -name "*.txt" | xargs -i cp {} ${{}%.txt}.dat

我出现这样的错误:

bad substitution

关于这个,我有以下问题:

  1. 如何正确替换?
  2. 我很好奇xargs会在for loop一件一件的事情上做并行?

【问题讨论】:

    标签: shell xargs


    【解决方案1】:
    1. 如何正确替换?

    您不能以您尝试的方式使用替换,因为{} 不是 bash 变量(只是 xargs 语法的一部分),因此 bash 无法对其进行替换。

    更好的方法是创建一个完整的 bash 命令并将其作为参数提供给 xargs(例如 xargs -0 -i bash -c 'echo cp "$1" "${1%.txt}.dat"' - '{}' - 这样您可以进行 bash 替换)。

    1. 我很好奇 xargs 会在 for 循环一件一件地做事情时并行做事情?

    是的,for 循环会按顺序执行,但默认情况下 xargs 始终会执行。但是,您可以使用xargs-P 选项来并行化它,来自xargs 手册页:

       -P max-procs, --max-procs=max-procs
              Run up to max-procs processes at a time; the default is 1.  If max-procs is 0, xargs will run as many processes as possible at a time.  Use the -n option or the -L  option
              with  -P;  otherwise  chances are that only one exec will be done.  While xargs is running, you can send its process a
    

    SIGUSR1 信号增加命令数量 同时运行,或者使用 SIGUSR2 来减少数量。您不能将其增加到超过实现定义的限制(即 用 --show-limits 显示)。你不能定义 将其折痕到 1 以下。 xargs 永远不会终止它的命令;当被要求减少时,它只等待一个以上的存在 命令在开始另一个之前终止。

    Please  note that it is up to the called processes to properly manage parallel access to shared resources.  For example, if
    

    其中不止一个试图打印到标准输出, 除非流程在某些方面进行协作,否则输出将以不确定的顺序生成(并且很可能会混淆) 防止这种情况的方法。使用某种锁定 方案是防止此类问题的一种方法。一般来说,使用锁定方案将有助于确保正确的输出,但 降低性能。如果你不想忍受 性能差异,只需安排每个进程生成一个单独的输出文件(或以其他方式使用单独的 资源)。

    【讨论】:

      【解决方案2】:

      你可以使用:

      find . -type f -name "*.txt" -print0 |
      xargs -0 -i bash -c 'echo cp "$1" "${1%.txt}.dat"' - '{}'
      

      【讨论】:

        【解决方案3】:

        如果您对 bash -c '...' - 结构不满意,您可以改用 GNU Parallel:

        find . -type f -name "*.txt" -print0 | parallel -0 cp {} {.}.dat
        

        【讨论】:

          【解决方案4】:
          对于这类东西,

          xargs 和其他工具不如 Perl 灵活。

          ~ ❱ find . | perl -lne '-f && ($old=$_) && s/\.txt/.dat/g && print "$old => $_"'
          ./dir/00.file.txt => ./dir/00.file.dat
          ./dir/06.file.txt => ./dir/06.file.dat
          ./dir/05.file.txt => ./dir/05.file.dat
          ./dir/02.file.txt => ./dir/02.file.dat
          ./dir/08.file.txt => ./dir/08.file.dat
          ./dir/07.file.txt => ./dir/07.file.dat
          ./dir/01.file.txt => ./dir/01.file.dat
          ./dir/04.file.txt => ./dir/04.file.dat
          ./dir/03.file.txt => ./dir/03.file.dat
          ./dir/09.file.txt => ./dir/09.file.dat
          

          然后代替print函数使用:rename $old, $_

          有了这个one-liner,你可以重命名任何你喜欢的东西


          要强制xargs 使用并行模式,您应该使用-P,例如:

          ls *.mp4 | xargs -I xxx -P 0 ffmpeg -i xxx xxx.mp3
          

          同时将所有.mp4 文件转换为.mp3。因此,如果您有 10 个mp4,那么 10 个ffmpeg 将同时运行。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-09-07
            • 1970-01-01
            • 2020-08-20
            • 2019-07-13
            • 2020-07-13
            • 2021-02-01
            • 2016-06-11
            相关资源
            最近更新 更多