The regular expression for the history of commands executed from script names

I'm trying to write a regular expression that will parse the syntax to invoke the script, and grab the name of the script.

All this is valid syntax for the call

# normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \ script.bi 

This is what I still have

 my $r = q{run +(?:cred=(?:[^\s\']*|\'.*\') +)?([^\s\\]+)}; 

to lock in the value $1 .

But I get

 Unmatched [ before HERE mark in regex m/run +(?:cred=(?:[^\s\']*|\'.*\') +)?([ << HERE ^\s\]+)/ 
+4
source share
3 answers

\\ is treated as \ , and hence it becomes a regular expression \] , so avoiding ] and, consequently, an unsurpassed [

Replace run +(?:cred=(?:[^\s\']*|\'.*\') +)?([^\s\\\\]+) (Note \\\\ ) and try.

In addition, the comments you should use the qr for the regular expression, not just q .

(I just looked at the error, and not on the correctness / effectiveness of the regular expression for your problem)

+3
source

The essence of your problem, indicating a regular expression - a difference of one byte: q compared to qr . You write a regular expression, so to call it by what it is. Template processing in the form of a line means that you need to deal with the rules for quoting lines at the top of the rules for the displacement of regular expressions.

As for the language that matches your regular expression, add bindings to make the pattern match the entire string. Regex engine is rigidly determined and will continue to run until it finds a match. Without anchors he was happy to find a substring.

Sometimes it gives you unexpected results. Have you ever been treated with irritable child (or child-adult), which takes a narrow, extremely literal interpretation of what you're saying? Regular expressions - this way, but he's trying to help.

In the last example is appropriate because

  • You said quantified ? That subpattern cred=... can coincide with zero time, so the regex mechanism missed it.
  • You said that the name of the script - this is the next substring that starts one or more characters without spaces, without a backward slash, so regex mechanism seen cred=username/password , neither of which is not a space character or a backslash, and does not match, regular expressions are greedy: they consider a right to them, regardless of whether this substring "should" match the other subpattern.

The latest example for the account - but not the way you expected. An important lesson of regular expressions is any quantifier, such as ? or * which can coincide with the zero time, there will always be successful!

Without committing $ template of your question leaves the final backslash unsurpassed, you can see a slight modification of $runpat .

 qr{run +(?:cred=(?:[^\s']*|\'.*\') +)?([^\s\\]+)(.*)}; # ' SO hiliter hack 

Note the (.*) At the end to capture any newline characters, which can be left. Change cycle to

 while (<DATA>) { next unless /$runpat/; print "line $.: \$1=[$1]; \$2=[$2]\n"; } 

It gives the following output for a line 15.

  line 15: $ 1 = [cred = username / password];  $ 2 = [\] 

Like a complete program that becomes

 #! /usr/bin/env perl use strict; use warnings; # The goofy comment on the next line is a hack to # help Qaru syntax highlighter recover # from its confusion after seeing the quotes. It's # for presentation only: you won't need it in your # real code. my $runpat = qr{^\s*run +(?:cred=(?:[^\s']*|\'.*\') +)?([^\s\\]+)$}; # ' while (<DATA>) { next unless /$runpat/; print "line $.: \$1=[$1]\n"; } __DATA__ # normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \ script.bi is a hack to #! /usr/bin/env perl use strict; use warnings; # The goofy comment on the next line is a hack to # help Qaru syntax highlighter recover # from its confusion after seeing the quotes. It's # for presentation only: you won't need it in your # real code. my $runpat = qr{^\s*run +(?:cred=(?:[^\s']*|\'.*\') +)?([^\s\\]+)$}; # ' while (<DATA>) { next unless /$runpat/; print "line $.: \$1=[$1]\n"; } __DATA__ # normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \ script.bi . #! /usr/bin/env perl use strict; use warnings; # The goofy comment on the next line is a hack to # help Qaru syntax highlighter recover # from its confusion after seeing the quotes. It's # for presentation only: you won't need it in your # real code. my $runpat = qr{^\s*run +(?:cred=(?:[^\s']*|\'.*\') +)?([^\s\\]+)$}; # ' while (<DATA>) { next unless /$runpat/; print "line $.: \$1=[$1]\n"; } __DATA__ # normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \ script.bi need it in your #! /usr/bin/env perl use strict; use warnings; # The goofy comment on the next line is a hack to # help Qaru syntax highlighter recover # from its confusion after seeing the quotes. It's # for presentation only: you won't need it in your # real code. my $runpat = qr{^\s*run +(?:cred=(?:[^\s']*|\'.*\') +)?([^\s\\]+)$}; # ' while (<DATA>) { next unless /$runpat/; print "line $.: \$1=[$1]\n"; } __DATA__ # normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \ script.bi s * run + (?: cred = (: [^ \ s'] * | \ '* \') +?.) ([^ \ s \\] +) $?} #! /usr/bin/env perl use strict; use warnings; # The goofy comment on the next line is a hack to # help Qaru syntax highlighter recover # from its confusion after seeing the quotes. It's # for presentation only: you won't need it in your # real code. my $runpat = qr{^\s*run +(?:cred=(?:[^\s']*|\'.*\') +)?([^\s\\]+)$}; # ' while (<DATA>) { next unless /$runpat/; print "line $.: \$1=[$1]\n"; } __DATA__ # normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \ script.bi in a different way #! /usr/bin/env perl use strict; use warnings; # The goofy comment on the next line is a hack to # help Qaru syntax highlighter recover # from its confusion after seeing the quotes. It's # for presentation only: you won't need it in your # real code. my $runpat = qr{^\s*run +(?:cred=(?:[^\s']*|\'.*\') +)?([^\s\\]+)$}; # ' while (<DATA>) { next unless /$runpat/; print "line $.: \$1=[$1]\n"; } __DATA__ # normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \ script.bi lines using \ #! /usr/bin/env perl use strict; use warnings; # The goofy comment on the next line is a hack to # help Qaru syntax highlighter recover # from its confusion after seeing the quotes. It's # for presentation only: you won't need it in your # real code. my $runpat = qr{^\s*run +(?:cred=(?:[^\s']*|\'.*\') +)?([^\s\\]+)$}; # ' while (<DATA>) { next unless /$runpat/; print "line $.: \$1=[$1]\n"; } __DATA__ # normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \ script.bi 

Output:

  line 2: $ 1 = [script.bi]
 line 5: $ 1 = [script.bi]
 line 8: 1 $ = [script.bi]
 line 11: $ 1 = [script] 

Compatibility is not always useful with regular expressions. Consider the following alternative but equivalent specification:

 my $runpat = qr{ ^ \s* (?: run \s+ cred=(?:[^\s']*|'.*?') \s+ (?<script> [^\s\\]+) # ' hiliter | run \s+ (?!cred=) (?<script> [^\s\\]+) ) \s* $ }x; '\ s + (<script> [^ \ s \\] +?) # hiliter ([^ \ s'] * '*?.?)' my $runpat = qr{ ^ \s* (?: run \s+ cred=(?:[^\s']*|'.*?') \s+ (?<script> [^\s\\]+) # ' hiliter | run \s+ (?!cred=) (?<script> [^\s\\]+) ) \s* $ }x; =) (? <script> [^ \ s \\] +) my $runpat = qr{ ^ \s* (?: run \s+ cred=(?:[^\s']*|'.*?') \s+ (?<script> [^\s\\]+) # ' hiliter | run \s+ (?!cred=) (?<script> [^\s\\]+) ) \s* $ }x; 

Yes, it takes more space to write, but it is more clear as acceptable alternatives. Your loop is pretty much the same

 while (<DATA>) { next unless /$runpat/; print "line $.: script=[$+{script}]\n"; } $ + {script}] \ n"; while (<DATA>) { next unless /$runpat/; print "line $.: script=[$+{script}]\n"; } 

and even eliminates the poor reader from having to count parentheses.

To use named capture buffers, for example, (?<script>...) , be sure to add

 use 5.10.0; 

at the top of your program to provide executable documentation on the minimum required version of perl.

+3
source

Are there sometimes arguments for the script? If not, why not:

 /^run(?:\s.*\s|\s)(\S+)\s*$/ 

I think it is not working at the bit line continuation.

 /^run(?:\s+cred=(?:[^'\s]*|'[^']*')\s+|\s+)([^\\\s]+)\s*$/ 

Testing program:

 #!/usr/bin/perl $foo="# normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \\ script.bi "; foreach my $line (split(/\n/,$foo)) { print "Looking >$line<\n"; print "Match >$1<\n" if ($line =~ /^run(?:\s+cred=(?:[^'\s]*|'[^']*')\s+|\s+)([^\\\s]+)\s*$/); } in a different way #!/usr/bin/perl $foo="# normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \\ script.bi "; foreach my $line (split(/\n/,$foo)) { print "Looking >$line<\n"; print "Match >$1<\n" if ($line =~ /^run(?:\s+cred=(?:[^'\s]*|'[^']*')\s+|\s+)([^\\\s]+)\s*$/); } lines using \ #!/usr/bin/perl $foo="# normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \\ script.bi "; foreach my $line (split(/\n/,$foo)) { print "Looking >$line<\n"; print "Match >$1<\n" if ($line =~ /^run(?:\s+cred=(?:[^'\s]*|'[^']*')\s+|\s+)([^\\\s]+)\s*$/); } \ n /, $ foo)) #!/usr/bin/perl $foo="# normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \\ script.bi "; foreach my $line (split(/\n/,$foo)) { print "Looking >$line<\n"; print "Match >$1<\n" if ($line =~ /^run(?:\s+cred=(?:[^'\s]*|'[^']*')\s+|\s+)([^\\\s]+)\s*$/); } n"; #!/usr/bin/perl $foo="# normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \\ script.bi "; foreach my $line (split(/\n/,$foo)) { print "Looking >$line<\n"; print "Match >$1<\n" if ($line =~ /^run(?:\s+cred=(?:[^'\s]*|'[^']*')\s+|\s+)([^\\\s]+)\s*$/); } run (: \ s + cred = (:?? [^ '\ s] * |' [^ '] *') \ s + | \ s +) ([^ \\\ s] #!/usr/bin/perl $foo="# normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \\ script.bi "; foreach my $line (split(/\n/,$foo)) { print "Looking >$line<\n"; print "Match >$1<\n" if ($line =~ /^run(?:\s+cred=(?:[^'\s]*|'[^']*')\s+|\s+)([^\\\s]+)\s*$/); } ; #!/usr/bin/perl $foo="# normal way run cred=username/password script.bi # single quoted username password, also separated in a different way run cred='username password' script.bi # username/password is optional run script.bi # script extension is optional run script # the call might be broken into multiple lines using \ # THIS ONE SHOULD NOT MATCH run cred=username/password \\ script.bi "; foreach my $line (split(/\n/,$foo)) { print "Looking >$line<\n"; print "Match >$1<\n" if ($line =~ /^run(?:\s+cred=(?:[^'\s]*|'[^']*')\s+|\s+)([^\\\s]+)\s*$/); } 

Output Example:

 Looking ># normal way< Looking >run cred=username/password script.bi< Match >script.bi< Looking >< Looking ># single quoted username password, also separated in a different way< Looking >run cred='username password' script.bi< Match >script.bi< Looking >< Looking ># username/password is optional< Looking >run script.bi< Match >script.bi< Looking >< Looking ># script extension is optional< Looking >run script< Match >script< Looking >< Looking ># the call might be broken into multiple lines using < Looking ># THIS ONE SHOULD NOT MATCH< Looking >run cred=username/password \< Looking >script.bi< script.bi < Looking ># normal way< Looking >run cred=username/password script.bi< Match >script.bi< Looking >< Looking ># single quoted username password, also separated in a different way< Looking >run cred='username password' script.bi< Match >script.bi< Looking >< Looking ># username/password is optional< Looking >run script.bi< Match >script.bi< Looking >< Looking ># script extension is optional< Looking >run script< Match >script< Looking >< Looking ># the call might be broken into multiple lines using < Looking ># THIS ONE SHOULD NOT MATCH< Looking >run cred=username/password \< Looking >script.bi< also separated in a different way < Looking ># normal way< Looking >run cred=username/password script.bi< Match >script.bi< Looking >< Looking ># single quoted username password, also separated in a different way< Looking >run cred='username password' script.bi< Match >script.bi< Looking >< Looking ># username/password is optional< Looking >run script.bi< Match >script.bi< Looking >< Looking ># script extension is optional< Looking >run script< Match >script< Looking >< Looking ># the call might be broken into multiple lines using < Looking ># THIS ONE SHOULD NOT MATCH< Looking >run cred=username/password \< Looking >script.bi< ' script.bi < Looking ># normal way< Looking >run cred=username/password script.bi< Match >script.bi< Looking >< Looking ># single quoted username password, also separated in a different way< Looking >run cred='username password' script.bi< Match >script.bi< Looking >< Looking ># username/password is optional< Looking >run script.bi< Match >script.bi< Looking >< Looking ># script extension is optional< Looking >run script< Match >script< Looking >< Looking ># the call might be broken into multiple lines using < Looking ># THIS ONE SHOULD NOT MATCH< Looking >run cred=username/password \< Looking >script.bi< < Looking ># normal way< Looking >run cred=username/password script.bi< Match >script.bi< Looking >< Looking ># single quoted username password, also separated in a different way< Looking >run cred='username password' script.bi< Match >script.bi< Looking >< Looking ># username/password is optional< Looking >run script.bi< Match >script.bi< Looking >< Looking ># script extension is optional< Looking >run script< Match >script< Looking >< Looking ># the call might be broken into multiple lines using < Looking ># THIS ONE SHOULD NOT MATCH< Looking >run cred=username/password \< Looking >script.bi< into multiple lines using < Looking ># normal way< Looking >run cred=username/password script.bi< Match >script.bi< Looking >< Looking ># single quoted username password, also separated in a different way< Looking >run cred='username password' script.bi< Match >script.bi< Looking >< Looking ># username/password is optional< Looking >run script.bi< Match >script.bi< Looking >< Looking ># script extension is optional< Looking >run script< Match >script< Looking >< Looking ># the call might be broken into multiple lines using < Looking ># THIS ONE SHOULD NOT MATCH< Looking >run cred=username/password \< Looking >script.bi< < Looking ># normal way< Looking >run cred=username/password script.bi< Match >script.bi< Looking >< Looking ># single quoted username password, also separated in a different way< Looking >run cred='username password' script.bi< Match >script.bi< Looking >< Looking ># username/password is optional< Looking >run script.bi< Match >script.bi< Looking >< Looking ># script extension is optional< Looking >run script< Match >script< Looking >< Looking ># the call might be broken into multiple lines using < Looking ># THIS ONE SHOULD NOT MATCH< Looking >run cred=username/password \< Looking >script.bi< \ < Looking ># normal way< Looking >run cred=username/password script.bi< Match >script.bi< Looking >< Looking ># single quoted username password, also separated in a different way< Looking >run cred='username password' script.bi< Match >script.bi< Looking >< Looking ># username/password is optional< Looking >run script.bi< Match >script.bi< Looking >< Looking ># script extension is optional< Looking >run script< Match >script< Looking >< Looking ># the call might be broken into multiple lines using < Looking ># THIS ONE SHOULD NOT MATCH< Looking >run cred=username/password \< Looking >script.bi< 
0
source

All Articles