1

I wrote a script that prints the current and subsequent line after a match, however, I've noticed a difference between two ways of using the readline return value.

This works as intended:

$ echo $'H1\na\nb\nH2\na\nb' | perl -ne 'if (/^H/) { print; print $line = readline }'
H1
a
H2
a

However, this doesn't:

$ echo $'H1\na\nb\nH2\na\nb' | perl -ne 'if (/^H/) { print; print readline }'
H1
a
b
H2
a
b

instead, it prints all the lines. Why?

Marcus
  • 5,104
  • 2
  • 28
  • 24

2 Answers2

4

print takes a list argument, and puts readline() in list context. Hence it exhausts all of the lines. When you use scalar assignment with $line = it is in scalar context, and will only read 1 line.

Read more about context here.

TLP
  • 66,756
  • 10
  • 92
  • 149
3

The context in which readline is called is different.

In $line = readline, = is the scalar assignment operator, and it evaluates its operands in scalar context. In scalar context, readline returns a single line.

print, on the other hand, accepts an expression which it evaluates in list context. In list context, readline returns all remaining lines.

Equivalent:[1]

  • $line = readline; print $line;
  • print $line = readline;
  • print scalar(readline);

  1. If $line isn't magical. Except for the effect on $line.
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • hi ikegami.. need your help in reviewing my answer https://stackoverflow.com/questions/68868817/how-to-convert-mac-addr-to-int-using-awk/68876184#68876184 could you pls suggest improvements – stack0114106 Aug 21 '21 at 19:41
  • ok thanks.. just want to know if 2 perl could be combined – stack0114106 Aug 21 '21 at 19:47