# Functions¶

## Built-in Functions¶

### Calling Built-in Functions¶

function(arg1,… argn)

The function’s parameters are evaluated completely before the function’s call is performed.

### Numeric Functions¶

 atan2(y, x) return the arctangent of y / x in radians cos(x) return the cosine of x , with x in radians exp(x) return the exponential of x ( e ^ x ) int(x) return the nearest integer to x log(x) return the natural logarithm of x rand() return a random number sin(x) return the sine of x , with x in radians. sqrt(x) return the positive square root of x srand([x]) set the starting point for generating random numbers to the value x
```awk '# Function to roll a simulated die.
function roll(n) { return 1 + int(rand() * n) }
# Roll 3 six-sided dice and
# print total number of points.
{
printf("%d points\n", roll(6) + roll(6) + roll(6))
}'
```

### String-Manipulation Functions¶

 asort(source[,dest[,how]]) sorts the values of source asorti(source[,dest[,how]]) if dest is specified, then source is duplicated into dest
```awk 'BEGIN {
a["last"] = "de"
a["first"] = "sac"
a["middle"] = "cul"
for (i in a)
printf "%s\n", a[i]
asort(a)
for (i in a)
printf "%s\n", a[i]
}'
```
```sac
cul
de
cul
de
sac
```
 gensub(regexp,replacement,how[,target]) replace all matches of regexp with replacement gsub(regexp,replacement[,target]) replace all matches of regexp with replacement
```awk 'BEGIN {
a = "abc def"
b = gensub(/(.+) (.+)/, "\\2 \\1", "g", a)
print b
}'
```
```def abc
```
```echo 'a b c a d e' | awk '{
print gensub(/a/, "AA", 1)
print gensub(/a/, "AA", 2)
print gensub(/a/, "AA", "g")
}'
```
```AA b c a d e
a b c AA d e
AA b c AA d e
```
 index(in,find) return the position of find in string in length([string]) return the number of characters in string
```awk 'BEGIN {
str = "guillaume"
print index(str, "aume")
print index(str, "gui")
}'

awk 'length(\$1) > 8 { print }' mail-list
```
 match(string,regexp[,array]) search string matched by regexp and return the character position
```echo 'FIND ru+n
My program runs
but not very quickly
FIND guisam
JF+KM
This line is property of Reality Engineering Co.
guisam was here.' | awk '{ if (\$1 == "FIND")
regex = \$2
else {
where = match(\$0, regex)
if (where != 0)
print "Match of", regex, "found at", where, "in", \$0
}}'
```
```Match of ru+n found at 12 in My program runs
Match of guisam found at 1 in guisam was here.
```
```echo "guillaume blablaba samblahblah" | awk '
match(\$0, /(gui).*(sam).*/, arr) { print arr[1]arr[2] }'
```
```guisam
```
```echo "guillaume blablaba samsamsam blahblah" | awk '
match(\$0, /(gui).*(sam).*/, arr) {
print arr[1]arr[2]
print arr[1, "start"], arr[1, "length"]
print arr[2, "start"], arr[2, "length"]
}'
```
```guisam
1 3
20 3
```
 patsplit(string,array[,fieldpat[,seps]]) divide string into pieces defined by fieldpat or fieldsep and store the split(string,array[,fieldsep[,seps]]) pieces in array and the separator strings in the seps array
```awk 'BEGIN {
split("cul-de_sac", a, /-|_/, seps)
for (i in a)
printf "%s -> %s\n", "a["i"]", a[i]
for (j in seps)
printf "%s -> %s\n", "seps["j"]", seps[j]
}'
```
```a[1] -> cul
a[2] -> de
a[3] -> sac
seps[1] -> -
seps[2] -> _
```
 sprintf(format,expression1,…) return (without printing) the string that printf would have printed out
```awk 'BEGIN {
pival = sprintf("pi = %.2f (approx.)", 22/7)
print pival
}'
```
```pi = 3.14 (approx.)
```
 strtonum(str) examine str and return its numeric value
```echo 0x17 | awk '{ printf "%.2f\n", strtonum(\$1) }'
```
```23.00
```
 sub(regexp,replacement[,target]) replace all matches of regexp with replacement
```awk 'BEGIN {
str = "guillaume, guillaume, everywhere"
print sub(/llaume/, "sam", str)
print str
sub("guisam", "& was here", str)
print str
}'
```
```1
guisam, guillaume, everywhere
guisam was here, guillaume, everywhere
```
 substr(string,start[,length]) return a length long substring, starting at character number start
```awk 'BEGIN {
str = "abcdefghi"
print substr(str, 1, 3) "DE" substr(str, 6)
}'
```
```abcDEfghi
```
 tolower(string) each uppercase character in the string replaced with lowercase character toupper(string) each lowercase character in the string replaced with uppercase character

