Why does this awk script that runs on CentOS not run on Ubuntu?
(for reference, the code is likely also here: https://github.com/garyexplains/examples which is probably a better source than a video.)
Would there be any reason why this simple script on CentOS wouldn't run on Ubuntu?
[nsaunders@rolly awk]$
[nsaunders@rolly awk]$ awk -f loop.awk numbers.txt
1 2 3
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
[nsaunders@rolly awk]$
[nsaunders@rolly awk]$ cat loop.awk
func printlist(n) {
for(i=1;i<=n;i++) {
printf("%d ",i)
}
printf("\n")
}
{printlist($1)}
[nsaunders@rolly awk]$
[nsaunders@rolly awk]$ cat numbers.txt
3
7
12
15
16
31
[nsaunders@rolly awk]$
I'm getting:
awk: loop.awk: line 11: function printlist never defined
awk: loop.awk: line 11: function printlist never defined
awk version on Ubuntu:
mawk 1.3.4 20200120
Copyright 2008-2019,2020, Thomas E. Dickey
Copyright 1991-1996,2014, Michael D. Brennan
random-funcs: srandom/random
regex-funcs: internal
compiled limits:
sprintf buffer 8192
maximum-integer 2147483647
And on the CentOS machine:
[nsaunders@rolly ~]$
[nsaunders@rolly ~]$ awk -W version
GNU Awk 4.2.1, API: 2.0 (GNU MPFR 3.1.6-p2, GNU MP 6.1.2)
Copyright (C) 1989, 1991-2018 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
[nsaunders@rolly ~]$
isn't awk
pretty much awk
regardless of what machine you're on?
As noted in the The GNU Awk User’s Guide
In many awk implementations, including gawk, the keyword
function
may be abbreviatedfunc
. (c.e.) However, POSIX only specifies the use of the keywordfunction
.
So the error is possibly because the implementation of awk
on your Ubuntu system is mawk
, or that something (such as a POSIXLY_CORRECT
environment variable) is affecting how gawk
behaves on your system.
Ubuntu used to ship with mawk
as the default awk
- but as far as I know, all currently supported versions use gawk
by default. If you installed mawk
via the packaqge management system, you should be able to use the update-alternatives
mechanism to query/set the default ex.
update-alternatives --query awk
sudo update-alternatives --config awk
isn't awk pretty much awk regardless of what machine you're on?
No, and you may even have multiple implementations on the same system. gawk
(GNU Awk) has a number of features not present in mawk
. The one you've run into isn't the only one. The gawk
documentation contains a list of common features that differ across major AWK implementations.
As steeldriver says, using func
as an abbreviation for function
is supported by some but not all AWK implementations. To solve this particular problem, the best thing to do is just change func
to function
. With that single change, your script works with mawk
as well as gawk
.
If for some reason you can't or don't wish to do that, or if you need other nonstandard functionality that gawk
provides but mawk
doesn't, you can use gawk
, which is provided by the gawk
package.
gawk -f loop.awk numbers.txt
As shown in steeldriver's answer, you can use update-alternatives
to make awk
resolve to gawk
rather than mawk
(or that may happen automatically when you install gawk
).
However, you're using awk -f
, so if you're willing to add a shebang line to the top of your AWK script and mark the script executable (chmod +x loop.awk
), then you can have it specify which interpreter ought to be used:
#!/usr/bin/awk -f
func printlist(n) {
for(i=1;i<=n;i++) {
printf("%d ",i)
}
printf("\n")
}
{printlist($1)}
You would then run the script with the command:
./loop.awk numbers.txt
Then other scripts remain unaffected.
For this tiny script with a single occurrence of the func
keyword that can be written as function
, adding a shebang probably isn't your best choice, unless you were going to do that anyway. For more complex situations where you need gawk
features not present in mawk
, though, I suggest considering it. Adding a shebang also has the benefit of clarifying what implementation of AWK you wish to be used, and a script for which this doesn't matter and that is written to be portable can have a #!/usr/bin/awk -f
shebang.
(Of course, scripts with such shebangs aren't totally portable in the broader sense, since they assume awk
is in /usr/bin
.)