ffe - flat file extractor


Next: , Previous: (dir), Up: (dir)

ffe

This file documents version 0.1.8 of ffe, a flat file extractor.

Copyright © 2006 Timo Savinen

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.


Next: , Previous: Top, Up: Top

1 Preliminary information

The ffe program is a used to extract fields from flat files and to print them in different formats. The input file structure and printing definitions are defined in a configuration file, which is always required. Default configuration file is ~/.fferc.

ffe is a command-line tool developed for GNU/linux and unix systems. ffe can read from standard input and write to standard output, so it can be used as a part of a pipeline.


Next: , Previous: Overview, Up: Top

2 Samples using ffe

One example of using ffe for printing personnel information in xml format from fixed length flat file:

     $ cat personnel
     john     Ripper       23
     Scott    Tiger        45
     Mary     Moore        41
     $

A file personnel contains three fixed length fields: `FirstName', `LastName' and `Age', their respective lengths are 9,13 and 2.

In order to print data above in xml, following configuration file must be available:

     $cat personnel.fferc
     structure personel {
         type fixed
         output xml
         record person {
             field FirstName 9
             field LastName  13
             field Age 2
         }
     }
     
     output xml {
         file_header "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
         data "<%n>%t</%n>\n"
         record_header "<%r>\n"
         record_trailer "</%r>\n"
         indent " "
     }
     $

Using ffe:

     $ffe -c personnel.fferc personnel
     <?xml version="1.0" encoding="ISO-8859-1"?>
      <person>
       <FirstName>john</FirstName>
       <LastName>Ripper</LastName>
       <Age>23</Age>
      </person>
      <person>
       <FirstName>Scott</FirstName>
       <LastName>Tiger</LastName>
       <Age>45</Age>
      </person>
      <person>
       <FirstName>Mary</FirstName>
       <LastName>Moore</LastName>
       <Age>41</Age>
      </person>
     $


Next: , Previous: Samples, Up: Top

3 How to run ffe

ffe is a command-line tool. Normally ffe can be invoked as:

ffe -o OUTPUTFILE INPUTFILE

ffe uses the definitions from ~/.fferc and tries to guess the inputfile structure using the first 10 000 lines or 1 MB of input data.

If the structure cannot be guessed the option -s must be used.


Next: , Up: Invoking ffe

3.1 Program invocation

The format for running the ffe program is:

     ffe option ...

ffe supports the following options:

-c file
--configuration=file
Configuration is read from file, instead of ~/.fferc.
-s structure
--structure=structure
Use structure structure for input file, suppresses guessing.
-p output
--print=output
Use output format output for printing. If not defined, then the record or structure related output format is used. Printing can be suppressed using format no.
-o file
--output=file
Write output to file instead of standard output.
-f list
--field-list=list
Print only fields expresses in comma separated list list. Order of fields in list defines also the printing order.
-e expression
--expression=expression
Print only those records for which the expression evaluates to true.
-a
--and
Expressions are combined with logical and, default is logical or.
-v
--invert-match
Print only those records which don't match the expression.
-l
--loose
Normally ffe stops when it encounteres an input line which doesn't match any of the records in selected structure. Defining this option causes ffe continue despite the error.
-r
--replace=field=value
Replace fields contents with value in output. value can contain same directives as output option data.
-?
--help
Print an informative help message describing the options and then exit successfully.
-V
--version
Print the version number of ffe and then exit successfully.

All remaining options are names of input files, if no input files are specified or - is given, then the standard input is read.

Expressions (option -e, --expression)

Expression can be used to select specific records comparing field values. Expression has syntax fieldxvalue, where x is the comparison operator. Expression is used to compare field's contents to value and if comparison is successfull the record is printed. Several expressions can be defined and at least one must evaluate to true in order to print a record. If option -a is defined all expressions must evaluate to true.

Expressions can be defined as:

