将多个命令行参数传递给带有文本文件的可执行文件

将多个命令行参数传递给带有文本文件的可执行文件

我有一个 C 可执行文件,它接受 4 个命令行参数。

program <arg1> <arg2> <arg3> <arg4>

我想创建一个 shell 脚本,它使用文本文件提供的参数持续运行可执行文件。这个想法是这样的:

./program "$(< arg1.txt)" "$(< arg2.txt)" "$(< arg3.txt)" "$(< arg4.txt)"

为运行提供的参数n将位于n每个文件的行上。当我尝试这样做时, printf() 调用相互干扰,或者发生了其他一些有趣的事情。我也愿意接受一种只接受一个文件的脚本,其中参数以某种方式分隔。

答案1

while 
  IFS= read -r a1 <&3 &&
    IFS= read -r a2 <&4 &&
    IFS= read -r a3 <&5 &&
    IFS= read -r a4 <&6
do
  ./program "$a1" "$a2" "$a3" "$a4" 3<&- 4<&- 5<&- 6<&-
done 3< arg1.txt 4< arg2.txt 5< arg3.txt 6< arg4.txt

这将运行循环,直到耗尽其中一个文件。将 s替换&&||s 运行它直到全部相反,文件已耗尽(对较短的文件使用空参数)。

使用 GNU xargs,您还可以执行以下操作:

paste -d '\n' arg[1-4].txt | xargs -n 4 -r -d '\n' ./program

(尽管要注意的./program是标准输入/dev/null

答案2

查看 sed 命令和粘贴命令的组合。首先,使用粘贴创建一个包含所有四个文件的新流。然后使用 sed 选择你想要的行:

paste arg1.txt arg2.txt arg3.txt arg4.txt | sed -n 10p

将打印粘贴输出的第 10 行。可以使用 xargs 将其作为参数提供给程序:

paste arg1.txt arg2.txt arg3.txt arg4.txt | sed -n 10p | xargs ./program

如果要循环遍历各行,可以使用 seq 命令生成序列,然后迭代序列中的每个值:

for i in $(seq 1 100); do 
    paste arg1.txt arg2.txt arg3.txt arg4.txt | sed -n ${i}p | xargs ./program
done

这个循环会很慢,因为它每次迭代都会调用一次 Paste。首先创建一个临时文件可能是个好主意。

答案3

最好的选择是预读取文件并将组织的结果存储在数组或临时文件中。否则,您将必须为每次迭代调用读取函数四次,并让该函数在文件中越来越远地读取。这远非最佳。

这是临时文件版本。注意,尚未经过测试。

PROG=./program
TEMPDIR=tmp
mkdir "$TEMPDIR"

# Create the temp files.
for arg in arg*.txt; do
    i=0
    while read a; do
        ((i++))
        printf "%s\n" "$a" >> "$TEMPDIR"/"$i"
    done < "$arg"
done

# Now the temp files are ready.
## Each file contains all arguments for 1 run of ./program,
## each of them on a separate line.

# Start executing the ./program.
for iteration in "$(ls "$TEMPDIR" | sort -n)"; do
    unset args
    while read arg; do
        args=( "$arg" )
    done < "$TEMPDIR"/"$iteration"
    "$PROG" "${args[@]}"
done

# Finally, remove the temp files.
rm -r "$TEMPDIR"

答案4

在 Bash(或其他支持$''和 数组的 shell)中,只要您的输入文件不包含制表符(*) ,就可以这样做:

IFS=$'\t'
paste arg1.txt arg2.txt | 
while read -r -a A ; do 
   [ "${#A[@]}" -eq 2 ] && printf "%s - %s\n" ${A[@]}
done 

paste将输入文件逐行粘在一起,read -a A将列读取到 array A,使用 tab (from IFS) 作为分隔符。[ "${#A[@]}" -eq 2 ]检查数组是否恰好有两个成员,并将${A[@]}它们放入 的命令行中printf。根据需要更改命令。

(* 如果您需要支持标签,我建议您使用 Perl)

使用这些输入文件:

$ cat arg1.txt 
foo bar
doo
$ cat arg2.txt 
one
two two
three three three

上面代码片段的输出是:

foo bar - one
doo - two two

最后一行将arg2.txt被忽略,因为arg1.txt没有相应的行。read忽略前导选项卡,如果我们关心哪些列缺少元素,则无法使用。

相关内容