1

次の方法で 2 つの異なるファイルを比較するために、bash コードを書きたいと思います。最初の 5 列の値が両方のファイルで等しい場合は、2 つの異なるファイルの残りの列の値を合計します (例: colum6file1 + colum6file2 など)。それらが異なる場合は、新しいファイルに異なる行の両方を保持してください。最初のファイルの先頭にある行は、2 番目のファイルの末尾にある行と同じ 4 列の値を持つ可能性があるため、行ごとに比較できないことに注意してください。

これが明確であることを願っています、

ありがとう。

ファイル1:

  118    2   AA      4.25     30.25  1  
  119    2   AA      4.50     30.25  2  
  120    2   AA      4.75     30.25  3  
  121    2   AA      5.00     30.25  4  
  122    2   AA      5.25     30.25  5  
  123    2   AA      5.50     30.25  6    
  124    2   AA      5.75     30.25  7   
  125    2   AA      6.00     30.25  8    
  126    2   AA      6.25     30.25  9  

ファイル 2:

  179    1   BB     19.75     30.00  1  
  180    1   BB     19.75     30.00  2  
  230    1   BB     32.25     30.00  3   
  231    1   BB     32.50     30.00  4      
  232    1   BB     32.75     30.00  5   
  118    2   AA      4.25     30.25  6   
  119    2   AA      4.50     30.25  7  
  120    2   AA      5.00     30.25  8   
  121    2   AA      5.00     30.25  9   

出力:

  118    2   AA      4.25     30.25  7    
  119    2   AA      4.50     30.25  9    
  120    2   AA      4.75     30.25  11    
  121    2   AA      5.00     30.25  13    
  122    2   AA      5.25     30.25  5  
  123    2   AA      5.50     30.25  6    
  124    2   AA      5.75     30.25  7   
  125    2   AA      6.00     30.25  8    
  126    2   AA      6.25     30.25  9  
  179    1   BB     19.50     30.00  1    
  180    1   BB     19.75     30.00  2  
  230    1   BB     32.25     30.00  3   
  231    1   BB     32.50     30.00  4      
  232    1   BB     32.75     30.00  5   
4

3 に答える 3

2

これはおそらく最小限に抑えることができますが、ここに私が問題だと思うものの解決策の大まかなカットがあります:

sort file1 file2 |
  awk '{current = sprintf("%s %s %s %s %s", $1, $2, $3, $4, $5)

      if (current == previous) {
        total = total + $6
      } else if (previous) {
        printf("%s %d\n", previous, total)
        total = $6
      } else {
        total = $6
      }

      previous = current
    }
    END { printf("%s %d\n", previous, total) }'
于 2012-06-14T14:52:58.123 に答える
0

コマンドを使用しsedて最初の列のみを取得し、それを比較できます。

sed チュートリアル

それで:sed -e "s/([0-9]*\)\s.*/\1/"

最初の数字を取得します(他のものとは—空白文字で区切られ\sています)基本的にはs/match pattern/replacement/.

/( /)いくつかのテキストまたはパターンの出現をマークし、\<number>それを文字列の置換で使用するために使用します。置換文字列として、\1最初の (そして唯一の) マーク付きフラグメントをそのまま使用しました。

ここで使用したように:最初の番号([0-9]*)を見つけてマークし、空白(\s)で区切って、残りの行を置き換えました.*

于 2012-06-14T14:59:32.410 に答える
0

これが解決策です。エレガントなのかひどいのかわかりません。joinコマンド (したがってコマンドも) を悪用しsort、さらにawk.

file1=xx1
file2=xx2

join -t ' ' -j 1  -a 1 -a 2 -o 1.1,2.1,1.2,2.2 \
    <(sort -b $file1 | awk '{printf("%s\t%s\t%s\t%s\t%s %s\n",$1,$2,$3,$4,$5,$6)}') \
    <(sort -b $file2 | awk '{printf("%s\t%s\t%s\t%s\t%s %s\n",$1,$2,$3,$4,$5,$6)}') |