field=value
Field field is equal to value.
field^value
Field field starts with value.
field~value
Field field contains value.
field!value
Field field is not equal to value.


Next: , Previous: Invocation, Up: Invoking ffe

3.2 Configuration

ffe uses a configuration file in order to read the input file and print the output. Default configuration file is ~/.fferc.

Configuration file for ffe is a text file. The file may contain empty lines. Commands are case-sensitive. Comments begin with the #-character and end at the end of the line. The string definitions can be enclosed in double quotation " characters. char is a single character. string and char can contain following escape codes: \a, \b, \t, \n, \v, \f, \r, \" and \#. A backslash can be escaped as \\.

Configuration has two main parts: the structure, which defines the input file structure and the output, which defines how the input data is formated for output.

Common syntax

Common syntax for configuration file is:

     #comment
     structure name {
         option value ...
         ...
         record name {
             option value ...
             ...
         }
         record name {
             option value ...
             ...
         }
         ...
     }
     structure name {
         ...
     }
     ...
     output name {
         option value ...
         ...
     }
     output name {
         ...
     }
     ...

Structure

Keyword structure is used to define an input file content. An input file can contain several types of records (or lines). E.g. file can have a header, data and trailer record types. Records must be distinguishable from each other, this can be achieved defining different 'keys' (id in record definition) or having different line lengths (for fixed length structure) or different count of fields (for separated structure) for different records.

Typically a structure maps to a file and a records maps to a line in the file.

A structure is defined as:

     structure name {
         option value ...
         ...
     }

A structure can contain following options:

