views:

578

answers:

4

I have a file with fields separated by pipe characters and I want to print only the second field. This attempt fails:

$ cat file | awk -F| '{print $2}'
awk: syntax error near line 1
awk: bailing out near line 1
bash: {print $2}: command not found

Is there a way to do this?

A: 

The pipe character needs to be escaped so that the shell doesn't interpret it. A simple solution:

$ awk -F\| '{print $2}' file

Another choice would be to quote the character:

$ awk -F'|' '{print $2}' file
Jon Ericson
+8  A: 

Or just use one command:

cut -d '|' -f FIELDNUMBER
Zsolt Botykai
Note that the crux of the problem is the pipe character, not the command used. But this is a fine solution.
Jon Ericson
I thought about it, but I'd rather have an answer that explains the problem. That's kinda the point of my comment, in fact. ;-)
Jon Ericson
A: 

And 'file' contains no pipe symbols, so it prints nothing. You should either use 'cat file' or simply list the file after the awk program.

Jonathan Leffler
Urg. Sorry about that. The original code grep'ed a file then piped the output to awk. I sanitized the command, but didn't test it. :(
Jon Ericson
+4  A: 

The key point here is that the pipe character (|) must be escaped to the shell. Use "\|" or "'|'" to protect it from shell interpertation and allow it to be passed to awk on the command line.


Reading the comments I see that the original poster presents a simplified version of the original problem which involved filtering file before selecting and printing the fields. A pass through grep was used and the result piped into awk for field selection. That accounts for the wholly unnecessary cat file that appears in the question (it replaces the grep <pattern> file).

Fine, that will work. However, awk is largely a pattern matching tool on its own, and can be trusted to find and work on the matching lines without needing to invoke grep. Use something like:

awk -F\| '/<pattern>/{print $2;}{next;}' file

The /<pattern>/ bit tells awk to perform the action that follows on lines that match <pattern>.

The lost-looking {next;} is a default action skipping to the next line in the input. It does not seem to be necessary, but I have this habit from long ago...

dmckee