1

I am trying to use awk to print the unique lines returned by a command. For simplicity, assume the command is ls -alh.

If I run the following command in my Z shell, awk shows all lines printed by ls -alh

ls -alh | awk '!seen[$0]++'

However, if I run the same command with $SHELL -c while escaping the ! with backslash, I only see the first line of the output printed.

$SHELL -c "ls -alh | awk '\!seen[$0]++'"

How can I ensure the latter command prints the exact same outputs as the former?

EDIT 1:

I initially thought the ! could be the issue. But changing the expression '!seen[$0]++' to 'seen[$0]++==0' has the same problem.

EDIT 2:

It looks like I should have escaped $ too. Since I do not know the reason behind it, I will not post an answer.

Matt
  • 796
  • 12
  • 25
  • 1
    what is the output from `echo "${SHELL}"` ? – hek2mgl Feb 10 '23 at 09:37
  • This is crazy anyway. `$SHELL` could be e.g. `/bin/csh` or `/bin/fish` whose syntax is completely different from Bourne shell. Simply run `sh` if that's what you mean. – tripleee Feb 10 '23 at 09:52
  • My `$SHELL` is zsh. I am just curious why this command has to be run differently when invoked with `$SHELL` and without, even if both are zsh. – Matt Feb 10 '23 at 20:43

1 Answers1

1

In the second form, $0 is being treated as a shell variable in the double-quoted string. The substitution creates an interestingly mangled awk command:

> print $SHELL -c "ls -alh | awk '\!seen[$0]++'"
/bin/zsh -c ls -alh | awk '!seen[-zsh]++'

The variable is not substituted in the first form since it is inside single quotes.

This answer discusses how single- and double-quoted strings are treated in bash and zsh: Difference between single and double quotes in Bash


Escaping the $ so that $0 is passed to awk should work, but note that quoting in commands that are parsed multiple times can get really tricky.

> print $SHELL -c "ls -alh | awk '\!seen[\$0]++'"
/bin/zsh -c ls -alh | awk '!seen[$0]++'
Gairfowl
  • 2,226
  • 6
  • 9