awkまたはsedで最初の列で行を連結します


12

awk次の状況でどのように使用できますか?

同じ列で始まる行を連結します。結合後は最初の列のみが保持されます(この場合aaawww、、hhh)。

ファイルはスペースまたはタブで区切られます。

入力例:

aaa bbb ccc ddd NULL NULL NULL
aaa NULL NULL NULL NULL NULL NULL
aaa bbb ccc NULL NULL NULL NULL
www yyy hhh NULL NULL NULL NULL
hhh 111 333 yyy ooo hyy uuuioooy
hhh 111 333 yyy ooo hyy NULL

望ましい出力:

aaa bbb ccc ddd NULL NULL NULL NULL NULL NULL NULL NULL NULL bbb ccc NULL NULL NULL NULL
www yyy hhh NULL NULL NULL NULL
hhh 111 333 yyy ooo hyy uuuioooy 111 333 yyy ooo hyy NULL

これの背景は、最初の列が常にエンティティの識別子である、非常に単純なファイルベースのデータベースをセットアップすることです。同じ識別子列に基づくすべての行は連結されます。


1
どこでしたuuu行は、(出力中)から来ますか?
saeedn

すみません、私の悪い。編集します。
小さな

回答:


8

awkを使用して各行の最初の列を取得するには、次を実行できます。

< testfile awk '{print $1}'
aaa
aaa
aaa
www
hhh
hhh

これらは、残りの行のキーです。したがって、最初の列をキーとして使用し、行の2番目の列を値として使用して、ハッシュテーブルを作成できます。

< testfile awk '{table[$1]=table[$1] $2;} END {for (key in table) print key " => " table[key];}'
www => yyy
aaa => bbbNULLbbb
hhh => 111111

列2から始まる行全体を取得するには、すべての列を収集する必要があります。

< testfile awk '{line="";for (i = 2; i <= NF; i++) line = line $i " "; table[$1]=table[$1] line;} END {for (key in table) print key " => " table[key];}'
www => yyy hhh NULL NULL NULL NULL 
aaa => bbb ccc ddd NULL NULL NULL NULL NULL NULL NULL NULL NULL bbb ccc    NULL NULL NULL NULL 
hhh => 111 333 yyy ooo hyy uuuioooy 111 333 yyy ooo hyy NULL 

こんにちは、そうです、テーブルをハッシュ化するための内訳が必要でした。ありがとうございました!
小さな

2
@tiny-順序を保持する必要があると想定していました。これは事実ではありませんか(この答えは、元の順序ではなく、ハッシュメカニズムに対応する順序を生成します)?
ire_and_curses

3

他の誰かがawkまたはsedで答えることができますが、Pythonバージョンは簡単であり、役に立つかもしれません。

#!/usr/bin/env python

input_file = 'input.dat'
in_fh      = open(input_file, 'r')

input_order = []
seen        = {}
for line in in_fh:    
    # Remove the newline character...
    line = line[:-1]

    # Separate the first column from the rest of the line...
    key_col, sep, rest_of_line = line.partition(" ")
    rest_of_line = sep + rest_of_line  

    # If we've seen this key already, concatenate the line...
    if key_col in seen:
        seen[key_col] += rest_of_line
    # ...otherwise, record the ordering, and store the new info
    else:
        input_order.append(key_col)
        seen[key_col] = rest_of_line

in_fh.close()

# Dump the ordered output to stdout
for unique_col in input_order:
    print unique_col + seen[unique_col]

とてもかっこいい。私も:)それは、入力ファイル名として最初の引数をとることを編集スクリプトに管理私のゼロ経験パイソンと
小さな

2

これは、coreutilsの興味深いアプリケーションです。入力の各行に対してjoinを呼び出すため、大きな入力ではあまり効率的ではないと思われます。

touch outfile
while read; do
  join -a1 -a2 outfile <(echo $REPLY) > tmp
  mv tmp outfile
done < infile

効率を向上させるには、保存してRAMディスクに保存するoutfiletmp役立つ場合があります。

編集

または一時ファイルなし:

out=""
while read; do
  out=$(join -a1 -a2 <(echo -n "$out") <(echo -n "$REPLY"))
done < infile

echo "$out"

2

そして、ここにPERLワンライナーがあります:

$ perl -e 'my %h; while(<>){chomp; @a=split(/\s+/); $k=shift(@a); $h{$k}.=join(" ", @a) . " "; } map{$h{$_}=~s/\s*$//; print "$_ $h{$_}\n}keys(%hash);' infile
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.