如何从文件传递命令行参数

Posted

技术标签:

【中文标题】如何从文件传递命令行参数【英文标题】:How to pass command line parameters from a file 【发布时间】:2011-09-28 22:17:14 【问题描述】:

我有一个从 argv 读取命令行参数的 C 程序。是否可以制作管道将文件的内容作为命令行参数重定向到我的程序?假设我有一个文件arguments.dat,内容如下:

0 0.2 302 0

我希望我的程序被调用:

./myprogram 0 0.2 302 0

我尝试了以下方法:

cat arguments.dat | ./myprogram

没有成功。

【问题讨论】:

【参考方案1】:

xargs 是你的答案:

cat arguments.dat | xargs ./myprogram

或者更简单:

xargs -a arguments.dat ./myprogram

查看手册了解自定义xargs 的多种方法。例如,您可以逐行而不是逐字阅读,并且可以在更复杂的替换中使用参数。

【讨论】:

这里有一些注意事项——如果你的文件包含的参数多于单个命令行(请记住,环境变量和命令行参数使用相同的空格)——所以@987654325 @ing 太多或太大的命令行变量会减少最大命令行长度),xargs 将多次运行 ./myprogram,在调用之间拆分参数。 @CharlesDuffy:好点子。这可能是一个错误,也可能是一个非常需要的功能,具体取决于用例。无论如何,我添加了另一种机制。 @CharlesDuffy:是的,确实如此。 Bash 还有一种方法可以让您使用编辑器编辑命令行。 xargs 有许多先进的操作方式,可以让你引用参数并逐行阅读等等。 @CharlesDuffy:是的,这绝对是我在可重用脚本中所做的。但是,如果它是一次性使用,您大致知道参数是什么,那么简单的 xargs 通常就是您所需要的。 当然。我试图就正确性提出一个论点,因为 *** 的答案本质上是可重复使用的——它(理想情况下)会被很多人阅读和使用(在很多不同的场景中,其中一些用例可能与 OP 不同),因此花在正确处理细节上的时间和精力是非常值得的。也就是说,如果我应该添加一个竞争性答案,请随时告诉我。 :)【参考方案2】:

对于大多数 shell,您可以使用 $(<filename) 将文件的内容插入命令行:

./myprogram $(<arguments.dat)

如果您的 shell 不支持,那么其中一种较旧的方法将起作用:

./myprogram $(cat arguments.dat)
./myprogram `cat arguments.dat`   # need this one with csh/tcsh

(您确实知道命令行参数和文件输入之间的区别,对吧?您为什么希望将命令行参数通过管道传递到程序中?)

【讨论】:

“旧方式”不会拆分参数。文件中的所有数据都将作为单个参数加载。 @osgx:这根本不是真的。要使其成为单个参数,您需要将其放在双引号内。 如果您的文件包含"first argument" "second argument",这会将"first 作为一个参数,argument" 作为第二个参数,"second 作为第三个参数。如果它包含*.txt,它将用文本文件列表替换它,而不是保持原样。如果文件包含"*.txt",引号将作为字符串的文字部分传递(if 用户没有nullglobfailglob 导致先验被视为失败的 glob...好吧,如果没有任何名称以文字双引号字符开头和结尾的文件,则失败)。【参考方案3】:

如果您不希望参数被静默分割

...也就是说:以下答案适用于不能将./myprogram --first-argument "first value" 静默更改为./myprogram --first-argument; ./myprogram "first value" 的情况。

如果你的参数是一对一的文字

也就是说,如果您的输入如下所示:

--first-argument
first value
--second-argument
second value

你的意思是这样运行:

./myprogram --first-argument "first value" --second-argument "second value"

...那么您应该使用(使用 bash 4.0 或更高版本):

readarray -t args <arguments.dat
./myprogram "$args[@]"

...或(对于 bash 3.x 也是如此):

args=( )
while IFS= read -r arg; do
  args+=( "$arg" )
done <arguments.dat
./myprogram "$args[@]"

如果您的参数带有引号或转义以区分它们

也就是说,如果您的文件包含类似的内容(请注意,换行符和不带引号的空格在此处的行为相同):

--first-argument "first value"
--second-argument "second value"

...你的意思是这样运行:

./myprogram --first-argument "first value" --second-argument "second value"

...那么你应该使用:

args=( )
while IFS= read -r -d '' arg; do
  args+=( "$arg" )
done < <(xargs printf '%s\0' <arguments.dat)

如果你控制你的参数格式

使用 NUL 分隔的值。也就是这样创建文件:

printf '%s\0' "argument one" "argument two" >arguments.dat

...并解析如下:

args=( )
while IFS= read -r -d '' arg; do
  args+=( "$arg" )
done <arguments.dat
./myprogram "$args[@]"

这适用于所有可能的参数值,即使是带有文字换行符、文字引号、文字反斜杠或其他不可打印字符的参数值。 (在 UNIX 命令行中,文字 NUL 不可能,因为命令行由以 NUL 结尾的字符串组成;因此,NUL 是唯一可以完全安全地用于明确分隔字符串中的参数的字符) .


如果需要跨调用拆分参数

如果期望的结果(当文件中的参数多于可以传递给程序调用的参数时)是程序的多个不同调用,每个调用都接收参数的子集,则此小节是相关的。在这一系列案例中,xargs 是适合这项工作的工具。

如果在 GNU 平台上,您可能希望运行 xargs -a arguments.dat 而不是重定向标准输入;但是,BSD xargs 不支持此功能(如在 MacOS 上),因此此处未演示。

如果你的参数是一对一的文字

使用 GNU xargs(大多数 Linux 平台):

xargs -d $'\n' ./myprogram <arguments.dat

使用 BSD xargs(MacOS、FreeBSD/OpenBSD/等):

xargs -0 ./myprogram < <(tr '\n' '\0' <arguments.dat)

如果您的参数带有引号或转义以区分它们

xargs ./myprogram <arguments.dat

如果您生成了以 NUL 分隔的输入

xargs -0 ./myprogram <arguments.dat

【讨论】:

以上是关于如何从文件传递命令行参数的主要内容,如果未能解决你的问题,请参考以下文章

如何将参数从 bat 文件或命令行传递给 plpgsql 函数?

从带有命令行参数的批处理文件运行控制台应用程序,如何在运行时传递参数值? [复制]

如何将参数从 gradle exec 任务传递到命令行

命令行运行PHP文件时如何传递参数?

如何将参数从命令行传递到 python 脚本以读取和更新 json 文件中存在的某些键的值

WebDriverIO Selenium 将命令行参数从 config.js 文件传递​​到 Chrome