如何在 xargs 中使用替换?

rog*_*ger 5 shell xargs

我想做的是

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

它可以这样做:

for f in `find . -type f -name "*.txt"`; do cp $f ${f%.txt}.dat; done
Run Code Online (Sandbox Code Playgroud)

我想用 xargs 做到这一点,我试过这个:

find . -type f -name "*.txt" | xargs -i cp {} ${{}%.txt}.dat
Run Code Online (Sandbox Code Playgroud)

我会像这样出错:

bad substitution
Run Code Online (Sandbox Code Playgroud)

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

  1. 如何正确地进行替换?
  2. 我很好奇,xargs当for loop一件件事情做的时候,事情会并行吗?

syn*_*gma 9

  1. 如何正确地进行替换?

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

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

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

是的,for循环会依次思考,但默认情况下 xargs 总是会。但是,您可以使用来自手册页的-P选项xargs来并行化它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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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