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.