awk '{
    if (NF == 6) sum = $6;
    else         sum = $11 + $12;
    print $1, $2, $3, $4, $5, sum;
}'

ファイル名はパラメーターです。の<(sort -b $fileN | awk '...')特徴である「プロセス置換」ですbash。これは「括弧内のコマンドを実行する」ことを意味し、パイプラインの標準出力は名前付きファイル (通常は/dev/fd/NN) としてコマンドに提供されます。この場合はjoin. パイプラインはよこしまです。データを並べ替えてawkから、キー フィールド (最初の 5 つのフィールド) がタブで区切られ、6 番目のフィールドが空白で区切られるようにデータをフォーマットします。はフィールドのsort -b先頭の空白を無視します。それは正気の結果を得るために重要です。

このjoinコマンドは空白をフィールド セパレータ ( ) として扱う-t ' 'ため、入力ファイルにはそれぞれ 2 つのフィールドがありますjoin。結合は、最初のフィールドが等しい場合に発生します-j 1(最初のフィールドはタブで区切られた 5 つの値のセットであることを思い出してください)。-a 1出力には、ファイル 1 ( ) とファイル 2 ( )からの一致しないエントリが含まれます-a 2。出力形式は、ファイル 1 からフィールド 1、ファイル 2 からフィールド 1、ファイル 1 からフィールド 2、ファイル 2 からフィールド 2 です。

一致する場合、出力には、空白またはタブで区切られた多数の列が含まれます。一致するものがない場合、出力には空白またはタブで区切られた半ダースの列が含まれます。

の後処理でawkは、空白とタブがどちらもフィールドの区切り文字であるという事実を利用していますawk。入力行に 6 つのフィールドがある場合、そのキーに一致するものがなかったため、合計が の値になり$6ます。入力行にその他の数のフィールドがある場合 (12 にする必要があります)、合計は最後の 2 つのフィールドの値になります$11 + $12。次に、スクリプトは最初の 5 つのフィールドと合計を出力します。

フィールド区切りとして空白とタブを使用するこのトリックは、おそらくグロテスクですが、このコンテキストではかなり効果的です。

サンプル データでは、特定のキー (最初の 5 列は各ファイルで一意) を持つ各ファイルに最大 1 行あるため、joinファイル 1 の N 行とファイル 2 の M 行をペアにして NxM 出力を与えるという事実必要に応じて N = 1 および M = 1 であるため、行は重要ではありません。

出力例

質問に示されているデータ ファイル (およびファイル内のスクリプトjb.sh)を考えると、次のようになります。

$ bash jb.sh
118 2 AA 4.25 30.25 7
119 2 AA 4.50 30.25 9
120 2 AA 4.75 30.25 3
120 2 AA 5.00 30.25 8
121 2 AA 5.00 30.25 13
122 2 AA 5.25 30.25 5
123 2 AA 5.50 30.25 6
124 2 AA 5.75 30.25 7
125 2 AA 6.00 30.25 8
126 2 AA 6.25 30.25 9
179 1 BB 19.75 30.00 1
180 1 BB 19.75 30.00 2
230 1 BB 32.25 30.00 3
231 1 BB 32.50 30.00 4
232 1 BB 32.75 30.00 5
$

この出力は目的の出力と同一ではないことに注意してください。これは、目的の出力が指定された入力に対して誤っているためです (または、目的の出力に対して入力が誤っているためです)。サンプル データには次の行があります。

120 2   AA  4.75    30.25  3 
120 2   AA  5.00    30.25  8

列 4 はここでは同じではない (4.75 対 5.00) ため、これらの行を結合することはできず、'120' に対して 2 つの出力行が得られることに注意してください。


16列に拡張

スクリプトは少し整理されていますが、それ以外は以前と同じパターンが続きます。

