csplitと貼り付け

csplitと貼り付け

テキストファイルがあります列.txt以下のように2つの列があります。

  1 1.1
  2 4.0
  3 3.2
  start newset
  1 2.2
  2 6.1
  3 10.3
  4 2.1
  start newset
  1 18.2
  2 4.3

次の場合、新しい列のペアを作成するには、それらを複数の列に変換する必要があります。ニュース収集開始到着しました。だから私が望む出力テキストファイルは次のようになります。 (文字列のある行を削除したいです。ニュース収集開始):

  1 1.1 1 2.2 1 18.2
  2 4.0 2 6.1 2 4.3
  3 3.2 3 10.3
        4 2.1

答え1

これを試してみてください。

awk '
    /^start newset/ {
        max = max>i ? max : i
        i = 0
        set++
        next
    }
    {
        ++i
        a[i][set] = $0
    }
    END {
        for( i=1 ; i<=max ; i++ ) { 
            for( j=1 ; j<=set ; j++ )
                b = b OFS a[i][j]
            sub( "\t" , "" , b )
            print b
            b=""
        }
    }
' set=1 OFS='\t' column.txt

答え2

csplitと貼り付け

csplitパターンに従ってファイルを複数のファイルに分割するために使用されます。それからpaste

awk 'NF' column.txt | csplit --suppress-matched -s -z -f INTERIM -n 4 - '/start newset/' '{*}' ; paste INTERIM* | expand -t 6,13 ; rm -f INTERIM*

わかりやすくするために、同じコードを再フォーマットしました。

awk 'NF' column.txt | \
csplit --suppress-matched -s -z -f INTERIM -n 4 - '/start newset/' '{*}' ;

paste INTERIM* | \
expand -t 6,13 ;

rm -f INTERIM*

説明する:

  • awk 'NF' column.txt
    空白行を削除します。それ以外の場合は、入力ファイルの空行が出力に追加の列区切り文字を配置します。
  • 分割
    • --suppress-matched
      出力に分割パターンを含む行を含めないでください。
    • -s
      出力ファイルの要約情報を表示しません。
    • -z
      空の出力ファイルを作成しないでください(つまり、入力ファイルの隣接する2行に分割パターンが含まれている場合)。
    • -f INTERIM
      分割ファイルのファイル名はこの文字列で始まります。
    • -n 4
      分割されたファイルのファイル名は、この数字を含む数字で終わります。
    • -
      STDINまず入力ファイルを実行するので、から入力を取得しますawk
    • '/start newset/'
      この正規表現を含む最初の行で入力ファイルを分割します。
    • '{*}'
      その正規表現を含む各追加行で入力ファイルを分割し続けます。
  • paste INTERIM*
    一時ファイルを追加します。
  • expand -t 6,13
    リンクされたファイル間の列間隔を調整します(たとえば、2番目のファイルは列6から始まり、3番目のファイルは列13から始まります)。
  • rm -f INTERIM*
    一時ファイルを削除します。

入力ファイルの例column.txt:

1 1.1
2 4.0
3 3.2
start newset
1 2.2
2 6.1
3 10.3
4 2.1
start newset
1 18.2
2 4.3

出力例:

1 1.1 1 2.2  1 18.2
2 4.0 2 6.1  2 4.3
3 3.2 3 10.3 
      4 2.1  

入力ファイルの行と最終出力の行をインデントすると、より複雑になります。

入力ファイルの例column.txt:

  1 1.1
  2 4.0
  3 3.2
  start newset
  1 2.2
  2 6.1
  3 10.3
  4 2.1
  start newset
  1 18.2
  2 4.3
  • 追加処理の前にインデントを削除するには、にawk 'NF'変更します。awk 'NF { sub(/^ +/,"",$0) ; print $0 }'
  • インデントされた出力expand -t 6,13に変更します。awk '{ print " " $0 }' | expand -t 8,15

出力例:

  1 1.1 1 2.2  1 18.2
  2 4.0 2 6.1  2 4.3
  3 3.2 3 10.3 
        4 2.1  

答え3

いくつかの一時ファイルを介したルーティング:

$ awk 'BEGIN { n = 1 } /^start newset/ { n++; next } { name = sprintf("tmp-%04d", n); print >name }' file

これにより、端末に出力は生成されませんが、1以上のゼロで埋められた4桁の整数という名前tmp-nのファイルが生成されます。n各データセットには1つのファイルがあります。

その後、これらの一時ファイルを一緒に貼り付けることができます。

$ paste tmp-*
1 1.1   1 2.2   1 18.2
2 4.0   2 6.1   2 4.3
3 3.2   3 10.3
        4 2.1

または、タブの代わりにスペースを区切り文字として使用します。

$ paste -d ' ' tmp-*
1 1.1 1 2.2 1 18.2
2 4.0 2 6.1 2 4.3
3 3.2 3 10.3
 4 2.1

もしあれば大きいデータのセット数に応じて、2つの問題が発生します。

  1. 2番目のコードブロックをawk変更すると、これを防ぐことができます。awk

    { name = sprintf("tmp-%04d", n); print >name }
    

    到着

    { name = sprintf("tmp-%06d", n); print >>name; close(name) }
    

    (また、より大きな数字を許可するように書式文字列を変更することに注意してください。)

  2. pasteパターンはあまりにもtmp-*多くのファイルに展開されるため、コマンドの実行に問題がある可能性があります。これが問題かどうかを教えてください。修正します(ファイルの列を追加して結果を作成するシェルループが発生しますtmp-*)。

答え4

$ awk '$1+0>=1{a[$1]=a[$1]" "$0}END{for (i in a)print a[i]}' file.txt 
 1 1.1 1 2.2 1 18.2
 2 4.0 2 6.1 2 4.3
 3 3.2 3 10.3
 4 2.1

上記のawkコマンドは、aという配列を生成し、最初の列に基づいて値を保存/追加します。ファイルを完全に読み取ったら、配列値を印刷するだけです。

step 1 : a[1] = "1 1.1"
step 2 : a[2] = "2 4.0"
step 3 : a[3] = "3 3.2"
step 4 : ignore the line # 4. because the first column is not numeric
step 5 : a[1] = "1 1.1 1 2.2"
step 6 : a[2] = "2 4.0 2 6.1".
....
...
once the file is fully procssed by awk, then just print the array values a[1],a[2],a[3]...a[n]

関連情報