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