### Input/Output Functions¶

 close(filename[,how]) close the file filename for input or output fflush([filename]) flush any buffered output system(command) execute the operating system command command

#### Interactive Versus Noninteractive Buffering¶

```awk '{print \$1\$2}'
1 2
12
gui sam
guisam

awk '{print \$1\$2}' | cat
1 2
gui sam
12
guisam
```

### Time Functions¶

 mktime(datespec) turn datespec into a timestamp
```awk 'BEGIN { t = mktime("2020 02 27 13 31 31")
print t }'
```
```1582806691
```
 strftime([format[,timestamp[,utc-flag]]]) format the time timestamp based on the format string
Default format is PROCINFO[“strftime”]
`"%a %b %e %H:%M:%S %Z %Y"`
```awk 'BEGIN {
now = strftime()
old = strftime("%F %T %Z", "1582733718", 1)
print now
print old
}'
```
```Thu Feb 27 01:38:47 CET 2020
2020-02-26 16:15:18 GMT
```
 systime() current time as the number of seconds since the system epoch
```awk 'BEGIN {
now = systime()
print strftime(PROCINFO["strftime"], now)
print strftime(PROCINFO["strftime"], now, 1)
}'
```
```Thu Feb 27 01:48:27 CET 2020
Thu Feb 27 00:48:27 GMT 2020
```

### Getting Type Information¶

 isarray(x) return a true value if x is an array

### String-Translation Functions¶

 bindtextdomain(directory[,domain]) set the directory for message translation files dcgettext(string[,domain[,category]]) return the translation of string in text domain domain for locale category category dcngettext(string1,string2,number[,domain[,category]]) return the plural form used for number of the translation of string1 and string2 in text domain domain for locale category category

## User-Defined Functions¶

### Function Definition Syntax¶

function name([parameter-list])
{
body-of-function
}

Place some extra space between the arguments and the local variables.

```echo -e "test\ntest" | awk '
function myprint(num)
{
printf "%s\n", num
}
{
myprint(\$0)
}'
```
```awk '
function delarray(a,    i)
{
for (i in a)
delete a[i]
}
BEGIN {
a[1] = "un"
a[2] = "deux"
for (j in a)
printf "%s -> %s\n", "a["j"]", a[j]
delarray(a)
print a[1] }'
```
```a[1] -> un
a[2] -> deux
```
```echo "Guisam" | awk '
function rev(str) {
if (str == "")
return ""
return (rev(substr(str, 2)) substr(str, 1, 1))
}
{ print rev(\$0) }'
```
```masiuG
```
```# awk version of C ctime(3) function
awk 'function ctime(ts,   format)
{
format = "%a %b %e %H:%M:%S %Z %Y"
if (ts == 0)
ts = systime()
# use current time as default
return strftime(format, ts)
}
BEGIN { print ctime()
}'
```
```Fri Feb 28 20:40:27 CET 2020
```

### Calling User-Defined Functions¶

#### Controlling variable scope¶

There is no way to make a variable local to a { … } block in awk, but you can make a variable local to a function.

• i is a global variable

```awk 'function bar()
{
for (i = 0; i < 3; i++)
print "bar'\''s i=" i
}
function foo(j)
{
i = j + 1
print "foo'\''s i=" i
bar()
print "foo'\''s i=" i
}
BEGIN {
i = 10
print "top'\''s i=" i
foo(0)
print "top'\''s i=" i
}'
```
```top's i=10
foo's i=1
bar's i=0
bar's i=1
bar's i=2
foo's i=3
top's i=3
```
• i is a local variable

```awk 'function bar(    i)
{
for (i = 0; i < 3; i++)
print "bar'\''s i=" i
}
function foo(j,    i)
{
i = j + 1
print "foo'\''s i=" i
bar()
print "foo'\''s i=" i
}
BEGIN {
i = 10
print "top'\''s i=" i
foo(0)
print "top'\''s i=" i
}'
```
```top's i=10
foo's i=1
bar's i=0
bar's i=1
bar's i=2
foo's i=1
top's i=10
```

#### Passing function arguments by value or by reference¶

If the argument is an array variable, then it is passed by reference. Otherwise, the argument is passed by value.

• by reference

```awk 'function myfunc(array)
{
print array[1]
array[1] = "zzz"
print array[1]
}
BEGIN {
foo[1] = "bar"
myfunc(foo)
print foo[1]
}'
```
```bar
zzz
zzz
```
• by value

```awk 'function myfunc(str)
{
print str
str = "zzz"
print str
}
BEGIN {
foo = "bar"
myfunc(foo)
print foo }'
```
```bar
zzz
bar
```

