首页 > 解决方案 > 使用 xargs 在带参数的多个输入列表上运行 bash 脚本

问题描述

我正在尝试在多个文件列表上运行脚本,同时还并行传递参数。我有 file_list1.dat、file_list2.dat、file_list3.dat。我想运行接受 3 个参数的 script.sh: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: terminate by signal 13

关于使用 xargs 将参数传递给 bash 脚本的正确语法的任何想法?

标签: bashxargs

解决方案


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

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\0' file_list*.dat | xargs -0 -P "$Ncores" -n 1 sh script.sh "$arg1" "$arg2" "$arg3"

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

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

printf '%s\0'它是明确且可预测的——它打印每个字符串(在这种情况下为文件名),后跟一个 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.


推荐阅读