UbuntuでBashを使用しており、質問は次のとおりです。
ヘッダーと区切り文字を含む大きなテキストファイルがあります#|#
。
このファイルに関する情報を取得するためにAWKを使用しようとしています。次の式を使用して、列1の値にグループ化された列2の合計を計算しようとしています。
awk 'BEGIN { FS="\\#\\|\\#" }{arr[$1]+=$2} END {for (i in arr) {print i,arr[i]}}' myfile.txt
私が得た出力には2つの問題があります。
まず、列1が2つの固有値value1とvalue2を使用すると仮定すると、AWKは2つではなく3つのグループ(value1、value2、およびname_column1)を形成します。
ファイルの最初の行がヘッダであることを理解していないようです...
2番目の問題は、私の出力が次のようになることです。
value1 0 value2 0 name_column1 0
したがって、私たちは出力の最後の行が予期しないものであることを知っています(前述のように)。最初の2行に集中します。ここでは両方の合計が空ですが、そのうちの少なくとも1つは厳密にゼロより大きくなければならないことを知っています。
awk 'BEGIN { FS="\\#\\|\\#" }{sum1+=2;}END{print sum1;}' myfile.txt
私にしてください
251597850
。
したがって、最後のコマンド(一般的な合計)に問題があるか、前のコマンド(合計+グループに基づいて)に問題があります。
この問題を解決する方法を知っている人はいますか?
編集:私のファイルテキストは次のとおりです。
Column1#|#Column2#|#Column3
0300#|#0.00#|#0000
ここで、0300はvalue1
前述のものです(数字ではなくカテゴリーです)。
編集2:
awk 'BEGIN { FS="\\#\\|\\#" }{sum1+=2;}END{print sum1;}' myfile.txt
私に2 *(ファイルの行数)を与えるが、これは明らかに私が望むものではないので、コマンドは次のようになります。
awk 'BEGIN { FS="\\#\\|\\#" }{sum1+=$2;}END{print sum1;}' myfile.txt
編集3:
区切り文字のため、私のコマンドはすべて間違っていることがわかりました。したがって、グループ化する正しいコマンドは次のとおりです。
awk 'BEGIN { FS="#[|]#" } FNR>1 {arr[$1]+=$2} END { for (i in arr) print i,arr[i] }' file.txt
ベストアンサー1
簡単に答えると、この場合、FS変数はRE(正規表現またはパターン)です。したがって、実際のデータ文字がREコンテキストで「特殊」である場合は、REからエスケープして演算子ではなくそれ自体で処理する必要があります。
この場合、犯人は|
交代演算子です。両側の項目は代替REであり、いずれかが一致すると見なされます。たとえば、フィールド区切り文字はa|u|o|i|e
各コレクション内のフィールドを分割します。
したがって、REは#|#
多少冗長です。フィールド区切り文字で 2 回指定され、#
繰り返しは無視されます。
解決策はエスケープすることです|
。私が好む方法は、それ自体を表すためにダウングレードされる|
角括弧式(文字クラス)に変換することです。[|]
|
またはエスケープ文字を渡して区切り文字\
を#\\|#
。
脱出は\
なぜ2回書きましたか?これは別の奇妙なルールです(バックスラッシュがしばしばawkモードで問題を引き起こす理由です)。
awk REを作成する方法には、同じパターンで作成するか、/myRE/
同じ文字列で作成する2つの方法があります"myRE"
。
この/myRE/
形式は(デフォルトで)ブール値として機能し、pattern { action }
awkソースモデルまたは{ if (/myRE/) ...}
.また、フィールドや変数などのより具体的なターゲットと$6 ~ /myRE/
一致させることもできますmyVar ~ /myRE/
。この形式では、文字は個別にエスケープされます\
。
ただし、REが文字列で書かれている場合、awkは後でREとして呼び出すことができることを知りません。解析済み二重:元のソースコードで最初に一般的な文字列エスケープ(\t
タブ、改行、\n
バック\\
スラッシュなど)を実行します。その後、~
演算子またはmatch()
or関数と一緒にsplit()
使用したときにやり直してください。
FS文は文字列として扱われるため、すべてのバックスラッシュを2倍にする必要があります。これは、コマンドラインでFSを使用するか、宣言するか、-F
またはそのようにFSを宣言するかどうかです。-v FS=
BEGIN { FS = "myRE" }
私は「短い答え」に言及しましたが、このようなものはほとんど常に間違っています。例外があり、その例外にも例外があります。
特殊演算子には機能する項目が必要なため、単一文字の正規表現を作成するのは困難です。したがって、FS 内のすべての単一文字値は文字通り処理されます。'-F|'
あるいは、フィールドをパイプ記号で区切って作成することもできます-v 'FS=|'
。BEGIN { FS = "|" }
単一文字規則の例外は、単一のスペースで構成されるFSです(デフォルト)。これは行の各単語をフィールドに変換します。 awkと同様に、単純は比較用語です。
(1)区切り文字は、ASCIIスペース、水平タブ、および改行文字が連続して混合されたシーケンスとして定義される「スペース」です。 (代替レコード区切り文字が有効な場合にのみ改行文字が表示されます.)
(2) 行全体の先頭と末尾のスペースは、フィールド区切り文字ではありません。 (他のFSが行の先頭または末尾にある場合は、それぞれその前または後に暗黙の追加の空白フィールドがあります。)
私が参照する場所はGNU/awk オンラインマニュアル。
回答自体は非常に長くて複雑ですが、マニュアルではセクション3、正規表現に約600行を割り当て、セクション4.5、フィールド区切り方法の指定に別の250行を割り当てます。