在带参数的多个输入列表上使用 xargs 到 运行 bash 脚本

Using xargs to run bash scripts on multiple input lists with arguments

我正在尝试 运行 多个文件列表上的脚本,同时还并行传递参数。我有 file_list1.dat、file_list2.dat、file_list3.dat。我想 运行 script.sh 接受 3 个参数:arg1、arg2、arg3。

对于一个 运行,我会这样做:

sh script.sh file_list1.dat $arg1 $arg2 $arg3

我想运行对所有文件列表并行执行此命令。

我的尝试:

Ncores=4
ls file_list*.dat | xargs -P "$Ncores" -n 1 [sh script.sh [$arg1 $arg2 $arg3]]

这会导致错误:-P 选项的数字无效。我认为这个命令的顺序是错误的。

我的第二次尝试:

echo $arg1 $arg2 $arg3 | xargs ls file_list*.dat | xargs -P "$Ncores" -n 1 sh script.sh

但这会导致错误:xargs: ls: 终止于信号 13

关于使用 xargs 将参数传递给 bash 脚本的正确语法有什么想法吗?

我不确定我是否完全理解你想要做什么。是否要并行执行类似这些命令的操作?

sh script.sh $arg1 $arg2 $arg3 file_list1.dat
sh script.sh $arg1 $arg2 $arg3 file_list2.dat
sh script.sh $arg1 $arg2 $arg3 file_list3.dat
...etc

如果这是正确的,这应该有效:

Ncores=4
printf '%s[=11=]' file_list*.dat | xargs -0 -P "$Ncores" -n 1 sh script.sh "$arg1" "$arg2" "$arg3"

您的版本中的两个主要问题是您将 "Ncores" 作为文字字符串传递(而不是使用 $Ncores 来获取变量的值),并且您有 [ ] 围绕命令和参数(这与 shell 语法的任何相关部分无关)。我还在所有变量引用周围添加了双引号(通常是好的做法),并使用 printf '%s[=14=]'(和 xargs -0)代替 ls.

为什么我使用 printf 而不是 ls?因为 ls 在这里没有做任何 printfecho 或任何不能做的有用的事情。您可能会认为 ls 是获取文件名列表的工具,但在这种情况下,通配符表达式 file_list*.dat 命令之前扩展为文件列表 是 运行;所有 ls 对它们所做的就是查看每一个,对自己说 "yep, that's a file",然后打印出来。 echo 可以用更少的开销做同样的事情。但是使用 lsecho 如果任何文件名包含空格、引号或其他有趣的字符,输出可能会模棱两可。 ls 的某些版本试图通过在 周围 带有有趣字符的文件名中添加引号或其他内容来 "fix" ,但这可能与 xargs 匹配也可能不匹配解析它的输入(如果它发生的话)。

但是 printf '%s[=14=]' 是明确且可预测的——它打印每个字符串(在本例中为文件名)后跟一个 NULL 字符,这正是 xargs -0 作为输入的内容,所以没有机会混淆或错误解析。

好吧,有一种极端情况:如果没有任何匹配的文件,通配符模式将按字面意思传递,最终会尝试 运行 脚本未展开的字符串 "file_list*.dat" 作为参数。如果你想避免这种情况,请在此命令之前使用 shopt -s nullglob(然后使用 shopt -u nullglob,以返回正常模式)。

哦,还有一件事:sh script.sh 不是 运行 脚本的最佳方式。在开头给脚本一个适当的 shebang 行(#!/bin/sh 如果它只使用基本的 shell 功能,#!/bin/bash#!/usr/bin/env bash 如果它使用任何 bashisms), 运行 和 ./script.sh.