Converting from decimal to hexadecimal is something that awk
can very well do itself. And you could define an awk
function to do it:
function d2h(d) {
return sprintf("%x", d)
}
Now to answer the question in the general case, for awk
to run bash
functions, you'd need awk
to execute a bash
shell, that bash
to interpret the definition of that function, and call that function, with the value extracted by awk
passed as arguments.
Not trivial.
bash
supports exporting functions via the environment, so it's available in subsequent invocations of bash
, so that's one way to pass the definition of the function to the bash
invoked by awk
:
export -f d2h
The only ways for awk
to execute a command (bash
here) are with its system("cmd")
, or print... | "cmd"
or "cmd" | getline
. In all cases, awk
runs a shell to interpret that cmd
, but it will be sh
, not bash
. So you need to construct a command line for sh
that is a bash
invocation that interprets a bash
command line to invoke the function, so you need to be careful with quoting:
export -f d2h
<file awk -v q="'" '
function shquote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
{print $1; system("exec bash -c '\''d2h \"$1\"'\'' bash " shquote($2))}'
If you want to get the output of the function back into awk
, you'd need to transfer it back via a pipe. For that, you'd use cmd | getline
instead of system(cmd)
(which leaves cmd
's stdout untouched).
cmd | getline line
stores one line (strictly speaking one record, records being lines by default), so to get the whole output in the cases where it's made of several lines, you'd need a loop such as:
awk '...
cmd = "exec bash -c '\''d2h \"$1\"'\'' bash " shquote($2)
output = ""
while ((cmd | getline line) > 0) {
output = output line RS
}
sub(RS "$", "", output) # remove the last newline
...'
That does mean running one sh
and one bash
for each each invocation of the function, so is going to be quite inefficient. That would end up being even significantly more inefficient than having bash
do the reading and splitting with a while read loop
:
(unset -v IFS; while read -r a b rest; do
printf '%s\n' "$a"
d2h "$b"
done < file)
Also note that since shellshock, bash
now export functions in environment variables that are named like BASH_FUNC_d2h%%
. Some sh
implementations including mksh
and newer versions of dash
remove those environment variables from the environment:
$ env 'foo%%=bar' dash -c 'printenv foo%%'
$ env 'foo%%=bar' mksh -c 'printenv foo%%'
$ env 'foo%%=bar' zsh -c 'printenv foo%%'
bar
$ env 'foo%%=bar' bash -c 'printenv foo%%'
bar
So instead of relying on the flimsy function export feature, you could pass the function definition some other way. It could be via an environment variable with a usual name:
BASH_FUNCTIONS=$(typeset -f d2h) awk '
...
cmd = "exec bash -c '\''eval \"$BASH_FUNCTIONS\";" \
"d2h \"$1\"'\'' bash " shquote($2)
...'