列の2つの連続した行を追加し、前の行に分割して印刷します。

列の2つの連続した行を追加し、前の行に分割して印刷します。

ほぼ2000行の入力ファイルがあります。計算をして3番目の列に印刷する必要があります。

入力ファイルに関連する操作の例:

n ID1_1 n/(n+k)
k ID1_2

入力ファイル:

 10 ID1_1
 20 ID1_2
  1 ID3_1
  9 ID3_2
 20 ID20_1
 15 ID2_1
300 ID2_2

予想出力:

 10 ID1_1 0.33
 20 ID1_2 
200 ID3_1 0.11
  9 ID3_2
 20 ID20_1 /*I would just leave it like that*/
 15 ID2_1 0.047
300 ID2_2

簡単な解決策がありますか?ありがとうございます。

答え1

表示された入力を考慮すると、次のことが機能します。

<infile sed -e '$!N;2i\' -e '3k 
s|\(\(.*  *\).*_1\)\n\(\(.*  *\).*_2\)$|[\1 ]P\2d\4+/p[\3]pc|;t
s|^[ _ID0-9]*|[&]pc|;P;D' | dc

私のために印刷されます...

 10 ID1_1 .333
 20 ID1_2
  1 ID3_1 .100
  9 ID3_2
 20 ID20_1
 15 ID2_1 .047
300 ID2_2

...dc精度を3に設定しましたが、精度が10だからです...

 10 ID1_1 .3333333333
 20 ID1_2
  1 ID3_1 .1000000000
  9 ID3_2
 20 ID20_1
 15 ID2_1 .0476190476
300 ID2_2

出力精度に加えて、あなたの精度とは異なります。期待される出力3行目 - しかし、これは質問のタイプミスのためのようです。

とにかく、これを理解するには、まず出力を2つの形式に解析する必要があることを考慮する必要があります。dc次のewlineなしでaを印刷するdcか、数字または1でaを印刷します。マクロで実行する以外は文字列として何もできません。しかし、数値を見ると非常に能力に優れています。P[string]\np[string]xdc

したがって、現在の行が最後の行の場合は、sedまず$!N現在の行に追加の行を追加します。 2行目はstdoutに文字列を挿入します。これは精度を3に設定するコマンドです。!$i3kdc

その後、交換しようとしています。

s|\(\(.*  *\).*_1\)\n\(\(.*  *\).*_2\)$|[\1 ]P\2d\4+/p[\3]pc|

_1これは、パターンスペースに現在少なくとも1つのスペースが含まれている場合にのみ成功します。ある地点ではすぐ後ろに並んだ文字が続き\n、ある地点ではその後に少なくとも1つの空白が続き、ある地点では直後に末尾が_2続き$ます。パターン空間の

これは、上記の置換が次の行のペアにのみ影響することを意味します。

...ID_1
...ID_2

...他の人でもありません。影響がある場合は、コンテンツを利用可能なdcスクリプトに変換します。次に、t交換が成功したことを確認し、成功すると、スクリプトから分岐して交換結果を印刷し、sedコマンドを実行しなくなります。標準出力を標準入力としてdc使用するため、たとえば、最初の2行を次のように変更します。sedsed

[ 10 ID_1 ]P10d20+/p[ 20 ID_2]pc

