use strict; use warnings; use Getopt::Std; my %record; #hash to store fields of each record my @fields; #list of field names our $opt_s ; #collect command line switch my $sep = ':'; #default separator between field name and field value my ($name, $value); unless (@ARGV) { die " $0 Script to convert a file with fieldname and value on each line like this: Field1: Value Field2: Value Field3: Value Field1: Value ... into conventional CSV. Usage: [perl] $0 [-sSeparator] Source [> Destination] Default separator is colon. Use -s if you need to specify something else. Spaces between separator and field value are ignored. Source is the input file. Destination is (optional) output file. CSV data is sent to STDOUT so can be piped or redirected." } getopt('s'); #read -s switch on command line (if it's there) $sep = $opt_s if $opt_s ; #?use custom separator print STDERR "Separator is $sep\n" ; $/ = ""; #records delimited by blank lines; open INFILE, shift @ARGV or die "Couldn't open input file. $!"; #scan file to get all field names while () { chomp; foreach (split "\n") { #split into fields and iterate ($name, $value) = split /$sep\s*/, $_; $record{$name} = 0 ; #just put something into the hash } } #create and print list of fields found foreach $name (keys %record) { push @fields, $name; } print STDOUT join(',', @fields), "\n"; #reset the input file seek INFILE,0,0 or die "Could not reset input file for second pass. \n$!"; #now read the file again and output the restructured records while () { chomp; #clear field values in %record foreach $name (@fields) { $record{$name} = '' } ; #put new values into %record foreach (split "\n") { ($name, $value) = split /$sep\s*/, $_ ; $record{$name} = $value ; } #write record to STDOUT foreach $name (@fields) { $value = $record{$name}; #if the value contains a comma, double any quote marks it #contains and enclose the result in quotes if ($value =~ m/,/ ) { $value =~ s|\"|\"\"|g ; $value = '"' . $value . '"' ; } #append a comma except to the last field #or a newline to the last $value .= $name ne $fields[-1] ? ',' : "\n" ; print STDOUT $value ; } }