file1=xx1
file2=xx2

sort_print()
{
    sort -b "$@" |
    awk '{printf("%s\t%s\t%s\t%s\t%s %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
                 $1,$2,$3,$4,$5, $6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)}'
}

join -t ' ' -j 1  -a 1 -a 2 -o 1.1,2.1,1.2,2.2 \
    <(sort_print $file1) <(sort_print $file2) |
tee joined.data |
awk '{
    if (NF != 16)
    {
        for (i = 6; i <= 16; i++)
        {
            j = i + 16
            $i = $i + $j;
        }
    }
    printf "%s %s %s %s %s", $1, $2, $3, $4, $5;
    for (i = 6; i <= 16; i++)
        printf " %s", $i;
    printf "\n";
}'

ファイルxx1

118    2   AA      4.25     30.25  1  2 3 4 5 14 5 4 5 7 8
119    2   AA      4.50     30.25  2  2 3 4 5 4 15 4 5 7 8
120    2   AA      5.00     30.25  3  2 3 4 5 4 5 14 5 7 8
121    2   AA      5.00     30.25  4  2 3 4 5 4 5 4 15 7 8
122    2   AA      5.25     30.25  5  2 3 4 5 4 5 4 5 17 8
123    2   AA      5.50     30.25  6    2 13 4 5 4 5 4 5 7 18
124    2   AA      5.75     30.25  7   2 3 4 5 4 5 4 5 7 18
125    2   AA      6.00     30.25  8    12 3 4 5 4 5 4 5 7 18
126    2   AA      6.25     30.25  9  2 3 4 5 4 5 4 5 7 18

ファイルxx2

179    1   BB     19.75     30.00  1   8 21 2 4 12 2 3 1 9 1032
180    1   BB     19.75     30.00  2  29 1 22 4 12 2 3 1 9 1042
230    1   BB     32.25     30.00  3   9 8 2 44 12 2 3 1 9 1052
231    1   BB     32.50     30.00  4   9 17 2 44 12 2 3 1 9 1062
232    1   BB     32.75     30.00  5   9 8 1 4 122 2 3 1 9 1072
118    2   AA      4.25     30.25  6   9 8 1 2 4 22 3 1 9 1082
119    2   AA      4.50     30.25  7  29 8 1 2 4 12 23 1 9 1092
120    2   AA      5.00     30.25  8   9 8 1 2 4 12 2 21 9 1002
121    2   AA      5.00     30.25  9   9 8 1 2 4 12 2 3 29 1012

出力

118 2 AA 4.25 30.25 124 11 8 5.25 32.25 5 24 6 5 14 1096
119 2 AA 4.50 30.25 126 31 8 5.5 32.25 6 14 26 5 14 1096
120 2 AA 5.00 30.25 128 11 8 6 32.25 7 14 5 25 14 1006
121 2 AA 5.00 30.25 130 11 8 6 32.25 8 14 5 7 34 1016
122 2 AA 5.25 30.25 5 2 3 4 5 4 5 4 5 17 8
123 2 AA 5.50 30.25 6 2 13 4 5 4 5 4 5 7 18
124 2 AA 5.75 30.25 7 2 3 4 5 4 5 4 5 7 18
125 2 AA 6.00 30.25 8 12 3 4 5 4 5 4 5 7 18
126 2 AA 6.25 30.25 9 2 3 4 5 4 5 4 5 7 18
179 1 BB 19.75 30.00 1 8 21 2 4 12 2 3 1 9 1032
180 1 BB 19.75 30.00 2 29 1 22 4 12 2 3 1 9 1042
230 1 BB 32.25 30.00 3 9 8 2 44 12 2 3 1 9 1052
231 1 BB 32.50 30.00 4 9 17 2 44 12 2 3 1 9 1062
232 1 BB 32.75 30.00 5 9 8 1 4 122 2 3 1 9 1072
于 2012-06-14T18:21:37.027 に答える