awk
次の状況ではどのように使用しますか?
同じ列で始まる行を連結したいと思います。結合後、最初の列(この場合)のみがaaa
保持されwww
ます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
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
他の人は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]
答え3
これはcoreutilsの興味深いアプリケーションです。入力のすべての行に対して結合を呼び出すので、大きな入力ではそれほど効率的ではないと考えられます。
touch outfile
while read; do
join -a1 -a2 outfile <(echo $REPLY) > tmp
mv tmp outfile
done < infile
効率を上げるには、仮想ディスクoutfile
に保存するのが役立ちます。tmp
編集する
または一時ファイルがありません。
out=""
while read; do
out=$(join -a1 -a2 <(echo -n "$out") <(echo -n "$REPLY"))
done < infile
echo "$out"
答え4
OP仮定求める入力順序を維持希望の出力、関連(文字列インデックス)配列はここでは使用できません。そのキーに対して反復を使用すると、出力順序はfor (var in array)
PerlのハッシュやPython辞書のように予測できません。3.6以前。
以下は、入力ファイルに最初に表示されたキーの元の順序を維持する、よく説明されたバニラAWKソリューションです。重複排除残りコラムはまた別の挑戦だろうが、必ずしもそうする必要はないようです。
これは、BSDバージョンのAWKを使用してmacOSでテストされました。しなければならない持っているすべてを活用して作業してくださいawk
。必要にchmod +x concat-by-first-col
応じて、最初に実行可能ファイルとしてマークした場合は、スタンドアロンシェルスクリプト*(AWKで書かれたことを誰も知らない)として実行できます。
#!/usr/bin/awk -f
## concat-by-first-col
## concatenate values from lines beginning with the same first column
##
## usage:
## $ chmod +x concat-by-first-col
## $ ./concat-by-first-col inputfile > outputfile
BEGIN {
# default output separator *is* a space, but if you wanted to change it…
OFS = " "
}
{
# assuming EVERY input record has AT LEAST the key…
# append to `keys` if we haven’t seen this key before
if (!($1 in values))
keys[length(keys)+1] = $1
# append second and subsequent columns to what we already have
for (i = 2; i <= NF; i++)
# insert an OFS *only* if there’s an existing value for this key
values[$1] = (values[$1] ? values[$1] OFS : "") $i
}
END {
# for all the keys, in the order they appeared in the input…
for (i = 1; i <= length(keys); i++) {
key = keys[i]
# a comma stands in for OFS in AWK’s `print` statement
print key, values[key]
}
}
スタンドアロンスクリプトの代わりにスイッチを使用して、AWKにプログラムテキストを提供できます-f
。
awk -f concat-by-first-col inputfile > outputfile
ブロックも省略した場合は、コマンドラインで指定BEGIN
できます。OFS
awk -v OFS='\t' -f concat-by-first-col inputfile > outputfile
希望の出力と一致しますか?確認する:
echo "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" > input
echo "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" > expected
# uses Bash’s process substitution**; expect no output
diff expected <(./concat-by-first-col input)
*のため理由、Linuxを使用している場合、またはAWKバージョンではない場合は、システムが/usr/bin/awk
「shebang」行を調整する必要があるかもしれません。
**https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html