5

Looking at this question, I've noticed that awk can't read user input if the file is being piped into standard input, but it does behave as expected if reading input from a file given as a command line parameter.

For instance, if you have the following BEGIN block in your awk script:

BEGIN {
    printf "Enter input: "
    getline var < "-"
}

If you run it like awk -f ./script.awk file.txt, it will ask prompt for user input, and then will proceed processing file.txt. However, if you run like cat file.txt | awk -f ./script.awk, I suppose awk will interpret what it is getting from the pipe as the user's input (so getline will fill var with the first line of file.txt).

Is there a way to make awk behave like it is reading from a file, but being used in a pipe?

I can use a temporary file, sure, but this is far from elegant.

3

Instead of a temporary file, you could use of your shell's support for process substitution (this assumes bash, zsh or some implementations of ksh (the feature was introduced by ksh88)):

awk -f ./script.awk <(cat file.txt)

This will provide awk a file name in place of the <(...) construct which, when read, will contain the output of the enclosed command.

  • I'm using zsh, and this solution also works with it without any modification. – Kira Dec 14 '15 at 21:07
5

Process substitution would work in simple cases but here is a generic way allowing to dialog with the console user while still processing piped data:

BEGIN {
    printf "Enter input: " > "/dev/tty"
    getline var < "/dev/tty"
    print var
}
  • 1
    Nice. I generally avoid touching /dev/tty (because what if the user wants to use redirects?), but, in this case, this looks completely adequate. – dhag Dec 14 '15 at 22:08
2

If that fits your workflow, you can make awk itself open the pipe. You can't do that for an ARGV element, so you won't get awk's automatic iteration on the lines read from the pipe. Instead awk will read from the files passed as command line arguments, or from standard input if there were no file arguments.

{
    printf "Enter input: "
    getline var
    while (("cat file.txt" | getline) > 0) { … }
}

This structure doesn't fit your toy example well, but I'm mentioning it because it might fit your real problem.

1

if your system supports the /dev/fd/[num] links or your awk is GNU awk, this should probably work where awk -f ./script.awk file.txt does:

{ some_cmd | 3<&0 <&4 4<&- awk -f ./script.awk /dev/fd/3; } 4<&0
  • @StéphaneChazelas - oh, duh. thanks again, sc. – mikeserv Dec 17 '15 at 11:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.