4つのコマンドライン引数を受け入れるC実行可能ファイルがあります。
program <arg1> <arg2> <arg3> <arg4>
テキストファイルで提供される引数を使用して、実行可能ファイルを継続的に実行するシェルスクリプトを作成したいと思います。アイデアは次のとおりです。
./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
ファイルの1つが使い果たされるまでループが実行されます。 sをs&&
に置き換えて、||
次まで実行します。みんな代わりにファイルが使い果たされます(短いファイルの場合は空の引数を使用)。
GNUを使用すると、xargs
次のこともできます。
paste -d '\n' arg[1-4].txt | xargs -n 4 -r -d '\n' ./program
(注意事項は./program
標準入力ですが/dev/null
)
答え2
sedコマンドとPasteコマンドの組み合わせを見てください。まず、貼り付けを使用して、4つのファイルをすべて含む新しいストリームを作成します。次に 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
このループは繰り返しごとに貼り付けを1回呼び出すため、遅くなります。まず、一時ファイルを作成することをお勧めします。
答え3
最善の方法は、ファイルを事前に読み、整理された結果を配列または一時ファイルに保存することです。それ以外の場合は、繰り返しごとに読み取り関数を4回呼び出し、関数がファイルを読み続けることができるようにする必要があります。これは最適ではありません。
一時ファイルのバージョンです。まだテストされていません。
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(または配列をサポートする他のシェル)では、入力ファイルにタブ文字(*)$''
が含まれていない限り、次のことができます。
IFS=$'\t'
paste arg1.txt arg2.txt |
while read -r -a A ; do
[ "${#A[@]}" -eq 2 ] && printf "%s - %s\n" ${A[@]}
done
paste
入力ファイルを1行ずつ連結し、タブを区切り文字として使用してread -a A
列を配列に読み込みます。配列に正確に2つのメンバーがあることを確認し、それをコマンドラインに入れます。必要に応じてコマンドを変更します。A
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