type fixed|separated [char] [*]
The fields in the input are fixed length fields or separated by char. If * is defined, multiple sequential separators are considered as one. Default separator is comma.
quoted [char]
Fields may be quoted with char, default quotation mark is double quotation mark '"'. A quotation mark is assumed be escaped as \char or doubling the mark as charchar in input. Non escaped quotation marks are not preserved in output.
header first|all|no
Controls the occurrence of the header line. Default is no. If set as first or all, the first line of the first input file is considered as header line containing the names of the fields. first means that only the first file has a header, all means means that all files have a header, allthough the names are still taken from the the header of the first file. Header line is handled according the record definition, meaning that the name positions, separators etc. are the same as for fields.
output name
All records belonging this structure are printed according output format name. Default is to use output named as `default'.
record name {options ...}
Defines one record for a structure. A structure can contain several record types.

Record

A record defines one type of input line in a file. Different records can be distinguished using the id option or different line lengths or field counts.

A record can contain following options:

id position string
Identifies a record in the input file. Records are identified by the string in input record position position. For fixed length input the position is the byte position of input record and for separated input the position is the position'th field of the input record. Positions start from one.

A record definition can contain several id's, then all id'd must match the input line (id's are anded).

field name|FILLER|* [length]
Defines one field in input structure. length is mandatory for fixed length input structure. Length is also used for printing the fields in fixed length format (directive %D in output definitions). The order of fields in configuration file is essential, it defines the field order in a record.

If * is defined instead of the name, then the name will be the ordinal number of the field, or if the header option has value first or all, then the name of the field will taken from the header line (first line of the input).

If field is named as FILLER, the field will not appear in output.

fields-from record
Fields for this record are the same as for record record. field and fields-from are mutually exclusive.

Output

Keyword output defines one output format for formatting the flat file data. Formatting is controlled using options and printf-style directives. An output defition is allways independent from structure, so one output format can be used with different input file formats.

Actual formatting and printing is controlled using pictures in output options. Pictures can contain following printf-style directives:

%f
Name of the input file.
%s
Name of the current structure.
%r
Name of the current record.
%o
Input record number in current file.
%O
Input record number starting from the first file.
%n
Field name.
%t
Field contents, without leading and trailing whitespaces.
%d
Field contents.
%D
Field contents, right padded to the field length (requires length definition for the field).
%p
Fields start position in a record. For fixed structure this is field's byte position in the input line and for separated structure this is the ordinal number of the field. Starts from one.
%e
Does not print anything, causes still the "field empty" check to be performed. Can be used when only the names of non-empty fields should be printed.
%%
Percent sign.

Output options:

file_header picture
picture is printed once before file contents.
file_trailer picture
picture is printed once after file contents.
header picture
If defined, then the header line describing the field names is printed before records. Every field name is printed according the picture using the same separator and fields length as defined for the fields. Picture can contain only %n directive.
data picture
Field contents is printed according picture.
separator string
All fields are terminated by string, except the last field of the record. Default is not to print separator.
record_header picture
All records are started by picture. Default is not to print the record header.
record_trailer picture
All records are ended with picture. Default is newline.
justify left|right|char
The output from the data option is left or right justified. char justifies output according the first occurrence of char in the data picture. Default is left.
indent string
Record contents is intended by string. Field contents is intended by two times the string. Default is not to indent.
field-list field1,field2,...
Only fields named as field1,field2,... are printed, same effect as has option -f. Default is print all fields. Fields are also printed in the same order as they are listed.
no-data-print yes|no
If field-list is defined and and this is set as no and none of the fields in field-list does not belong to the current record, then the record_header and record_trailer are not printed. Default is yes.
field-empty-print yes|no
When set as no, nothing is printed for fields which consist entirely of characters from empty-chars. If none of the fields of a record are printed, then the printing of record_trailer is also suppressed. Default is yes.
empty-chars string
string defines a set of characters which define an "empty" field. Default is " \f\n\r\t\v" (space, form-feed, newline, carriage return, horizontal tab and vertical tab).


Next: , Previous: Configuration, Up: Invoking ffe

3.3 Guessing

If -s is not given, ffe tries to guess the input structure. ffe reads first 10 000 lines or 1 MB of input data and tries to match the structure definitions from configuration file to input stream. If all lines match one and only one structure, the structure is used for reading the input file.

Guessing uses following execution cycle:

  1. Input line is read
  2. All record id's are compared to the input line, if all id's of a record match the input line and the records line length matches the total length (or total count for separated structure) of the fields, the record is considered to match the input line. If there are no id's, only the line length or field count is checked.
  3. If all lines match at least one of the records in a particular structure, the structure is considered as selected. There must be only one structure matching all lines used for guessing.


Previous: Guessing, Up: Invoking ffe

3.4 Limitations

At least in GNU/Linux ffe should be able to handle big files (> 4 GB), other systems are not tested.


Next: , Previous: Invoking ffe, Up: Top

4 How ffe works

Following examples use two different input files:

Fixed length example

Fixed length personnel file with header and trailer, line (record) is identified by the first byte (H = Header, E = Employee, B = Boss, T = trailer).

     $cat personnel.fix
     H2006-02-25
     EJohn     Ripper       23
     BScott    Tiger        45
     EMary     Moore        41
     ERidge    Forrester    31
     T0004
     $

Structure for reading file above. Note that record `boss' reuses fields from `employee'.

     structure personel_fix {
         type fixed
         record header {
             id 1 H
             field type 1
             field date 10
         }
         record employee {
             id 1 E
             field EmpType 1
             field FirstName 9
             field LastName  13
             field Age 2
         }
         record boss {
             id 1 B
             fields-from employee
         }
         record trailer {
             id 1 T
             field type 1
             field count 4
         }
     }

Separated example

Sama file as above, but now separated by colon.

     $cat personnel.sep
     H,2006-02-25
     E,john,Ripper,23
     B,Scott,Tiger,45
     E,Mary,Moore,41
     E,Ridge,Forrester,31
     T,0004
     $

Structure for reading file above. Note that the field lengths are not needed in separated format.

     structure personel_sep {
         type separated ,
         record header {
             id 1 H
             field type
             field date
         }
         record employee {
             id 1 E
             field type
             field FirstName
             field LastName
             field Age
         }
         record boss {
             id 1 B
             fields-from employee
         }
         record trailer {
             id 1 T
             field type
             field count
         }
     }

