file1
2、6、7行を各行の値に置き換えて、次のようなfile2
系列を作成したいと思います。wc -l file2
cat file1
w
3
y
G
7
1.2
Q
cat file2
1 1 1
6 6 7
5 6 5
予想される結果:
cat out1
w
1
y
G
7
1
1
cat out2
w
6
y
G
7
6
7
cat out3
w
5
y
G
7
6
5
答え1
awk '
FNR == NR { data[++n] = $0; next }
{
data[2] = $1; data[6] = $2; data[7] = $3;
outname = sprintf("out%d", FNR) # or: outname = "out" FNR
for (i = 1; i <= n; ++i)
print data[i] >outname
close(outname)
}' file1 file2
file1
この内容を最初に読み、次に読みますfile2
。
file1
(チャンクとして)読み取り中にFNR == NR
コードが行う唯一の作業は、awk
各行を配列に保存することですdata
。
読み取ると、file2
コードはファイルの1行にある3つのフィールドをそれぞれ取得し、変更する行に対応するdata
インデックスに割り当てますfile1
。
保存された行は現在の行番号を取り、その前に文字列を追加して設定されたファイル名data
で印刷されます。file2
out
close(outname)
awk
これは、実際にはGNU以外のものを使用し、記録されたawk
ファイル数が開かれたファイル記述子制限を超える場合にのみ必要です(返された数を超え、ulimit -n
標準ストリームの場合は3つ減算)。
テスト:
$ tree
.
|-- file1
`-- file2
0 directory, 2 files
$ awk '
FNR == NR { data[++n] = $0; next }
{
data[2] = $1; data[6] = $2; data[7] = $3;
outname = sprintf("out%d", FNR)
for (i = 1; i <= n; ++i)
print data[i] >outname
close(outname)
}' file1 file2
$ tree
.
|-- file1
|-- file2
|-- out1
|-- out2
`-- out3
0 directory, 5 files
$ paste out[123]
w w w
1 6 5
y y y
G G G
7 7 7
1 6 6
1 7 5
答え2
$ cat tst.awk
BEGIN {
split("2 6 7",tmp)
for (fldNr in tmp) {
map[tmp[fldNr]] = fldNr
}
}
NR==FNR {
rows[++numRows] = $i
next
}
{
out = "out" FNR
for (rowNr=1; rowNr<=numRows; rowNr++) {
print (rowNr in map ? $(map[rowNr]) : rows[rowNr]) > out
}
close(out)
}
$ awk -f tst.awk file1 file2
$ head out?
==> out1 <==
w
1
y
G
7
1
1
==> out2 <==
w
6
y
G
7
6
7
==> out3 <==
w
5
y
G
7
6
5
答え3
使用GNU sedout_0/1/2 ファイル内の file2 の各行の出力を取得します。
tmpf=$(mktemp) i=0
while read -ra a <&3
do
printf '%s\n' "${a[@]}" > "$tmpf"
sed -ne "
$(printf '%dba\n' 2 6 7)
p;d;:a
R $tmpf
" file1 > "out_$i"
(( i++ ))
done 3< file2
- whileループからfile2を読み取り、スペースで区切られたフィールドを改行区切りフィールドに変換して一時ファイルに保存します。
- get sed は、目的の出力を得るために file1 の行 2,6,&7 で R コマンドを呼び出します。