49

AWK では、フィールドの「範囲」を指定できますか?

例。1 行あたり 100 フィールドのタブ区切りファイル「foo」が与えられた場合、各行のフィールド 32 から 57 のみを出力し、結果をファイル「bar」に保存します。私が今していること:

awk 'BEGIN{OFS="\t"}{print $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $50, $51, $52, $53, $54, $55, $56, $57}' foo > bar

これに関する問題は、入力するのが面倒で、エラーが発生しやすいことです。

より簡潔でエラーが発生しにくい方法 (「$32..$57」など) で同じことを言える構文形式はありますか?

4

9 に答える 9

36

@Jerryによるawk 回答に加えて、他の選択肢があります:

使用cut(デフォルトでタブ区切り文字を想定):

cut -f32-58 foo >bar

使用perl:

perl -nle '@a=split;print join "\t", @a[31..57]' foo >bar
于 2012-11-15T04:36:56.163 に答える
28

軽度に改訂されたバージョン:

BEGIN { s = 32; e = 57; }

      { for (i=s; i<=e; i++) printf("%s%s", $(i), i<e ? OFS : "\n"); }
于 2012-11-15T04:12:10.970 に答える
8

RE間隔を使用してawkで実行できます。たとえば、このファイルのレコードのフィールド 3 ~ 6 を印刷するには、次のようにします。

$ cat file
1 2 3 4 5 6 7 8 9
a b c d e f g h i

だろう:

$ gawk 'BEGIN{f="([^ ]+ )"} {print gensub("("f"{2})("f"{4}).*","\\3","")}' file
3 4 5 6
c d e f

RE セグメント f を作成して、すべてのフィールドとそれに続くフィールド セパレータ (便宜上) を表し、gensub でそれを使用して、そのうちの 2 つ (つまり、最初の 2 つのフィールド) を削除します。参照用に次の 4 つを覚えておいてください。後で \3 を使用して、その後に続くものを削除します。フィールド 32 ~ 57 (つまり、最初の 31 の後の 26 フィールド) を印刷するタブ区切りファイルの場合は、次のようにします。

gawk 'BEGIN{f="([^\t]+\t)"} {print gensub("("f"{31})("f"{26}).*","\\3","")}' file

上記では、gensub() 関数に GNU awk を使用しています。他の awks では、sub() または match() と substr() を使用します。

編集:仕事をするための関数を書く方法は次のとおりです:

gawk '
function subflds(s,e,   f) {
   f="([^" FS "]+" FS ")"
   return gensub( "(" f "{" s-1 "})(" f "{" e-s+1 "}).*","\\3","")
}
{ print subflds(3,6) }
' file
3 4 5 6
c d e f

FS を適切に設定するだけです。入力ファイルがスペースで始まる場合や、フィールド間に複数のスペースがある場合は、デフォルトの FS を調整する必要があり、FS が 1 文字の場合にのみ機能することに注意してください。

于 2012-11-15T05:17:21.987 に答える
2

ループの組み合わせを使用でき、printfそのためにawkで使用できます。

#!/bin/bash

start_field=32
end_field=58

awk -v start=$start_field -v end=$end_field 'BEGIN{OFS="\t"}
{for (i=start; i<=end; i++) {
    printf "%s" $i;
    if (i < end) {
        printf "%s", OFS;
    } else {
        printf "\n";
    }
}}'

ただし、これは少しハッキーに見えます。

  • OFS指定された、およびに基づいて出力を適切に区切ります。
  • ファイルの各入力行の最後に必ず新しい行を出力します。
于 2012-11-15T04:16:05.367 に答える
1

awkでフィールド範囲を選択する方法がわかりません。入力の最後にフィールドをドロップする方法は知っていますが(以下を参照)、最初は簡単ではありません。ベロー、最初にフィールドをドロップするのは難しい方法です。

入力に含まれていない文字がわかっている場合cは、次のawkスクリプトを使用できます。

BEGIN { s = 32; e = 57; c = "#"; }
{ NF = e            # Drop the fields after e.
  $s = c $s         # Put a c in front of the s field.
  sub(".*"c, "")    # Drop the chars before c.
  print             # Print the edited line.
}

編集

そして、入力にない文字をいつでも見つけることができると思いました:use \n

于 2012-11-15T13:15:44.380 に答える