3

I am currently writing a awkscript which looks like this :

#!/usr/bin/awk -f
BEGIN {
    print "Starting extracting data"
}
{
    print $0
}
END {
    print "End of file"
}

My script works fine like that on my computer but it is not portable... I'd like to do something like

#!/usr/bin/env awk -f
...

but the Debian shell does not accept several parameters in a single shebang. I get "awk -f" no such file or directory. Is there any workaround I could use or is it completely impossible ?

12
  • Can you show the full command how you invoked the awk? Commented Aug 10, 2017 at 11:52
  • 1
    @Inian well, not according to this thread and the fact that it works well on my computer. Anyway, I think there is no portable solution still thank you for trying to help me :) ! Commented Aug 10, 2017 at 12:16
  • 1
    @Xatyrian: If you carefully read through the comments in the accepted answer passing arguments in she-bang line is not supported in Linux, you can still use #!/usr/bin/env awk and pass -f while calling the script. Commented Aug 10, 2017 at 12:19
  • 1
    @Xatyrian: Usual SO behavior, some people just look at a few comments and think my answer didn;t solve your problem and downvote away! Thanks Commented Aug 10, 2017 at 13:09
  • 3
    This is documented in the execve(2) man page Commented Aug 10, 2017 at 15:02

2 Answers 2

1

There is no easy way to do this cleanly; as mentioned in glenn jackman's comment, shebangs are implemented by execve(), which only accepts an interpreter and a single optional argument.

You'll need a workaround.

The comments to the question imply you don't want a wrapper script, but what if it's contained inside the final ~awk script?

#!/bin/sh
awk -f - "$@" << 'EOF'
#!/usr/bin/awk -f

BEGIN {
    print "Starting extracting data"
}
{
    print $0
}
END {
    print "End of file"
}

This uses portable POSIX shell in its shebang and then immediately invokes awk with awk code from a heredoc on standard input (-f -), passing the further arguments and options ("$@") to awk as files. The heredoc is quoted (<< 'EOF') so things like $0 aren't interpreted by the POSIX shell. Since a line consisting solely of EOF is not present, the heredoc ends with the file.

(The second shebang is not read by anything. It's purely cosmetic for people who read the code. If you name this file with the .awk suffix, editors like vim will default their syntax highlighting to awk despite the contents of the first shebang.)

That code won't work for piping content into the file because the script is itself piped into awk. If you want to support piping, it needs to be a little uglier, using bash's input process substitution (<(…)):

#!/bin/bash
exec awk -f <(awk 'NR > 2' "$0") "$@"
#!/usr/bin/awk -f

BEGIN {
    print "Starting extracting data"
}
{
    print $0
}
END {
    print "End of file"
}

This tells bash to execute awk on a named pipe created from that second awk command, which reads the full script (bash interprets $0 as the name of the file it is running) and prints lines 3 and higher. Again, the second shebang is purely cosmetic and is therefore just a comment.

Sign up to request clarification or add additional context in comments.

Comments

0

There's really no reason to invoke awk in the shebang. Just invoke it via sh:

#!/bin/sh
exec awk '
BEGIN {
    print "Starting extracting data"
}
{
    print $0
}
END {
    print "End of file"
}
' "$@"

1 Comment

This might (? I'm not sure) run into size limits due to being effectively a single command line. That's why my answer used heredoc or process substitution. There's a pretty good chance that the awk script is small enough that it doesn't matter, in which case this is probably the simplest solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.