一致するIDと一致しないIDの最初の列

一致するIDと一致しないIDの最初の列

input.txt,Linuxシステムには、異なる列(区切り文字)を含む2つのファイルがあります。各ファイルの最初の列に報告されたIDを使用してこれらのファイルを結合するスクリプトがあります。このスクリプトは、出力内の最初のファイルのすべてのIDを保持し、2番目のファイルの一致するIDのみを保持します。最初のファイルのIDと一致しない2番目のファイルのIDを保持するオプションを追加して、このスクリプトを実装する必要があります。

例:

2931,C,-9.750,-2.550,57.910,-0.3,C
2932,C,-5.470,-0.200,51.550,0.9,C
2940,C,-10.860,-3.400,54.000,0.7,C
2941,S,-11.820,-13.550,55.070,2.1,S
2944,H,-3.770,-4.180,60.300,0.7,H

2.txtと入力してください

4304,N,-9.700,-7.680,58.330,-2.3,N
2940,S,-10.440,-3.450,54.270,2.2,S
2900,C,-13.655,-13.730,59.405,-1.5,C
2931,C,-9.910,-2.420,57.610,0.2,C

注文する:

join -t, -a1 -o auto <(sort input1.txt) <(sort input2.txt) > output.txt.txt

出力.txt

2931,C,-9.750,-2.550,57.910,-0.3,C,2931,C,-9.910,-2.420,57.610,0.2,C
2932,C,-5.470,-0.200,51.550,0.9,C,,,,,,,
2940,C,-10.860,-3.400,54.000,0.7,C,2940,S,-10.440,-3.450,54.270,2.2,S
2941,S,-11.820,-13.550,55.070,2.1,S,,,,,,,
2944,H,-3.770,-4.180,60.300,0.7,H,,,,,,,

2つの出力ファイルを取得するためにコマンドを変更したいと思います。最初の項目は今受け取るものと似ていなければなりませんが、IDも一致してはいけません。

final.txt 出力

2931,C,-9.750,-2.550,57.910,-0.3,C,2931,C,-9.910,-2.420,57.610,0.2,C
2932,C,-5.470,-0.200,51.550,0.9,C,,,,,,,
2940,C,-10.860,-3.400,54.000,0.7,C,2940,S,-10.440,-3.450,54.270,2.2,S
2941,S,-11.820,-13.550,55.070,2.1,S,,,,,,,
2944,H,-3.770,-4.180,60.300,0.7,H,,,,,,,
,,,,,,,2900,C,-13.655,-13.730,59.405,-1.5,C
,,,,,,,4304,N,-9.700,-7.680,58.330,-2.3,N

他の出力ファイルには、一致しない次の行のみを含める必要がありますinput2.txt

出力2.txt

2900,C,-13.655,-13.730,59.405,-1.5,C
4304,N,-9.700,-7.680,58.330,-2.3,N

また、input2.txtで4000以上のIDを持つ行の最後の列要素のみを文字列「P」に置き換えるにはどうすればよいですか?

つまり、最初の行(ID = 4304)の最後の「C」を「P」に置き換えたいと思います。

出力.txt

4304,N,-9.700,-7.680,58.330,-2.3,P
2940,S,-10.440,-3.450,54.270,2.2,S
2900,C,-13.655,-13.730,59.405,-1.5,C
2931,C,-9.910,-2.420,57.610,0.2,C

答え1

ジョブ1:

IDファイルが一意であると仮定すると、awk 次のように使用できます。

awk -F, -v OFS=, '
    NR == FNR {
        m[$1] = $0 
        while (i++ <= NF) empty = OFS empty
        next
    }
    !m[$1]{$0 = $0 OFS empty}
    m[$1]{$0 = $0 OFS m[$1];delete m[$1]}
    1
    END{
        for ( i in m )
            if(m[i]) print empty, m[i]
    }
' file2 file1

ファイルを並べ替える必要はありません。公開フィールドが見つかるたびに配列から削除します。最後に、配列は表示されたコンテンツだけを保持します。file2


ジョブ2:

awk -F, 'NR == FNR {m[$1];next} !($1 in m)' file1 file2

出力リダイレクトを使用して、最初の2つの内容をシェルスクリプトに入れます。

#!/bin/bash

# first awk cmd
... > output1.txt

# Second awk cmd
... > output2.txt

答え2

joinすべてのフィールドを含めるように指示すると、最初に必要な出力ファイルを取得できます。このファイルは、両方のファイルのすべてのIDを含むファイルです。

$ join -t, -a1 -a2 -o 1.1,1.2,1.2,1.4,1.5,1.6,1.7,2.1,2.2,2.2,2.4,2.5,2.6,2.7 \
   <(sort input1.txt) <(sort input2.txt) 
,,,,,,,2900,C,C,-13.730,59.405,-1.5,C
2931,C,C,-2.550,57.910,-0.3,C,2931,C,C,-2.420,57.610,0.2,C
2932,C,C,-0.200,51.550,0.9,C,,,,,,,
2940,C,C,-3.400,54.000,0.7,C,2940,S,S,-3.450,54.270,2.2,S
2941,S,S,-13.550,55.070,2.1,S,,,,,,,
2944,H,H,-4.180,60.300,0.7,H,,,,,,,
,,,,,,,4304,N,N,-7.680,58.330,-2.3,N

順序はファイル内で見つかった順序であるため、表示されたものとは異なります(,,,,,,,2900...最初に表示されますsort input2.txt)。

,その後、最初の出力ファイルを解析し、1 つ以上の文字で始まる行を探して、2 番目の出力ファイルを取得できます。

$ join -t, -a1 -a2 -o 1.1,1.2,1.2,1.4,1.5,1.6,1.7,2.1,2.2,2.2,2.4,2.5,2.6,2.7 \
   <(sort input1.txt) <(sort input2.txt) | grep -oP '^,+\K.*'
2900,C,C,-13.730,59.405,-1.5,C
4304,N,N,-7.680,58.330,-2.3,N

このオプションは、行の一致部分のみを印刷するように-o指示し、Perl準拠の正規表現を有効にします。その後、PCREは「ここに一致するものはすべて無視」という意味を提供し、拡張部分のみを印刷できます。grep-P\K,

tee最初の出力をファイルに書き込み、それを標準出力に書き込む2つのファイルを作成する単一のコマンドにまとめることができ、次に上記のようにgrep実行できます。

join -t, -a1 -a2 -o 1.1,1.2,1.2,1.4,1.5,1.6,1.7,2.1,2.2,2.2,2.4,2.5,2.6,2.7 \
    <(sort input1.txt) <(sort input2.txt) | 
        tee output1.txt | grep -oP '^,+\K.*' > output2.txt

最終出力は次のとおりです。

$ cat output1.txt 
,,,,,,,2900,C,C,-13.730,59.405,-1.5,C
2931,C,C,-2.550,57.910,-0.3,C,2931,C,C,-2.420,57.610,0.2,C
2932,C,C,-0.200,51.550,0.9,C,,,,,,,
2940,C,C,-3.400,54.000,0.7,C,2940,S,S,-3.450,54.270,2.2,S
2941,S,S,-13.550,55.070,2.1,S,,,,,,,
2944,H,H,-4.180,60.300,0.7,H,,,,,,,
,,,,,,,4304,N,N,-7.680,58.330,-2.3,N


$ cat output2.txt 
2900,C,C,-13.730,59.405,-1.5,C
4304,N,N,-7.680,58.330,-2.3,N

関連情報