web-dev-qa-db-ja.com

複雑なファイル構造からのデータの抽出

データベースからのダンプであるtxtファイルがあり、1行に1つのエントリが含まれています。構造は次のようになります。

1500
29/03/2010 
18
02
09
47
17
45
28.248
0
0.01
130
12.721
7908
298,809
YES
3.046.550,39
6.500.000,00
17,444,222


1501
30/03/2010
27
54
28
50
22
03
37.223
0
0.00
97
22,466
7379
421.90
NO
20,262,429
25,000,000.01
17,995,281.33


... the third record starts here

データベースには21のフィールドが含まれています。前の行は、そのデータベースの2つのレコードのダンプを示しています。空白行は、データベースの空白フィールドを表します。

最初のフィールド(F0)は、1500、1501 ...と表示される番号です。

2番目のフィールド(F1)は、日、月、年の形式の日付です。

フィールドF2、F3、F4、F5、F6、F7は6つの整数です。

必要なのは、このファイルからF0、F2、F3、F4、F5、F6、F7を抽出して、それぞれに1行を作成することです。

上記の2つのレコードを考えると、最終的なファイルは次のようになります。

1500,18,02,09,47,17,45
1501,27,54,28,50,22,03

何マイルも長く、各行で相互作用するbashスクリプトを使用してこれを行う方法を知っています。しかし、unixはトリックの袋であり、特にsedコマンドであり、おそらくこれが可能であることも知っています。簡単な行で完了します。私は新しいことを学ぶのが大好きなので、Unixの神である皆さんにどうやってそれをするのか聞いてみます。

私はOSXMavericksを使用しています。ありがとう。

5
SpaceDog

これが1つの方法です:

_$ Perl -000ne '@f=split(/\n/); print join(",",@f[0,2..7]) , "\n"' file.txt  
1500,18,02,09,47,17,45
1501,27,54,28,50,22,03
_

説明:

  • _-000_:「段落モード」をアクティブにし、Perlのフィールド区切り文字を_\n\n_、連続する改行に設定します。これは、各レコードを1行として扱うことを意味します。

  • @f=split(/\n/);:現在の行(レコード)を改行で分割し、配列_@f_として保存します。この配列には、レコードの各フィールドが含まれています。これは、配列スライス_@f[0,2..8]_にフィールド0および2から8が含まれることを意味します。

  • _print join ",",@f[0,2..8] , "\n"'_:これは配列スライスをコンマで結合し、結果の文字列の後に改行を出力します。

3
terdon

awkの使用:

awk '
  BEGIN {
    fields[1]
    fields[3]
    fields[4]
    fields[5]
    fields[6]
    fields[7]
    last_field=8
  }
  ( NR%21 in fields ) { printf($0",") }
  NR%21==last_field' in_file.txt

またはさらに良い:

awk '
  NR%21 ~ /^(1|3|4|5|6|7)$/ { printf($0",") }
  NR%21==8' in_file.txt

GNU sedには、ここで役立つ特定の行の後のn行目に一致するNice拡張子があります。 OSXでは動作しませんが、楽しみのために:

sed -n '
  1~21 { h }
  3~21,7~21 { H }
  8~21 { H; g; s/\n/,/gp }' in_file
5
Graeme

データに常にいくつかの欠落フィールドがある場合(つまりレコード間で2つ以上のハードリターン)、単純に次のことができます。

$ awk -v RS="\\n{2,}" -F"\\n" -v OFS="," '{print $1, $3, $4, $5, $6, $7, $8}' file.txt
1500,18,02,09,47,17,45
1501,27,54,28,50,22,03
0
user61786