Home > other >  Reading stdin in perl requires line feeds around input. How to avoid?
Reading stdin in perl requires line feeds around input. How to avoid?

Time:01-03

MSG_OUT="<B><I>Skipping<N> all libraries and fonts...<N>"

perl -ne '%ES=("B","[1m","I","[3m","N","[m","O","[9m","R","[7m","U","[4m"); while (<>) { s/(<([BINORSU])>)/\e$ES{$2}/g; print; }'

This perl one-liner swaps a token for an escape sequence.
It works as intended but only if the input is surrounded with line feeds.

i.e.

echo "\x0a${MSG_OUT}\x0a" | perl -ne '.... etc.

How do I avoid this issue when reading from stdin?

CodePudding user response:

-n wraps your code in while (<>) { ... }* (cf perldoc perlrun). Thus, your one-liner is equivalent to:

perl -e '
   while(<>) {
      %ES=("B","[1m","I","[3m","N","[m","O","[9m","R","[7m","U","[4m");
      while (<>) { s/(<([BINORSU])>)/\e$ES{$2}/g; print; }
   }
'

[Line breaks added for readability. They can be removed if you so desire.]

See the double while (<>) { ... }? That's your issue: the first while (the one added by -n) reads a line, then the second while (the one you wrote) reads a second line, does your s/// (on the second line), and prints this second line updated. Thus, you need a blank line before the actual line you want to process.

To fix the issue, either remove the inner while(<>), or remove the -n flag. For instance:

perl -e '
   %ES=("B","[1m","I","[3m","N","[m","O","[9m","R","[7m","U","[4m");
   while (<>) { s/(<([BINORSU])>)/\e$ES{$2}/g; print; }
' 

Or,

perl -ne '
   BEGIN { %ES=("B","[1m","I","[3m","N","[m","O","[9m","R","[7m","U","[4m") };
   s/(<([BINORSU])>)/\e$ES{$2}/g; print;
'

Note that instead of using -n and print, you can use -p, which is the same as -n with an extra print** at the end:

perl -pe '
    BEGIN { %ES=("B","[1m","I","[3m","N","[m","O","[9m","R","[7m","U","[4m") };
    s/(<([BINORSU])>)/\e$ES{$2}/g;
'

* For completness, note that -n adds the label LINE before the while loop (LINE: while(<>) { ... }), although that doesn't matter in your case.

** The print added by -p is actually in a continue block after the while, although, once again, this doesn't matter in your case.

  •  Tags:  
  • perl
  • Related