5
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?

Dada
6,7657 gold badges28 silver badges48 bronze badges
asked Jan 1, 2022 at 16:58
2
  • 1
    Tip: Get rid of needless capture: s/(<([BINORSU])>)/\e$ES{2ドル}/g -> s/<([BINORSU])>/\e$ES{1ドル}/g Commented Jan 1, 2022 at 19:42
  • Tip: use => in hashes to make the code more readable: %ES=("B"=>"[1m","I"=>"[3m","N"=>"[m","O"=>"[9m","R"=>"[7m","U"=>"[4m"); looks nicer than %ES=("B","[1m","I","[3m","N","[m","O","[9m","R","[7m","U","[4m"); Commented Jan 2, 2022 at 9:17

1 Answer 1

4

-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.

ikegami
391k17 gold badges291 silver badges555 bronze badges
answered Jan 1, 2022 at 17:23
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.