0

I'm pretty new to Perl and have the following issue: I'm trying to replace a version number in a .yml file with a different value. This is what my regex looks like:

version:\s*([^\s]+)

It works so far, but it does not do what I like it to do.

Here the code that I currently have, and the Perl statement to replace the value in the .yml file.

file content(./test.yml):

app:
  version: 1.2
  name: abc

code:

$search = "version:\s*([^\s]+)";
$replace = '1.3';
perl -pie 's/$search/$replace/m' ./test.yml;

Any help would be greatly appreciated!

Stefan
  • 214
  • 1
  • 12

2 Answers2

5

Why are you trying to re-implement a YAML parser in a one-liner?!

perl -MYAML=DumpFile,LoadFile -e'
   my $d = LoadFile($ARGV[0]);
   $d->{app}{version} = "1.3";
   DumpFile($ARGV[0], $d);
' test.yml

It seems unlikely that the new version should be hardcoded like that.

  • Version comes from the outside.

    perl -MYAML=DumpFile,LoadFile -e'
       my $d = LoadFile($ARGV[0]);
       $d->{app}{version} = $ARGV[1];
       DumpFile($ARGV[0], $d);
    ' test.yml 1.3
    
  • Version should be incremented.

    perl -MYAML=DumpFile,LoadFile -e'
       my $d = LoadFile($ARGV[0]);
       $d->{app}{version} =~ s/\.\K(.*)/ $1+1 /e;
       DumpFile($ARGV[0], $d);
    ' test.yml
    
ikegami
  • 367,544
  • 15
  • 269
  • 518
3

Your regex seems fine, but your use of the perl command-line tool needs justifying:

perl -pi -e 's/(?<=version:).*/ 1.3/' test.yml

Takeaways:

  • Use \S instead of [^\s].
  • Use perl -pi -e and not perl -pie. (-i takes an optional argument.)

Depending on whether this is a one-time use regex or code that will be deployed, consider making the regex sensitive to the context of (a) app and (b) a version number lower than 1.3; i.e. don't just bump any version number found in the file to 1.3.

  • Addressing (a),

    perl -pi -e '$toplevel = $1 if /^(\S+)$/; s/(?<=version:).*/ 1.3/ if $toplevel eq "app"' test.yml
    

    This would push app's 1.2 to 1.3 without touching wat's in the following file:

    app
      version: 1.2
      name: abc
    
    wat
      version: 1.2
      name: wat
    
  • Addressing (b),

    perl -pi -e 's/(?<=version:)\s*(\d+(?:\.\d+)?)/" " . ($1 < 1.3 ? 1.3 : $1)/e' test.yml
    
sshine
  • 15,635
  • 1
  • 41
  • 66
  • Thanks for this Simon. (a) makes the most sense for my use case. However, I'm not able to make it work. In the use case I'm looking at the app / wat level in your example are not on the top but rather within the structure (3rd level). I tried to remove the caret from the regex, but no luck. Any ideas? – Stefan Apr 03 '18 at 15:59
  • 1
    @Stefan: I can only answer questions that you ask. You're in irregular land here; you might be able to grab it by `^\s*app$` (but do note @ikegami's suggestion that this isn't valid YAML without an ending `:`, in which case you're building a simplistic YAML parser). Since the file is not so simple as you suggested, I'd recommend you go and use @ikegami's solution using the YAML package. You can install it with `cpan -i YAML`. – sshine Apr 04 '18 at 06:10