我有一个 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
忽略前导选项卡,如果我们关心哪些列缺少元素,则无法使用。