I ran into this problem while trying to print single quotes in a Perl one-liner. I eventually figured out you have to escape them with '\''
. Here's some code to illustrate my question.
Let's start with printing a text file.
perl -ne 'chomp; print "$_\n"' shortlist.txt
red
orange
yellow
green
blue
Now let's print the name of the file instead for each line.
perl -ne 'chomp; print "$ARGV\n"' shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
Then we can add single quotes around each line.
perl -ne 'chomp; print "'$_'\n"' shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
Wait that didn't work. Let's try again.
perl -ne 'chomp; print "'\''$_'\''\n"' shortlist.txt
'red'
'orange'
'yellow'
'green'
'blue'
So I got it working now. But I'm still confused on why '$_' evaluates to the program name. Maybe this is something easy but can someone explain or link to some documentation?
edit: I'm running Perl 5.8.8 on Red Hat 5
I try to avoid quotes in one liners for just this reason. I use generalized quoting when I can:
Although I can avoid even that with the
-l
switch to get the newline for free:If I don't understand a one-liner, I use
-MO=Deparse
to see what Perl thinks it is. The first two are what you expect:You see something funny in the one where you saw the problem. The variable has disappeared before
perl
ever saw it and there's a constant string in its place:Your fix is curious too because Deparse puts the variable name in braces to separate it from the old package specifier
'
:To your shell,
'chomp; print "'$_'\n"'
results in a string that's the concatenation ofchomp; print "
(the first sequence inside single quotes),$_
, and\n"
(the second sequence inside single quotes).In
bash
,$_
"... expands to the last argument to the previous command, after expansion. ...". Since this happens to beshortlist.txt
, the following is passed toperl
:For example,
You use single quotes in one-liners to protect your Perl code from being evaluated by the shell. In this command:
you close the single quotes before
$_
, so the shell expands$_
to the last argument to the previous command. In your case, this happened to be the name of your input file, but the output would be different if you ran a different command first: