http://qs321.pair.com?node_id=1216291

vinoth.ree has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I am writing git pre-commit hook to verify the code before it get committed into git. As part of it I need to check the code extension correctly inserted in the code are not, if not I need to auto populate the file extension.

Below is the sample code begin get committed. Here the "@Filetyp" is empty, I need to update it with the file extension 'c'

@header_start
@Titel         : init 
@Filename      : test.c
@Filetyp       :
@Version       : 0001
@Produkt       : xx
@delivery      : xx
@date          : 20160610
@header_end

I tried the below perl one liner to replace the "@Filetyp :" as "@Filetyp :c"

my $ext='c'; qx("perl -p -i -e \"s/(\@Filetyp\\s*?:)/\\1$ext/\" /path/test.c")

Its get interpretered as below,

perl -p -i -e "s/(@Filetyp\s*?:)/\1c/" /path/test.c

But I did not get the expected output, it puts the 'c' letter in all the lines, as below

@header_start
@Titel         :c init 
@Filename      :c test.c
@Filetyp       :c
@Version       :c 0001
@Produkt       :c xx
@delivery      :c xx
@date          :c 20160610
@header_end

Pls someone tell me what I am doing wrong here...


All is well. I learn by answering your questions...

Replies are listed 'Best First'.
Re: perl one liner to replace matching string (updated x2)
by haukex (Archbishop) on Jun 10, 2018 at 10:18 UTC
    qx("perl -p -i -e \"s/(\@Filetyp\\s*?:)/\\1$ext/\" /path/test.c")

    It is extremely rare that you need to call another perl from inside a Perl script! I'm going to guess that you're doing it for the effect of the -i flag? You can get that feature from inside Perl using $^I:

    { # new scope for local local *ARGV; @ARGV = '/path/test.c'; local $^I = ""; # -i command line switch while (<>) { s/(\@Filetyp\s*?:)/$1 c/; print; } }

    Update: qx// is often problematic anyway!

    Update 2: Fixed this potential issue in the above example code.

Re: perl one liner to replace matching string
by Athanasius (Archbishop) on Jun 10, 2018 at 07:48 UTC

    Hello vinoth.ree,

    With warnings:

    use strict; use warnings; while (<DATA>) { s/(@Filetyp\s*?:)/\1c/; print; } __DATA__ @header_start @Titel : init @Filename : test.c @Filetyp : @Version : 0001 @Produkt : xx @delivery : xx @date : 20160610 @header_end

    Output:

    0:54 >perl 1895_SoPW.pl Possible unintended interpolation of @Filetyp in string at 1895_SoPW.p +l line 18. \1 better written as $1 at 1895_SoPW.pl line 18. Global symbol "@Filetyp" requires explicit package name (did you forge +t to declare "my @Filetyp"?) at 1895_SoPW.pl line 18. Execution of 1895_SoPW.pl aborted due to compilation errors. 17:41 >

    Perl sees @Filetyp as an (empty) array. Escape the sigil (and change \1 to $1):

    s/(\@Filetyp\s*?:)/$1 c/;.

    Output:

    17:44 >perl 1895_SoPW.pl @header_start @Titel : init @Filename : test.c @Filetyp : c @Version : 0001 @Produkt : xx @delivery : xx @date : 20160610 @header_end 17:44 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      I tried the below perl one liner to replace the "@Filetyp :" as "@Filetyp :c"

      my $ext='c'; qx("perl -p -i -e \"s/(\@Filetyp\\s*?:)/\\1$ext/\" /path/test.c");

      I am already doing it.Could you pls try like above perl one liner to replace the string?


      All is well. I learn by answering your questions...

        Ok, I get the same result as you reported. Playing around with it, I had to add two additional backslashes to get it to work as desired (not sure why):

        my $ext='c'; qx("perl -p -i.bak -e \"s/(\\\@Filetyp\\s*?:)/\\1$ext/\" ./path/test.c +"); # ^^

        (Note: I also had to specify an extension for the backup file.) This is on Windows; if your O/S is different, it may treat the backslashes differently.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: perl one liner to replace matching string
by jwkrahn (Abbot) on Jun 10, 2018 at 11:23 UTC
    qx("perl -p -i -e \"s/(\@Filetyp\\s*?:)/\\1$ext/\" /path/test.c")

    qx() is interpolated the same as a double quoted string so after interpolation the string "perl -p -i -e "s/(@Filetyp\s*?:)/\1$ext/" /path/test.c" is passed to the shell to execute.

    You should probably use single quotes around the substitution so that the shell doesn't mess with it, unless you are on Windows.

    The \1 capture variable should be $1 in the replacement string. \1 is only allowed inside the regular expression.

    To sum up, your code would be better written as (untested):

    my $ext = 'c'; qx(perl -p -i -e 's/\\Q@Filetyp\\E\\s*?:\\K/$ext/' /path/test.c)

    Although you may be better off using the solution that haukex provied.