...dc次に、その入力を次のように処理します。

  • [ 10 ID_1 ]- 角かっこの間の文字列をスタックの一番上にスライドさせます。(これを行うと、すでにスタック内のすべてのアイテムが1つ下にプッシュされます。)
  • PP- 後ろに並んでいないスタックの上部を印刷して\nポップします。(これを行うと、下のスタックのすべての値が1ずつ増加します。)
  • 10- 数字10をスタックの一番上にスライドさせます。
  • dd- スタックの上部をコピーします。
  • 20- 数字20をスタックの一番上にスライドさせます。
  • +- スタックの上部に2cdを追加し、スタックの上部に2cdを追加します。(2つを同時に爆発させる)そして結果をスタックの一番上にスライドさせます。
  • /- スタックの上から2cdを分割します。(今私たちはdコピーします10スタックの上から(私たちの10 20 +結果) (2つを同時に爆発させる)そして結果をスタックの一番上にスライドさせます。
  • pp- スタックの上部を印刷します。(揚げずに)その後に行が表示されます\n
  • [ 20 ID_2]- 文字列をスタックの一番上にスライドさせます。
  • pp- スタックの上部を印刷します。(もう一度言うが爆発しないでください)その後は\nEwlineが続く
  • cc- スタックを理解する

したがって、dc以下を印刷してください。

 10 ID1_1 .333
 20 ID1_2

ただし、sedすでに説明したように、成功した一致がなく、パターンスペースが変更された場合、処理する他の行が残ります。この場合、sedコマンドを追加してからの間に最初のシーケンスを挿入することもできます。次に、パターンスペースから最初に表示されるewlineまでパターンスペースを印刷し、残りの部分から始める前に同じ内容を削除します。したがって、全体的に1行の予測が実行され、ジョブスクリプトは常に印刷されます。[ ID_0-9]*[]pcP\nDseddcdc

これは、ファイル全体がストリームで処理されることを意味します。これは`dcsed` の両方が処理されると出力を提供するからです。これにより、入力が質問の例と似ている場合は、同じ方法で200万行を簡単に処理したり、リアルタイムでログファイルを処理したりできます。

答え2

Pythonで。

#!/usr/bin/python3
import re
import sys
fil = sys.argv[1]
with open(fil) as f:
    m = re.split(r'[\n\r]+(?= *\d+\s+ID\d+_1)', f.read())
    l = []
    for i in m:
        l.append(re.sub(r'(?s)^(\s*(\d+)\s+([^_]+)_1)([\n\r]+\s*(\d+)\s+\3_2)$', \
             lambda m: m.group(1) + " "+ str(float(m.group(2))/(float(m.group(2))+float(m.group(5)))) +  m.group(4),i))
    print('\n'.join(l), end = "")

上記のスクリプトを別の名前で保存してscript.py実行してみてください。

python3 script.py inputfile

例:

$ python3 f.py file
 10 ID1_1 0.3333333333333333
 20 ID1_2
  1 ID3_1 0.1
  9 ID3_2
 20 ID20_1
 15 ID2_1 0.047619047619047616
300 ID2_2

答え3

awk次のいずれかのコマンドですべての操作を実行できます。

$ awk '{if(NR%2){n=$1;last=$0;}else{print last,n/(n+$1)"\n"$0}}' file
10 ID1_1 0.333333
 20 ID1_2
  1 ID3_1 0.1
  9 ID3_2
 15 ID2_1 0.047619
300 ID2_2

アイデアは、単に現在の行が偶数であることを確認することです。 i)その場合は、last必要な計算で前の行()を印刷し、ii)そうでない場合は、現在の行をlast最初のフィールドとして保存しますn

以下を使用して、印刷される小数点以下の桁数を制御できますprintf

$ awk '{if(NR%2){n=$1;last=$0;}else{printf "%s %.2f\n%s\n",last,n/(n+$1),$0}}' file
10 ID1_1 0.33
 20 ID1_2
  1 ID3_1 0.10
  9 ID3_2
 15 ID2_1 0.05
300 ID2_2

Perlにも同じ基本内容があります。

$ perl -lane 'if($.%2){$n=$F[0];$last=$_;}
              else{printf "%s %.2f\n%s\n",$last,$n/($n+$F[0]),$_}' file
10 ID1_1 0.33
 20 ID1_2
  1 ID3_1 0.10
  9 ID3_2
 15 ID2_1 0.05
300 ID2_2

答え4

OP編集後(追加用語を参照):

awk '
/ID.*_1/{
    n=$1
    idx=$2
    sub("_1","_2",idx)
    printf s"%s",$0
    s="\n"}
$2==idx{
    printf " %.2f\n%s",n/(n+$1),$0}
END{
    print""}' file

関連情報