特定の列(例では$ 2)から重複フィールド(カンマ区切り)を削除したいと思います。
入力ファイル:
A 1,2,3,4
B 4,5,6,3
C 2,15
予想出力:
A 1,2,3,4
B 5,6
C 15
ベストアンサー1
perl -lpe 's/\s\K\S+/join ",", grep {!$seen{$_}++} split ",", $&/e'
上記のコードは次のように実行できます。
$ perl -lpe 's/\s\K\S+/join ",", grep {!$seen{$_}++} split ",", $&/e' afile
A 1,2,3,4
B 5,6
C 15
どのように動作しますか?
を初めて呼び出すperl
と、-lpe
次の3つのことが行われます。
-l[octal]
行末処理を有効にして行終端を指定します。-p
-n のような繰り返しを仮定し、sed のようなライン印刷も仮定します。-e program
1行プログラム(複数の-eを許可、プログラムファイルを省略)
これは本質的にファイルをインポートし、改行文字を削除し、1行で動作し、操作が完了すると改行文字を追加します。したがって、ファイルを繰り返しながら、各ファイルに対してPerlコードを順番に実行します。
実際のPerlコードは次のとおりです。
\s
空白文字(たとえば、最新バージョンでは[ \f\n\r\t]
5文字)を表します。\v
perl
[[:space:]]
\K
内容を\Kの左側に保ち、$&に含めないでください。\S+
セットにない 1 つ以上の文字 [\f\n\r\t\v]
結果が収集され、join ",",
各フィールドがコンマで区切られるように再結合されます。
split ",", $&
で見つかった一致を取得し、カンマ\S+
なしでフィールドに分割します。
各フィールドの番号を取得し、grep {!$seen{$_}++}
ハッシュに追加します。$seen{}
ここで、各フィールドの番号は、$_
各フィールドを繰り返すときの番号です。フィールド番号が「表示」されるたびに++
演算子で計算されます$seen{$_}++
。
grep{!$seen{$_}++}
フィールド値が一度だけ発生すると、フィールド値が返されます。
編集して何が起こるかを確認してください
この修正された嫌悪機能を使用すると、Perlコードの1行がファイルから複数行に移動したときに何が起こるかを確認できます。
$ perl -lpe 's/\s\K\S+/join ",", grep {!$seen{$_}++} split ",", $&/e; @a=keys %seen; @b=values %seen; print "keys: @a | vals: @b"' afile
keys: 4 1 3 2 | vals: 1 1 1 1
A 1,2,3,4
keys: 6 4 1 3 2 5 | vals: 1 2 1 2 1 1
B 5,6
keys: 6 4 1 3 2 15 5 | vals: 1 2 1 2 2 1 1
C 15
$seen{}
これは、処理されたファイルの行末に何があるかを示しています。ファイルの2行目を見てみましょう。
B 4,5,6,3
以下は、次のように行を表示する修正版です。
keys: 6 4 1 3 2 15 5 | vals: 1 2 1 2 2 1 1
つまり、フィールド#6(1回)、フィールド#4(2回)など、フィールド#5(1回)を確認したという意味です。したがって、grep{...}
結果が返されたときにその配列の結果がこの行(4、5、6、3)に表示され、1回(6,1,15,5)のみが表示される場合、その配列の結果のみが返されます。これら2つのリストの交差は(5,6)であり、これが返されますgrep
。