次のファイルがあります。
# Time-averaged data for fix avetimeall
# TimeStep Number-of-rows
# Row c_gyrationchunkall
1000 3
1 2.09024e-14
2 4.88628
3 5.69321
2000 3
1 2.10518e-14
2 8.33702
3 8.83162
3000 3
1 1.96656e-14
2 12.1396
3 11.5835
...
私のファイルでは、最初の3行は常にヘッダです。ヘッダーの後には、私のファイルに同じサイズのチャンクがリストされており、それぞれはタグサブヘッダーで始まります。各チャンクのデータがそのチャンクラベルの関連部分で始まる行に転送されるようにファイル内のデータを再構成し、そのチャンクの関連データ値をすべてスペースで区切ってリストしたいと思います。たとえば、上記の例を次のように変換したいとします。
# Time-averaged data for fix avetimeall
# TimeStep c_gyrationchunkall
1000 2.09024e-14 4.88628 5.69321
2000 2.10518e-14 8.33702 8.83162
3000 1.96656e-14 12.1396 11.5835
...
Bashでこれを行うにはどうすればよいですか? Bashの経験は少しありますが、この問題をすばやく処理するのに十分ではありません。
答え1
3
ブロックの行数が異なる可能性があるかどうかに関係なく、awkを使用してください。
$ awk '
NR == 2 { $3=""; saved=$0; next }
NR == 3 { $0=saved $3 }
NR < 4 { print; next }
!numLines {
numLines = $2
printf "%s%s", $1, OFS
next
}
{ printf "%s%s", $2, (--numLines ? OFS : ORS) }
' file
# Time-averaged data for fix avetimeall
# TimeStep c_gyrationchunkall
1000 2.09024e-14 4.88628 5.69321
2000 2.10518e-14 8.33702 8.83162
3000 1.96656e-14 12.1396 11.5835
以下の議論を続けてください。ザビエルGの答え読みやすさスタイルのデフォルト設定に関して、以下はシェルスクリプトと同じスタイルで書かれたawkスクリプトです(シェルスクリプトに含まれているため、外部でも同じように機能します)。しかし、はるかに速く実行されます*シェルスクリプトよりも強力で移植可能です。 :
$ cat ./script_filename
#!/usr/bin/env bash
awk '
BEGIN {
# Reformat comments:
getline first_line
print first_line
getline; split($0,line2)
getline; split($0,line3)
printf "# %s %s\n", line2[2], line3[3]
# Reformat data:
while ( getline > 0 ) {
timestep=$1; number_of_rows=$2
printf "%s", timestep
for ( i=1; i<=number_of_rows; i++ ) {
getline; row_value=$NF
printf " %s", row_value
}
print ""
}
}
'
$ ./script_filename < input
# Time-averaged data for fix avetimeall
# TimeStep c_gyrationchunkall
1000 2.09024e-14 4.88628 5.69321
2000 2.10518e-14 8.33702 8.83162
3000 1.96656e-14 12.1396 11.5835
*以下は、90,000個のOPレコードを含むファイルでbashスクリプトと上記のawkスクリプトを3回目に実行したタイミングの結果です。
$ time ./script_bash < file > /dev/null
real 0m9.425s
user 0m5.062s
sys 0m4.139s
$ time ./script_awk < file > /dev/null
real 0m0.265s
user 0m0.171s
sys 0m0.000s
答え2
使用幸せ(以前のPerl_6)
skip
ヘッダー行を一時的に忘れるために使用されます。
~$ raku -e 'my @a = lines.skip(3).rotor(4, partial => True).map: *.words; .[0,3,5,7].put for @a;' file
#OR
~$ raku -e 'my @a = lines.skip(3).batch(4).map: *.words; .[0,3,5,7].put for @a;' file
上記は、Perlシリーズのプログラミング言語であるRakuで書かれた答えです。つまり、最初の 3 つのヘッダー行を読み込んでlines
ping します。ファイルの末尾にある最後の「スピン」を含むskip
4行ごとに一緒にrotor
編集されます。その間、各/をスペースで区切ってみましょう。batch
partial
rotor
batch
words
これらのローター/配置の4行のそれぞれは、余白から分離され、という@
署名配列に格納されます@a
。最後に(2番目のステートメントで)for
各位置を使用して@a
繰り返しput
、不要な要素を削除するように注意します(インデックス角かっこを介して[0,3,5,7]
)。
入力例:
# Time-averaged data for fix avetimeall
# TimeStep Number-of-rows
# Row c_gyrationchunkall
1000 3
1 2.09024e-14
2 4.88628
3 5.69321
2000 3
1 2.10518e-14
2 8.33702
3 8.83162
3000 3
1 1.96656e-14
2 12.1396
3 11.5835
出力例:
1000 2.09024e-14 4.88628 5.69321
2000 2.10518e-14 8.33702 8.83162
3000 1.96656e-14 12.1396 11.5835
put
ヘッダーラインに関しては、2つのステートメントでRakuコードを起動するのは簡単ですput "Time-averaged data...";
。ただし、実際には、OPに必要な出力を提供するタスクです。
~$ raku -e 'lines[0].put; .words[0..1, *-1].put for lines[0..1].rotor(2); \
my @a = lines.rotor(4, partial => True).map: *.words; \
.[0,3,5,7].put for @a;' file
## Time-averaged data for fix avetimeall
# TimeStep c_gyrationchunkall
1000 2.09024e-14 4.88628 5.69321
2000 2.10518e-14 8.33702 8.83162
3000 1.96656e-14 12.1396 11.5835
答え3
使用AWK:
$ awk '
NR==2{sub(/[[:space:]]+[^[:space:]]+$/,"");rec = $0; next}
NR==3{$0 = rec OFS $NF};
NR<4;
NR>3{printf "%s", (NR%4==0) ? ((NR==4) ? "" : ORS) $1 : ($1="")$0 }
END{if (NR)print ""}'
$ awk '
NR==2{sub(/[[:space:]]+[^[:space:]]+$/,"");rec = $0; next}
NR==3{$0 = rec OFS $NF};
NR<4;
$NF ~ /^[0-9]+$/{a=$NF;n=NR+a; sub(/[[:space:]]+[^[:space:]]+$/,""); printf "%s", $0; next}
NR<=n{$1 =""; printf "%s", $0((NR==n) ? ORS : "") }'
答え4
質問に記載されている警告に基づいてサンプル入力をq762948ファイルとして使用すると、単純なawkコマンドを使用してこれを実行できます。
$ head -2 q762948 >result.txt
# dump the comments as required
$ tail +4 q762948 | awk '{c=(NR-1)%4} c==0{p=$1;print ""} c>0{p=$2}{printf p" "}'>>result.txt
$ cat result.txt
# Time-averaged data for fix avetimeall
# TimeStep Number-of-rows
1000 2.09024e-14 4.88628 5.69321
2000 2.10518e-14 8.33702 8.83162
3000 1.96656e-14 12.1396 11.5835