GNU/Linux >> Linux の 問題 >  >> Linux

Unix でテキスト ファイル内の複数のフィールドを結合する

最初の 3 つのフィールドを awk で組み合わせるのがおそらく最も簡単です:

awk '{print $1 "_" $2 "_" $3 " " $4}' filename

次に、 join を使用できます 通常は「フィールド 1」に


あなたはこれを試すことができます

awk '{
 o1=$1;o2=$2;o3=$3
 $1=$2=$3="";gsub(" +","")
 _[o1 FS o2 FS o3]=_[o1 FS o2 FS o3] FS $0
}
END{ for(i in _) print i,_[i] }' file1 file2

出力

$ ./shell.sh
foo 1 scaf  3 4.5
bar 2 scaf  3.3 1.00
foo 1 boo  2.3

珍しい行を省略したい場合

awk 'FNR==NR{
 s=""
 for(i=4;i<=NF;i++){ s=s FS $i }
 _[$1$2$3] = s
 next
}
{
  printf $1 FS $2 FS $3 FS
  for(o=4;o<NF;o++){
   printf $i" "
  }
  printf $NF FS _[$1$2$3]"\n"
 } ' file2 file1

出力

$ ./shell.sh
foo 1 scaf 3  4.5
bar 2 scaf 3.3  1.00

これが正解です 回答 (標準の GNU coreutils の使用に関して) ツール、および perl/awk でカスタム スクリプトを記述しない 名前を付けてください)。

$ join -j1 -o1.2,1.3,1.4,1.5,2.5 <(<file1 awk '{print $1"-"$2"-"$3" "$0}' | sort -k1,1) <(<file2 awk '{print $1"-"$2"-"$3" "$0}' | sort -k1,1)
bar 2 scaf 3.3 1.00
foo 1 scaf 3 4.5

わかりました、どのように機能しますか:

<オール>
  • まず、優れたツール join を使用します 2行をマージできます。 join 2 つの要件があります:

    • 参加できます 1 つのフィールドのみ。
    • 両方のファイルを並べ替える必要があります キー列別
  • キーを生成する必要があります 入力ファイルで、そのために単純な awk を使用します スクリプト:

    $ cat file1
    foo 1 scaf 3
    bar 2 scaf 3.3    
    
    $ <file1 awk '{print $1"-"$2"-"$3" "$0}'
    foo-1-scaf foo 1 scaf 3
    bar-2-scaf bar 2 scaf 3.3
    

    ご覧のとおり、「foo-1-scaf」のようなキーを持つ最初の列を追加しました ".file2 でも同じことを行います .ところで。 <file awkawk file を書くための空想的な方法です 、または cat file | awk .

    並べ替えも必要です キーによるファイル。この場合、これは列 1 であるため、コマンドの最後に | sort -k1,1 を追加します。 (並べ替え 1 列目から 1 列目までのテキスト)

  • この時点で、ファイル file1.with.key を生成するだけです。 file2.with.key それらを結合しますが、それらのファイルが巨大であると仮定すると、それらをファイルシステムにコピーしたくありません。代わりに bash と呼ばれるものを使用できます 名前付きパイプへの出力を生成する置換を処理します (これにより、不要な中間ファイルの作成が回避されます)。詳細については、提供されたリンクをお読みください。

    ターゲットの構文は次のとおりです:join <( some command ) <(some other command)

  • 最後に、複雑な結合引数について説明します:-j1 -o1.2,1.3,1.4,1.5,2.5

    • -j1 - 1 列目のキーで結合 (両方のファイル)
    • -o - これらのフィールドのみを出力 1.2 (最初のファイル フィールド 2)、1.3 (最初のファイルの列 3) など

      このように行を結合しましたが、join 必要な列のみを出力します。

  • この投稿から得られる教訓は次のとおりです。

    • coreutils を習得する必要があります これらのツールは組み合わせると非常に強力になり、ほとんど必要ありません。 そのような場合に対処するカスタム プログラムを作成する
    • コア ユーティリティ ツールも非常に高速で、十分にテストされているため、常に最良の選択です。

    結合コマンドは使いにくく、1 つの列でしか結合できません

    広範な実験とマニュアル ページの綿密な精査により、複数の列を直接結合することはできないことが示されました。また、私の結合の実際の例はすべて、おかしなことに、結合する列を 1 つだけ使用しています。

    したがって、どのような解決策でも、結合する列を何らかの形で 1 つの列に連結する必要があります。標準の結合コマンドでは、入力が正しい並べ替え順序になっている必要もあります。GNU の結合 (info coreutils join) には、並べ替えられたデータが必ずしも必要ではないという記述があります。

    <ブロック引用>

    ただし、GNU 拡張機能として、入力にペアにできない行がない場合、ソート順は、上記のソート比較で 2 つのフィールドが等しいと見なされる場合にのみ、2 つのフィールドが等しいと見なされる任意の順序にすることができます。

    与えられたファイルでそれを行う 1 つの可能な方法は次のとおりです:

    awk '{printf("%s:%s:%s %s %s %s %s\n", $1, $2, $3, $1, $2, $3, $4);}' file1 |
    sort > sort1
    awk '{printf("%s:%s:%s %s %s %s %s\n", $1, $2, $3, $1, $2, $3, $4);}' file2 |
    sort > sort2
    join -1 1 -2 1 -o 1.2,1.3,1.4,1.5,2.5 sort1 sort2
    

    これにより、最初に「:」を使用してサブフィールドを区切る複合ソート フィールドが作成され、2 つのファイルのそれぞれについてファイルがソートされます。 join コマンドは 2 つの複合フィールドを結合しますが、非複合 (非結合) フィールドのみを出力します。

    出力は次のとおりです:

    bar 2 scaf 3.3 1.00
    foo 1 scaf 3 4.5
    

    join ができないことをさせようとして失敗した

    join -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 file1 file2

    MacOS X 10.6.3 では、次のようになります:

    $ cat file1
    foo 1 scaf 3 
    bar 2 scaf 3.3
    $ cat file2
    foo 1 scaf 4.5
    foo 1 boo 2.3
    bar 2 scaf 1.00
    $ join -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 file1 file2
    foo 1 scaf 3 4.5 
    bar 2 scaf 3.3 4.5 
    $
    

    これはフィールド 3 (のみ) に参加しています - これは望んでいるものではありません。

    入力ファイルが正しいソート順になっていることを確認する必要があります。


    Linux
    1. Linuxで複数のファイルを圧縮する方法

    2. 1 つのテキスト ファイルを複数の *.txt ファイルに分割する方法は?

    3. 複数のリモート ファイルを追跡する

    1. MySQLに複数のSQLファイルをインポートする

    2. Linuxで2つのテキストファイルを結合する方法

    3. Unixの単一のコマンドまたはスクリプトで複数のファイルの名前を変更する方法は??

    1. 検索を使用して複数のファイルの名前を変更するにはどうすればよいですか?

    2. Dd:複数の入力ファイル?

    3. Linux – 2つのソートされたファイルを結合するとエラーが発生します:Join::112855:ソートされていません:?