Printing in XML-format

Data in examples above can be printed in xml using output definition like:

     output xml {
         file_header "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
         data "<%n>%t</%n>\n"
         record_header "<%r>\n"
         record_trailer "</%r>\n"
         indent " "
     }

Example output using command (assuming definitions above are saved in ~/.fferc)

ffe -p xml personnel.sep

     <?xml version="1.0" encoding="UTF-8"?>
      <header>
       <type>H</type>
       <date>2006-02-25</date>
      </header>
      <employee>
       <type>E</type>
       <FirstName>john</FirstName>
       <LastName>Ripper</LastName>
       <Age>23</Age>
      </employee>
      <boss>
       <type>B</type>
       <FirstName>Scott</FirstName>
       <LastName>Tiger</LastName>
       <Age>45</Age>
      </boss>
      <employee>
       <type>E</type>
       <FirstName>Mary</FirstName>
       <LastName>Moore</LastName>
       <Age>41</Age>
      </employee>
      <employee>
       <type>E</type>
       <FirstName>Ridge</FirstName>
       <LastName>Forrester</LastName>
       <Age>31</Age>
      </employee>
      <trailer>
       <type>T</type>
       <count>0004</count>
      </trailer>

Printing sql-commands

Data in examples above can be loaded to database by generated sql-commands. Note that the header and trailer are not loaded, because only fields `FirstName',`LastName' and `Age' are printed and `no-data-print' is set as no. This prevents the `record_header' and `record_trailer' to be printed for file header and trailer.

     output sql {
         file_header "delete table boss;\ndelete table employee;\n"
         record_header "insert into %r values("
         data "'%t'"
         separator ","
         record_trailer ");\n"
         file_trailer "commit\nquit\n"
         no-data-print no
         field-list FirstName,LastName,Age
     }

Output from command

ffe -p sql personnel.sep

     delete table boss;
     delete table employee;
     insert into employee values('john','Ripper','23');
     insert into boss values('Scott','Tiger','45');
     insert into employee values('Mary','Moore','41');
     insert into employee values('Ridge','Forrester','31');
     commit
     quit

Human readable output

This output format shows the fields suitable for displaying in screen or printing.

     output nice {
         record_header "%s - %r - %f - %o\n"
         data "%n=%t\n"
         justify =
         indent " "
     }

Output from command

ffe -p nice personnel.fix

      personel - header - personnel.fix - 1
       type=H
       date=2006-02-25
     
      personel - employee - personnel.fix - 2
            EmpType=E
       FirstName=John
        LastName=Ripper
             Age=23
     
      personel - boss - personnel.fix - 3
            EmpType=B
       FirstName=Scott
        LastName=Tiger
             Age=45
     
      personel - employee - personnel.fix - 4
            EmpType=E
       FirstName=Mary
        LastName=Moore
             Age=41
     
      personel - employee - personnel.fix - 5
            EmpType=E
       FirstName=Ridge
        LastName=Forrester
             Age=31
     
      personel - trailer - personnel.fix - 6
        type=T
       count=0004

HTML table

Personnel data can be displayed as HTML table using output like:

     output html {
         file_header "<html>\n<head>\n</head>\n<body>\n<table border=\"1\">\n<tr>\n"
         header "<th>%n</th>\n"
         record_header "<tr>\n"
         data "<td>%t</td>\n"
         file_trailer "</table>\n</body>\n</html>\n"
         no-data-print no
     }

Output from command

