単一のテキストファイルの単語でファイルを生成するスクリプトが必要です。

単一のテキストファイルの単語でファイルを生成するスクリプトが必要です。

以下のシナリオがありますが、Linuxの知識が不足してもあまり役に立ちません。

次の内容のYML値を含むテキストファイルがあります。

coolregion:
  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
  owners:
    groups: [jacob, eithan, michael]
  members:
    groups: [jack, noah]
niceregion:
      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
  owners:
    groups: [noah]
  members:
    groups: [logan, lucas, jack]

それぞれの名前とそれが属する領域のファイルを生成したいと思います。

たとえば、銀がnoah.txt含まれます。coolregion, niceregionjacob.txtcoolregion

私は正規表現をかなりよく知っているので、正しい方向(例:正規表現だけでトリックを実行するスクリプト)を教えてくれてうれしいです。

重要な場合、私のLinuxバージョンは「Debian GNU / Linux 5.0」です。

答え1

これはawkソリューションです。私はYMLがわからないので、正規表現を操作する必要があるかもしれません(例えば、領域マーカーをインデントできますか?)。このprint data >filename構成は、指定されたファイル名に最初に到達したときにファイルを作成または切り取り、それをファイルに追加します。

<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
}'

あまり真剣に受け入れられませんが、ここにsedとShellソリューションがあります。

<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"
    done
  done
)

答え2

「パール」ソリューション:

スクリプト:

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

関連情報