### The return Statement¶

return [expression]

```echo "1 5 23 8 16
44 3 5 2 8 26
256 291 1396 2962 100
-6 467 998 1101
99385 11 0 225" | awk '
function maxelt(vec,    i, ret)
{
for (i in vec) {
if (ret == "" || vec[i] > ret)
ret = vec[i]
}
return ret
} {
for(i = 1; i <= NF; i++)
nums[NR, i] = \$i
}
END {
print maxelt(nums)
}'
```
```99385
```

## Indirect Function Calls¶

You can specify the name of the function to call as a string variable, and then call the function.

the_func = “name”
result = @the_func()
• file `class_data1`

```Biology_101 sum average data: 87.0 92.4 78.5 94.9
Chemistry_305 sum average data: 75.2 98.3 94.7 88.2
English_401 sum average data: 100.0 95.6 87.1 93.4
```
• file `class_data2`

```Biology_101 sum average sort rsort data: 87.0 92.4 78.5 94.9
Chemistry_305 sum average sort rsort data: 75.2 98.3 94.7 88.2
English_401 sum average sort rsort data: 100.0 95.6 87.1 93.4
```
• file `indirect.awk`

```# indirectcall.awk --- Demonstrate indirect function calls
# average --- return the average of the values in fields \$first - \$last
function average(first, last,    sum, i)
{
sum = 0;
for (i = first; i <= last; i++)
sum += \$i
return sum / (last - first + 1)
}
# sum --- return the sum of the values in fields \$first - \$last
function sum(first, last,    ret, i)
{
ret = 0;
for (i = first; i <= last; i++)
ret += \$i
return ret
}
# For each record, print the class name and the requested statistics
{
class_name = \$1
gsub(/_/, " ", class_name) # Replace _ with spaces
# find start
for (i = 1; i <= NF; i++) {
if (\$i == "data:") {
start = i + 1
break
}
}
printf("%s:\n", class_name)
for (i = 2; \$i != "data:"; i++) {
the_function = \$i
printf("\t%s: <%s>\n", \$i, @the_function(start, NF) "")
}
print ""
}
```
• file `quicksort.awk`

```# quicksort.awk --- Quicksort algorithm, with user-supplied
# comparison function
# quicksort --- C.A.R. Hoare's quicksort algorithm. See Wikipedia
# or almost any algorithms or computer science text.
function quicksort(data, left, right, less_than,    i, last)
{
if (left >= right) # do nothing if array contains fewer
return # than two elements

quicksort_swap(data, left, int((left + right) / 2))
last = left
for (i = left + 1; i <= right; i++)
if (@less_than(data[i], data[left]))
quicksort_swap(data, ++last, i)
quicksort_swap(data, left, last)
quicksort(data, left, last - 1, less_than)
quicksort(data, last + 1, right, less_than)
}

# quicksort_swap --- helper function for quicksort, should really be inline
function quicksort_swap(data, i, j,    temp)
{
temp = data[i]
data[i] = data[j]
data[j] = temp
}

# num_lt --- do a numeric less than comparison
function num_lt(left, right)
{
return ((left + 0) < (right + 0))
}

# num_ge --- do a numeric greater than or equal to comparison
function num_ge(left, right)
{
return ((left + 0) >= (right + 0))
}

# do_sort --- sort the data according to `compare'
# and return it as a string
function do_sort(first, last, compare,    data, i, retval)
{
delete data
for (i = 1; first <= last; first++) {
data[i] = \$first
i++
}
quicksort(data, 1, i-1, compare)
retval = data[1]
for (i = 2; i in data; i++)
retval = retval " " data[i]
return retval
}

# sort --- sort the data in ascending order and return it as a string
function sort(first, last)
{
return do_sort(first, last, "num_lt")
}

# rsort --- sort the data in descending order and return it as a string
function rsort(first, last)
{
return do_sort(first, last, "num_ge")
}
```
```awk -f indirectcall.awk class_data1
Biology 101:
sum: <352.8>
average: <88.2>

Chemistry 305:
sum: <356.4>
average: <89.1>

English 401:
sum: <376.1>
average: <94.025>
```
```awk -f indirectcall.awk -f quicksort.awk class_data2
Biology 101:
sum: <352.8>
average: <88.2>
sort: <78.5 87.0 92.4 94.9>
rsort: <94.9 92.4 87.0 78.5>

Chemistry 305:
sum: <356.4>
average: <89.1>
sort: <75.2 88.2 94.7 98.3>
rsort: <98.3 94.7 88.2 75.2>

English 401:
sum: <376.1>
average: <94.025>
sort: <87.1 93.4 95.6 100.0>
rsort: <100.0 95.6 93.4 87.1>
```