0

I have this simple code

perl -we 'my $file= "
    #    parameter=10
#    parameter=10
# parameter=10
    parameter=10
parameter=10
"; $file=~ s/((?<!# ))\s*parameter\s*=.*/parameter=replaced/g; print(":$file:\n")'

and I want it to replace all parameter=10 but not if it is preceeded by a hash anywhere on that line. e.g.

        #    parameter=10
#    parameter=10
# parameter=10
        parameter=replaced
parameter=replaced

i know that if I provide a

((?<!#\s*))

I get an error

Variable length lookbehind not implemented in regex

So is there a way to do the task by any other means?

Thanks

1

You can do something like:

s/#.*|((?<!\S)parameter\h*=.*)/$1 ? "parameter=replaced" : $&/ge;

The idea is that the #.* (which we replace with itself) will munch away all the comments. And in the second part of the alternation, we look for your pattern (here parameter=... provided its not preceded by a non-whitespace) in what's left.

Another approach is to use:

s/^[^#\n]*\K(?!<\S)parameter\h*=.*/parameter=replaced/gm;

\K sets the start of the part to replace. The m flag makes ^ match at the start of every line inside the subject.

If those parameter= are only to be found at the start of the lines (followed by optional blanks), then that's just:

s/^\h*\Kparameter\h*=.*/parameter=replaced/gm;
  • your first example worked very well. – conanDrum May 28 at 17:41
  • second example s/^[^#]*\K(?!<\S)parameter\h*=.*/parameter=replaced/gm replaced ONLY the last line. can you look at it? – conanDrum May 28 at 17:44
  • @conanDrum, yes sorry. [^#] would also match on newline. See edit – Stéphane Chazelas May 28 at 17:56
  • @ Stéphane Chazelas excellent. I am prepared to give you the answer provided you do a nice breakdown for any person interested in this. We do not want this to be a blockage for anyone, even myself. So please do your best to explain to us so we can implement methods like this. Thank you very much for providing this answer – conanDrum May 28 at 17:58
0

Well, the only alternative I could come up with is this:

FILESECTION="\
        #    parameter=10
#    parameter=10
#  parameter=10
        parameter=10
parameter=10
"

newfile=''
while IFS= read -r line ; 
    do 

    SECTIONFIXED=$( perl -le '$file=$ARGV[0]; $file=~ s/^(?!#+$)(\s*)(parameter\s*=.*)/parameter=replaced/g; print("$file\n");' "${line}" ; ) 
    newfile=$( printf "${newfile}\n${SECTIONFIXED}\n" )  
done <<< "$FILESECTION"

echo "$newfile" 

Output:

        #    parameter=10
#    parameter=10
#  parameter=10
parameter=replaced
parameter=replaced

We have to use '^(?!#+$)(\s*)' negative lookahead line by line. And it accepts variable lengths (maybe because it is not on a multiline string? don't know yet.)

I came across this idea https://www.regextester.com/95226 and finally got it going.

I learned something new today. Hope you find this useful!

PS. we could also use a simple ([^#]*) as suggested by terdon https://unix.stackexchange.com/a/521512/354415 who suggested basically the same concept as here but implemented in a perl one liner! very nice !

  • That regexp doesn't make sense. (?!#+$) is pointless because there's no way the line will be made up of one or more # if it's to match \s*parameter=... – Stéphane Chazelas May 28 at 17:16
  • The first argument of printf is the format. It shouldn't have variable data. – Stéphane Chazelas May 28 at 17:17
  • It makes no sense to use a shell loop that calls perl for each line of some text. perl is much much more capable programming language to process text than a shell. – Stéphane Chazelas May 28 at 17:19
  • @ Stéphane Chazelas quite right. Terdon provided a better way in the other thread – conanDrum May 28 at 17:25
  • @ Stéphane Chazelas don't see how its pointless if it works – conanDrum May 28 at 17:26

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.