I have the following scenario and my lack of linux knowledge doesn't help a lot.

I have a text file that contains YML values, in the following matters:

  min: {z: -99613.0, y: 45.0, x: -99805.0}
  flags: {vehicle-place: allow}
  max: {z: 100387.0, y: 127.0, x: 100195.0}
  priority: 0
  type: cuboid
    groups: [jacob, eithan, michael]
    groups: [jack, noah]
      min: {z: 544.0, y: 6.0, x: 184.0}
  flags: {}
  max: {z: 556.0, y: 13.0, x: 197.0}
  priority: 0
  type: cuboid
    groups: [noah]
    groups: [logan, lucas, jack]

I want to generate files for each name with the regions that he belongs to.

For example noah.txt will contain coolregion, niceregion while jacob.txt will contain coolregion only.

I know regex pretty well so I'd be also pleased if you only point me to the right direction (i.e. a script that only needs the regex to complete).

If it matters, my linux version is "Debian GNU/Linux 5.0".


Here's an awk solution. I don't know YML, so you may need to fiddle with the regexps (e.g. can the region marker be indented?). Note that the print data >filename construct creates or truncates the file the first time it's reached for a given file name, and then appends to the file.

<input.yml awk '
/^[^ :]+: *$/ {sub(/: *$/,""); region=$0}     # start of region
/^ *groups:/ {                                # owner or member list
    sub(/^[^:]*: *\[/, ""); sub(/\].*/, "");  # extract bracketed names
    split($0, names, / *, */);                # split comma-separated list
    for (n in names)                          # iterate over names
        print region >names[n] ".txt";        # write or append to name file

Don't take it too seriously, but here's a sed and shell solution.

<input.yml sed -n -e '/^[^ ]/ h' \
                  -e '/^ \+groups:/ {' \
                    -e 'G' \
                    -e 's/^[^:]*: *\[\(.*\)\]\n\(.*\):/\2,\1/' \
                    -e 's/, \+/,/g' \
                    -e 'p' -e '}' | (
  IFS=,; set -f
  while read -r region names; do
    for name in $names; do
      echo "$region" >>"$name.txt"
| improve this answer | |
  • Thanks a lot, it works lovely. The regions are indeed indent so I added 2 spaces before the [^ :]+: to make it work. YML is all about the right number of spaces :) – yellowblood May 8 '11 at 21:07

A 'perl' solution:


use warnings;                                                                                                                                                                       
use strict;                                                                                                                                                                         

die "Usage: perl $0 file\n" unless @ARGV == 1;                                                                                                                                      

my (%hash, $region);                                                                                                                                                                

open my $fh, "<", $ARGV[0] or die "Cannot open file $ARGV[0]: $!\n";                                                                                                                

while ( my $line = <$fh> ) {                                                                                                                                                        

        ## Get region, characters until first ':' without spaces at the beginning.                                                                                                  
        $region = $1 if $line =~ /^([^:\s]+)/;                                                                                                                                      

        ## Get names with a regex and save them as keys of a hash, values will be                                                                                                   
        ## regions.                                                                                                                                                                 
        if ( $line =~ /^\s*(?i:groups):\s*\[([^\]]*)\]\s*$/ ) {                                                                                                                     
                my @names = split /,\s*/, $1;                                                                                                                                       
                for my $name ( @names ) {                                                                                                                                           
                        push @{ $hash{ $name } }, $region;                                                                                                                          

## Read names (keys of the hash), open a file for each one and write regions on it.                                                                                                 
for my $name ( sort keys %hash ) {                                                                                                                                                  
        my $outfile = $name . ".txt";                                                                                                                                               
        open my $ofh, ">", $outfile or do { warn "Cannot open $outfile: $!\n"; next };                                                                                              
        print $ofh join( ", ", @{ $hash{ $name } } ), "\n";                                                                                                                         
        close $ofh or warn "Cannot close $outfile\n";                                                                                                                               

close $fh or warn "Cannot close $ARGV[0]\n";


$ perl script.pl infile
| improve this answer | |
  • If you're using Perl, you can fairly easily use an actual YAML parser, which would add some robustness. – Tom Anderson Jun 29 '11 at 17:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.