結果:

結果:

次のような複数の列を含むテキストファイルがあります。

 1 102.0184 109.5487 107.3716
 2 100.2430 107.5874 108.7558
 3 103.9029 105.7406 106.9046
 4 102.7495 108.1275 104.4731
 5 102.8825 105.6664 107.2141
 6 104.5323 108.8850 106.0267
 7 103.0479 107.3056 105.5108
 8 101.2433 108.6113 107.2551
 9 104.4821 108.4339 105.9864
 10 101.5879 106.3859 102.825

次に、2番目の列のように、次のようにフィルタリングします。

awk '$2<104 {print $1,$2}' file.txt 

これを得ました:

1   102.0184
2   100.2430
3   103.9029
4   102.7495
5   102.8825
7   103.0479
8   101.2433
10  101.5879

最初の列の連続した範囲をすべて別のファイルに印刷したいので、この例では3つの出力ファイルがあります。

file_1-5.tmp
1   102.0184
2   100.2430
3   103.9029
4   102.7495
5   102.8825
file_7-8.tmp
7   103.0479
8   101.2433
file_10.tmp
10  101.5879

どうすればいいですか?ファイル内のすべての列に対してこのルーチンをどのように拡張できますか?私はこの問題を複数のファイルに適用したいので、この問題に対する一般的な解決策(この例で提供されている特定の範囲に依存しない)があることを願っています。

答え1

1行awkコマンド:

awk -v P=-1 '$2<104 {if ($1>P+1)N=$1;P=$1;print $1,$2>"file"N".tmp"}'

結果の提供(ファイル名が気に入らない場合)

==> file1.tmp <==
1   102.0184
2   100.2430
3   103.9029
4   102.7495
5   102.8825

==> file7.tmp <==
7 103.0479
8 101.2433

==> file10.tmp <==
10 101.5879

答え2

以下はawkプログラムです。パラメーターに指定された列としきい値を使用できます。

awk -v column=2 -v threshold=104 '
    function save() { if (lines != "") print lines >"file_" first "-" last ".txt" }

    ! ($column < threshold) {
        save()
        first = last = lines = ""
        next
    }

    { 
        if (first == "") first = $1
        last = $1
        lines = lines $1 OFS $column ORS
    }

    END { save() }
'

連続した行は、保存されるまでメモリに残ります。数億の連続行がある場合は、このソリューションを適用する必要があります(各行を一時ファイルに保存し、連続ブロックの最後の行に達すると名前を変更します)。

答え3

awk '{$0 = $2 < 104 ? NR : RS}1' inputfile |
sed -Ee '
   $aq
   /./,/^$/!d;/./H;$ba;/^$/ba;d;:a
   g;s/.//;s/\n.*\n|\n/,/;x;s/.*//;x
   s/(.*),(.*)/&w file_\1_\2.tmp/
   /,/!s/.*/&w file_&.tmp/
' | ed -s inputfile -

ここではツールを使用しますawk/sed/edAwkまず、104未満のすべての行に対して行番号を生成します。他の行の場合は、空白行を印刷します。次に、Sed空でない行から次の空行までの行の範囲を調べます。そして行番号を保持に保存します。これで、n、m、または一般nの2種類の範囲を見つけることができます。これを使用して、edこれらの範囲をそれぞれn、mw file_n_m.tmp、およびfile_n.tmpに変換する一連のコマンドを作成します。その後、edは動的に生成されたこのedスクリプトを使用して入力ファイルをただちに処理し、その行を.tmpファイルに配置します。

タスクを実行する1つの方法は次のとおりですPerl

perl -lane '
   BEGIN { $fmt = sprintf q[%s%%s\n%s], (chr 39)x2; }
   if ( $F[1] < 104 ) {
      push @A, "@F[0,1]";
      if ( eof ) {
         my $f = join $", q<printf>, $fmt, map(qq[\"$_\"], @A), q[>], (( ! defined $a ) ? qq[file_${.}.tmp] : qq[file_${a}_${.}.tmp]);
         system("$f");
      } else { $a //= $.; }
   } else {
      next if ! defined $a;
      $b //= $.-1;
      my $f = join $", q<printf>, $fmt, map(qq[\"$_\"], @A), q[>], (( $a == $b ) ? qq[file_$b.tmp] : qq[file_${a}_$b.tmp]);
      system("$f");
      ($a, $b, @A) = (undef)x2;
   }
' yourfile

結果:

file_1_5.tmp file_7_8.tmp file_10.tmp入力が与えられると、次の3つのファイルが生成されます。

%もっとfile_1_5.tmp file_7_8.tmp file_10.tmp

::::::::::::::
file_1_5.tmp
::::::::::::::
1 102.0184
2 100.2430
3 103.9029
4 102.7495
5 102.8825
::::::::::::::
file_7_8.tmp
::::::::::::::
7 103.0479
8 101.2433
::::::::::::::
file_10.tmp
::::::::::::::
10 101.5879

説明する:

まず、基本的なトップレベルのアイデア:2番目のフィールドが数字104の後ろにあるかどうかに注意深く注意してください。この場合、以前の範囲を印刷する必要があります。単一の長さの範囲では、ファイル名が反映されるように変更されます。

eof別のケースは、現在の範囲($ F [1] < 104)を累積する場合です。この作業中にヒットすると、範囲を印刷する必要があることに注意してください。

PS:このsystemコマンドは動的に生成された形式を使用して動的に生成され、そのデータは最初と2番目のフィールドであり、最後に範囲に基づいて.tmpファイル名が生成されます。

$a$b範囲の開始/終了行番号です。彼らの州は私たちに正しい決定を下すように伝えます。

関連情報