次のような統合分析形式に変更したいタブ区切りのモデル入力ファイルがあります。
入力.txt
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.5
abies_grandis 2.5 0.4
larix_occidentalis 1.5 0.3
次のように、1行に1つずつ別の乗数ファイルがあります。
乗数.txt
0.5
0.6
0.7
あるフィールド(wsg)に2番目のファイルの単一の乗数を掛ける一連の新しい入力ファイルを作成したいと思います。この例では、3つの乗数に対応する3つの新しいファイルがあります。出力ファイルは次のとおりです。
ファイル1.txt(wsg * 0.5)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.25
abies_grandis 2.5 0.2
larix_occidentalis 1.5 0.15
ファイル2.txt(wsg * 0.6)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
ファイル3.txt(wsg * 0.7)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
これはawkとforループを使用して可能なようですが、これを行うのに必要なレベルまでawkを知りません。この問題にどのように対処する必要がありますか?
答え1
現在持っている乗数に関係なく、すべてのUnixシステムのすべてのシェルでawkを使用してください。
$ ls *.txt
input.txt multipliers.txt
$ cat tst.awk
NR==FNR {
if ( pastHdr ) {
++numLines
wsg[numLines] = $NF
sub(/[[:space:]][^[:space:]]+$/,"")
rest[numLines] = $0
}
else {
hdr = hdr $0 ORS
if ( $1 == "***" ) {
pastHdr = 1
}
}
next
}
{
out = "file" FNR ".txt"
printf "%s", hdr > out
for (lineNr=1; lineNr<=numLines; lineNr++) {
print rest[lineNr], wsg[lineNr] * $0 > out
}
close(out)
}
$ awk -f tst.awk input.txt multipliers.txt
$ ls *.txt
file1.txt file2.txt file3.txt input.txt multipliers.txt
$ head file*.txt
==> file1.txt <==
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.25
abies_grandis 2.5 0.2
larix_occidentalis 1.5 0.15
==> file2.txt <==
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
==> file3.txt <==
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
上記は非常に似ています。@guest_7が投稿したソリューション、私がこの記事を投稿する理由は次のとおりです。
- 多くの単一文字変数名を使用すると、IMHOこのサイズのスクリプトは初心者が理解するのが難しくなります。
- wsg値を削除します
NF--
が、NFを減らすことは未定義の動作であるため、移植性はありません。 - ヘッダーの行数をハードコードします。 (これは間違っていないかもしれません。テキストを解析して決定することは私が好むものですが、実際の入力が常に投稿された例と同じかどうかによって間違っている可能性があります。そうでない場合は何ですか?違い)。
答え2
乗算は、6行目の後の最後のスペースで区切られたフィールドで正確に発生する必要があると仮定しますinput.txt
。単純なシェルループを使用してください。
count=0
while IFS= read -r mult; do
count=$(( count + 1 ))
awk -v mult="$mult" 'NR >= 6 { $NF *= mult }; 1' <input.txt >"file$count.txt"
done <multipliers.txt
これはループの各反復から乗数を読み取り、それをmultipliers.txt
行6()の後の最後のフィールド()値に適用します。次に、変更するかどうかにかかわらず、各行を印刷します(末尾が実行するアクションです)。$NF
NR >= 6
1
出力ファイル名は、静的接頭辞、file
カウンタ、および静的接尾辞としてcount
生成されます.txt
。
必要に応じてファイルを削除できますmultipliers.txt
(常に小さな定数乗数がある場合)。
count=0
for mult in 0.5 0.6 0.7; do
count=$(( count + 1 ))
awk -v mult="$mult" 'NR >= 6 { $NF *= mult }; 1' <input.txt >"file$count.txt"
done
答え3
input.txtファイルには6行しかないので、awk配列として読み込みます。
awk '
NR==FNR {
if (NR<6) {h=h sep $0}
else {
n++; b[n]=$NF
$NF=""; a[n]=$0
}
sep = ORS
next
}
{
close(f); f = fp($1)
print h > f
for (i=1; i<=n; i++) {
print a[i] b[i]*$1 > f
}
}
function fp(m) {
sub(/[.]/, "p", m)
return "file@mult=" m ".txt"
}
' input.txt multipliers.txt
結果:
.
├── file@mult=0p5.txt
├── file@mult=0p6.txt
├── file@mult=0p7.txt
├── input.txt
└── multipliers.txt
::::::::::::::
file@mult=0p5.txt
::::::::::::::
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.25
abies_grandis 2.5 0.2
larix_occidentalis 1.5 0.15
::::::::::::::
file@mult=0p6.txt
::::::::::::::
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
::::::::::::::
file@mult=0p7.txt
::::::::::::::
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
答え4
j=1; while read i; do awk -v i="$i" 'NR>5{$NF=$NF*i}1' input.txt >file$j.txt\(wsg*"$i"\);j=$(($j+1)); done < multipliers.txt
出力
@praveen:~$ cat file1.txt\(wsg\*0.5\)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.25
abies_grandis 2.5 0.2
larix_occidentalis 1.5 0.15
===========
praveen@praveen:~$ cat file2.txt\(wsg\*0.6\)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.3
abies_grandis 2.5 0.24
larix_occidentalis 1.5 0.18
========
praveen@praveen:~$ cat file3.txt\(wsg\*0.7\)
/* Preciptation in mm */
10 30 40 50 23
### Species description
*** sp_name LMA wsg
abies_lasiocarpa 2 0.35
abies_grandis 2.5 0.28
larix_occidentalis 1.5 0.21
Python
#!/usr/bin/python
mu=open('Multipliers.txt','r')
ik=open('input.txt','r')
t=ik.readlines()
d=1
for g in mu:
er=open("file{0}.txt(wsg*{1})".format(d,g.strip()),'w')
for h in range(0,len(t),1):
if (int(h) < 5):
print t[h].strip()
er.write(t[h].strip())
er.write('\n')
else:
k=t[h].split(' ')
co=float(k[-1].strip())*float(g)
print " ".join(k[0:-1])+" "+str(co)
er.write(" ".join(k[0:-1])+" "+str(co))
er.write('\n')
d=d+1