ffe -p html -f FirstName,LastName,Age personnel.fix

     <html>
     <head>
     </head>
     <body>
     <table border="1">
     <tr>
     <th>FirstName</th>
     <th>LastName</th>
     <th>Age</th>
     
     <tr>
     <td>John</td>
     <td>Ripper</td>
     <td>23</td>
     
     <tr>
     <td>Scott</td>
     <td>Tiger</td>
     <td>45</td>
     
     <tr>
     <td>Mary</td>
     <td>Moore</td>
     <td>41</td>
     
     <tr>
     <td>Ridge</td>
     <td>Forrester</td>
     <td>31</td>
     
     </table>
     </body>
     </html>

Using expression

Printing only Scott's record using expression with previous example:

ffe -p html -f FirstName,LastName,Age -e FirstName^Scott personnel.fix

     <html>
     <head>
     </head>
     <body>
     <table border="1">
     <tr>
     <th>FirstName</th>
     <th>LastName</th>
     <th>Age</th>
     
     <tr>
     <td>Scott</td>
     <td>Tiger</td>
     <td>45</td>
     
     </table>
     </body>
     </html>

Using replace

Make all boses and write a new personnel file printing the fields in fixed length format using directive %D:

Output definition:

     output fixed
     {
         data "%D"
     }

Write a new file:

     $ffe -p fixed -r EmpType=B -o personnel.fix.new personnel.fix
     $cat personnel.fix.new
     H2006-02-25
     BJohn     Ripper       23
     BScott    Tiger        45
     BMary     Moore        41
     BRidge    Forrester    31
     T0004
     $

The whole configuration file used in examples

     structure personel_fix {
         type fixed
         record header {
             id 1 H
             field type 1
             field date 10
         }
         record employee {
             id 1 E
             field EmpType 1
             field FirstName 9
             field LastName  13
             field Age 2
         }
         record boss {
             id 1 B
             fields-from employee
         }
         record trailer {
             id 1 T
             field type 1
             field count 4
         }
     }
     
     structure personel_sep {
         type separated ,
         record header {
             id 1 H
             field type
             field date
         }
         record employee {
             id 1 E
             field type
             field FirstName
             field LastName
             field Age
         }
         record boss {
             id 1 B
             fields-from employee
         }
             record trailer {
             id 1 T
             field type
             field count
         }
     }
     
     output xml {
         file_header "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
         data "<%n>%t</%n>\n"
         record_header "<%r>\n"
         record_trailer "</%r>\n"
         indent " "
     }
     
     output sql {
         file_header "delete table boss;\ndelete table employee;\n"
         record_header "insert into %r values("
         data "'%t'"
         separator ","
         record_trailer ");\n"
         file_trailer "commit\nquit\n"
         no-data-print no
         field-list FirstName,LastName,Age
     }
     
     output nice {
         record_header "%s - %r - %f - %o\n"
         data "%n=%t\n"
         justify =
         indent " "
     }
     
     output html {
         file_header "<html>\n<head>\n</head>\n<body>\n<table border=\"1\">\n<tr>\n"
         header "<th>%n</th>\n"
         record_header "<tr>\n"
         data "<td>%t</td>\n"
         file_trailer "</table>\n</body>\n</html>\n"
         no-data-print no
     }
     
     output fixed
     {
         data "%D"
     }

Using ffe to test file integrity

ffe can be used to check flat file integrity, because ffe checks for all lines the line length and id's for fixed length structure and field count and id's for separated structure.

Integrity can be checked using command

ffe -p no -l inputfiles...

Because option -p has value no nothing is printed to output except the error messages. Option -l causes all errorneous lines to be reported, not just the first one.

Example output:

     ffe: Invalid input line in file 'inputfileB', line 14550
     ffe: Invalid input line in file 'inputfileD', line 12


Previous: ffe configuration, Up: Top

5 Reporting Bugs

If you find a bug in ffe, please send electronic mail to tjsa@iki.fi. Include the version number, which you can find by running `ffe --version'. Also include in your message the output that the program produced and the output you expected.

If you have other questions, comments or suggestions about ffe, contact the author via electronic mail to tjsa@iki.fi. The author will try to help you out, although he may not have time to fix your problems.

Table of Contents