2つのファイル間の算術演算により、一連の新しいファイルが生成されます。

2つのファイル間の算術演算により、一連の新しいファイルが生成されます。

次のような統合分析形式に変更したいタブ区切りのモデル入力ファイルがあります。

入力.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が投稿したソリューション、私がこの記事を投稿する理由は次のとおりです。

  1. 多くの単一文字変数名を使用すると、IMHOこのサイズのスクリプトは初心者が理解するのが難しくなります。
  2. wsg値を削除しますNF--が、NFを減らすことは未定義の動作であるため、移植性はありません。
  3. ヘッダーの行数をハードコードします。 (これは間違っていないかもしれません。テキストを解析して決定することは私が好むものですが、実際の入力が常に投稿された例と同じかどうかによって間違っている可能性があります。そうでない場合は何ですか?違い)。

答え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()の後の最後のフィールド()値に適用します。次に、変更するかどうかにかかわらず、各行を印刷します(末尾が実行するアクションです)。$NFNR >= 61

出力ファイル名は、静的接頭辞、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        

関連情報