複数行を含む2つのtxtファイルを比較し、ファイル1に固有の行のみを含む3番目のtxtファイルを作成する必要があります。ファイル1の例は次のとおりです。
../../A/folder/fname.gz | -12.36 | A:BCD:123:A, D:DFR:241:AZ1
../../A/folder/fname2.gz | -4.56 | B:ABC:456:C | G:RFT:265:T
数千行にわたって続き、ファイル2の例は次のとおりです。
../../B/folder2/fname.gz | -7.65 | C:ABC:425:A
../../B/folder2/fname3.gz | -12.31 | A:BCD:758:D
../../folder/fname2.gz
例のように、最初のフィールドに基づいて一意のファイル1のすべての行を取得する必要があります。異なるfolder
場合がありますが、固有でなければfnameX.gz
なりません。folder
両方ともおよび/またはをfname
含みます。各行のフィールド数は異なる場合があります。上記の例の予想出力は次のとおりです。-
_
../../A/folder/fname2.gz | -4.56 | B:ABC:456:C | G:RFT:265:T
これを行う最良の方法は何ですか?
答え1
awk -F ' *[|] *' '{ k=$1; sub(".*/", "", k) }
!z { a[k]; next } !( k in a )' file2 z=1 file1
まず読み込み、file2
ファイル名部分を配列に保存します。読み込み時にfile1
ファイル名が配列にない場合は、1行を印刷します。
答え2
私たちはシュワルツ変換|
各ファイルの最初のフィールドのファイル名に文字が含まれておらず、フィールドがオプションのスペース|
(スペースおよび/またはタブ)で囲まれていると仮定するヘルパーシェル関数。
sorter
まず、入力データの最初のフィールドからファイル名を抽出し、データをソートする前に、各行にこのファイル名プレフィックスを追加するヘルパー関数を定義します。
sorter () {
awk -F '[[:blank:]]*\|[[:blank:]]*' -v OFS='|' \
'{ key=$1; sub(".*/","",key); print key, $0 }' |
sort
}
$0
最終出力で最初のフィールドのパス名のみが必要な場合は、上記の$1
コードでを変更してください。$2
2番目のフィールドなどをインポートするように変更します。
join
ユーティリティは入力が結合フィールドに従ってソートされると仮定するため、データをファイル名でソートする必要があります。
この関数は標準入力からデータを読み込み、最初のファイルを実行すると結果は次のようになります。
$ sorter <file1
fname.gz|../../A/folder/fname.gz | -12.36 | A:BCD:123:A, D:DFR:241:AZ1
fname2.gz|../../A/folder/fname2.gz | -4.56 | B:ABC:456:C | G:RFT:265:T
各入力ファイルに対してこれを行い、最初のフィールド結合を使用すると、次を使用して、2番目のファイルのどの行ともペアリングできない最初のファイルの行のみを出力するようにjoin
要求できます。join
join -v 1
join -t '|' -v 1 <( sorter <file1 ) <( sorter <file2 ) | cut -d '|' -f 2-
最後に、このコマンドは、コマンドが各行に追加したcut
ファイル名フィールドを削除します。awk
質問のデータを考慮すると、結果は次のようになります。
../../A/folder/fname2.gz | -4.56 | B:ABC:456:C | G:RFT:265:T
コードを$0
次に置き換えると、次のような結果が得られます。$1
awk
../../A/folder/fname2.gz