From: WH on
pk wrote:
> pk wrote:
>
>> perl -ne
>> [cut]
>> The Perl array is unnamed
>
> I guess that for true Perl correctness, all those object I called "unnamed
> arrays" are better called "lists". Sorry for the imprecision.
>

Thanks for your explanation.

If I understand it correctly, some lines are first combined into one
record and then split back into lines. The reason to go through this is
to process records with certain fields, such as "DEFINE CHANNEL". So
shouldn't it be

perl -ne'$_ .= <> and redo if s/\+$//; print grep /DEFINE
CHANNEL|SSLCAUTH\(REQUIRED\)|SSLCIPH/, /.*\n/g if /DEFINE CHANNEL/'

?
From: Ed Morton on
On 2/26/2010 12:01 PM, pk wrote:
> Ed Morton wrote:
>
>>> Sort of. The algorithm is different. The perl script above concatenates
>>> together all the lines that end with a '+' and then loops through that
>>> one string using grep() to pick out the correct "lines".
>>
>> OK, I get that concept, but I don't understand it knows when it finds a
>> "DEFINE CHANNEL" line in the concatenated string that it will later find a
>> "SSLCAUTH\(REQUIRED\)" string on a subsequent line so it's OK to print
>> that first line.
>
> I'm sure he'll be able to explain much better...anyway (slightly
> reformatted):
>
> -------------------
> perl -ne
>
> This (-n) enables an implicit loop over the input, ie the same that happens
> in awk automatically. By default, records end at \n, like in awk. "$_" is
> like awk's "$0", ie it contains the record (plus a ton of other things, but
> here that's what it does). One difference is that the trailing \n is NOT
> removed so it's part of "$_".
> -------------------
> $_ .=<> and redo if s/\+$//;
>
> (Note the "quasi natural language" syntax of this Perl code)
> This concatenates successive input lines as long as the resulting string
> ends in "+".<> is (VERY roughly) like awk's getline here. "." is the
> concatenation operator, s/// is like sed's substitution and by default it
> operates on "$_" (and the result is true if the replacement is performed),
> so the above code is similar (not completely equivalent) to this awk code:
>
> while(sub(/\+$/,"")) { getline a; $0=$0 "\n" a; }; $0=$0 "\n"
>
> Note that, even if trailing newline is preserved in Perl, /\+$/ matches what
> one expects.
> -------------------
>
> print grep /DEFINE CHANNEL|SSLCAUTH\(REQUIRED\)|SSLCIPH/, /.*\n/g'
>
> This is a very idiomatic construct. We should start from the end.
>
> /.*\n/g
>
> /pattern/ is Perl's match operator, and by default it matches against "$_".
> The /g modifier performs a global match, ie match as many times as possible.
> Believe it or not, due to Perl rules the result of the above "/.*\n/g" is an
> array containing all the "lines" in "$_". That would be like awk's
>
> n = split($0, lines, /\n/)
>
> except again each array element does end in "\n" in the Perl version.
>
> The Perl array is unnamed, and "grep" operates on that array.
> The syntax used for grep here is
>
> grep EXPRESSION,LIST
>
> where the unnamed array is the LIST part in the above synopsis.
> What grep does is to apply the EXPRESSION to each element of LIST, and
> return the elements for which EXPRESSION is true.
>
> EXPRESSION here is
>
> /DEFINE CHANNEL|SSLCAUTH\(REQUIRED\)|SSLCIPH/
>
> so it is a match against the enclosed pattern. So, each line in the unnamed
> array is matched against that pattern, and if it matches grep returns it.
>
> In awk it would be something like:
>
> count=0
> for(i=1;i<=n;i++){
> if(lines[i] ~ /DEFINE CHANNEL|SSLCAUTH\(REQUIRED\)|SSLCIPH/) {
> count++
> matchinglines[count] = lines[i]
> }
> }
>
> with again the difference that in awk you have to explicitly name the
> arrays.
>
> The result of grep is again a (possibly smaller) unnamed array, which is fed
> to "print" to be printed. Since each element already has its original
> trailing newline, it will be printed in a separate line. To complete, in awk
> that would be
>
> for(i=1;i<=count;i++){
> print matchinglines[i]
> }
>
> So the complete awk code would be (untested!)
>
> awk '{
> while(sub(/\+$/,"")) { getline a; $0=$0 "\n" a; }; $0=$0 "\n"
> n = split($0, lines, /\n/)
> count=0
> for(i=1;i<=n;i++){
> if(lines[i] ~ /DEFINE CHANNEL|SSLCAUTH\(REQUIRED\)|SSLCIPH/) {
> count++
> matchinglines[count] = lines[i]
> }
> }
> for(i=1;i<=count;i++){
> print matchinglines[i]
> }
> }'
>

Thanks for the explanation, but if I understand you correctly then the script
wouldn't work since it'd print the "DEFINE CHANNEL" and "SSLCIPH" lines even if
there was no "SSLCAUTH(REQUIRED)", the main pattern the OP wanted to search for,
in the block. I don't have perl handy to test it with....

Ed.
From: Ed Morton on
On 2/26/2010 1:34 PM, WH wrote:
> pk wrote:
>> pk wrote:
>>
>>> perl -ne
>>> [cut] The Perl array is unnamed
>>
>> I guess that for true Perl correctness, all those object I called
>> "unnamed arrays" are better called "lists". Sorry for the imprecision.
>>
>
> Thanks for your explanation.
>
> If I understand it correctly, some lines are first combined into one
> record and then split back into lines. The reason to go through this is
> to process records with certain fields, such as "DEFINE CHANNEL". So
> shouldn't it be
>
> perl -ne'$_ .= <> and redo if s/\+$//; print grep /DEFINE
> CHANNEL|SSLCAUTH\(REQUIRED\)|SSLCIPH/, /.*\n/g if /DEFINE CHANNEL/'
>
> ?

Ah, there you go - the OP was looking for "SSLCAUTH(REQUIRED)" so I guess the
above should be:

perl -ne'$_ .= <> and redo if s/\+$//; print grep /DEFINE
CHANNEL|SSLCAUTH\(REQUIRED\)|SSLCIPH/, /.*\n/g if /SSLCAUTH\(REQUIRED\)/'

Kinda reminds me of writing Prolog (back in the day!) or using Reverse Polish
notation calculators.

I thought the other syntax John posted was perfectly clear though:

perl -F'\n' -00 -ane'
if ( /SSLCAUTH\(REQUIRED\)/ ) {
for ( @F ) {
if ( /DEFINE CHANNEL|SSLCAUTH|SSLCIPH/ ) { print "$_\n" }
}
}'

and seems to actually be a few less characters so not sure if there's any
benefit to the first syntax.

Cheers,

Ed.
From: pk on
Ed Morton wrote:

> Thanks for the explanation, but if I understand you correctly then the
> script wouldn't work since it'd print the "DEFINE CHANNEL" and "SSLCIPH"
> lines even if there was no "SSLCAUTH(REQUIRED)", the main pattern the OP
> wanted to search for, in the block. I don't have perl handy to test it
> with....

Yes, mine was just an attempt to translate the code as it was. Then, as
you've already found out, a small change is needed to do what the OP wanted.