0

次のようにソートされたファイルが与えられます:

AAA 1 2 3
AAA 2 3 4
AAA 3 4 2
BBB 1 1 1
BBB 1 2 1

との望ましい出力

AAA 1 2 3
BBB 1 1 1

sedでこれを達成するための最良の方法は何ですか?

基本的に、列が前の行と同じフィールドで始まる場合、それを削除するにはどうすればよいですか?残りのデータは出力に保持する必要があります。

ホールドバッファ、分岐、またはテストコマンドのいずれかを使用してこれを行う方法が必要だと思います。

4

6 に答える 6

1

これはAWKで行うことができます:

$ gawk '{if (last != $1) print; last = $1}' in.txt
AAA 1 2 3
BBB 1 1 1
于 2012-10-01T18:53:39.750 に答える
1

awkの別の方法:

awk '!($1 in a){print;a[$1]}' file
于 2012-10-01T18:59:30.453 に答える
0

たぶん、より簡単な方法がsedありますが、:

sed ':a;N;/\([[:alnum:]]*[[:space:]]\).*\n\1/{s/\n.*//;ta};P;D'

これにより、出力が生成されます

AAA 1 2 3
BBB 1 1 1

これは質問のそれとは異なりますが、説明と一致します:

列が前の行と同じフィールドで始まる場合、どうすれば削除できますか?

于 2012-10-01T19:00:17.517 に答える
0

使用する1つの方法GNU awk

awk '!array[$1]++' file.txt

結果:

AAA 1 2 3
BBB 1 1 1
于 2012-10-02T04:21:38.847 に答える
0

これはうまくいくかもしれません(GNU sed):

sed -r ':a;$!N;s/^((\S+\s).*)\n\2.*/\1/;ta;P;D' file

または多分ただ:

sort -uk1,1 file
于 2012-10-01T20:22:55.623 に答える
0

sed を使用:

#!/bin/sed -nf

P

: loop
s/\s.*//
N
/\([^\n][^\n]*\)\n\1/ b loop

D

まず、-nフラグを sed に渡して、指定した内容のみを出力する必要があります。

最初の行は常に印刷され、必要なときにのみこの行を実行するように sed を強制するため、「P」コマンドで行を印刷することから始めます。

次に、ループを実行します。「:」コマンド (この場合、ラベルに「loop」という名前を付けます) を使用して開始ラベルを使用してループを定義し、必要に応じて、「b」コマンド (または「t」テスト) を使用してこのラベルに戻ります。指図)。このループは非常に単純です。

  1. 最初のフィールド以外をすべて削除します (最初のスペース文字とそれに続くすべてのものを何も置き換えません)。
  2. 次の行を追加します (改行文字が含まれます)
  3. 新しい行が分離したフィールドで始まるかどうかを確認します。これは、キャプチャを使用して行います。キャプチャは、一致した入力が特別な「変数」に格納される「サブマッチ」として定義され、存在するキャプチャの順序に従って番号が付けられます。バックスラッシュでエスケープされた括弧を使用してキャプチャを指定します (で始まり、\(で終わります\))。この場合、改行文字ではないすべての文字 (つまり[^\n]) を行末まで一致させます。これは、改行以外の文字の少なくとも 1 つとそれに続く任意の文字列を照合することによって行われます。これにより、改行の前に空の文字列が一致するのを防ぎます。キャプチャの後、特別な変数を使用して、改行文字とそれに続くキャプチャの結果を照合します。\1、その最初のキャプチャで一致した入力が含まれています。これが成功すると、最初のフィールドを繰り返す行があるので、「b」分岐コマンドでループの先頭に戻ります。
  4. ループを終了すると、最初のフィールドが異なる行が見つかったので、入力行を準備して、スクリプトの先頭に戻る必要があります。これは、"D" delete-first-line-and-restart-script コマンドで実行できます。

これは 1 行に短縮できます (「ループ」ラベルの名前を「a」に変更したことに注意してください)。

sed -e 'P;:a;s/\s.*//;N;/\([^\n][^\n]*\)\n\1/ba;D'
于 2012-10-02T13:11:43.910 に答える