A much more robust way would be to use the getline()
function of GNU awk
to use a variable from a pipe. In form cmd | getline
result, cmd
is run, then its output is piped to getline
. It returns 1
if got output, 0
if EOF, -1
on failure.
First construct the command to run in a variable in the BEGIN
clause if the command is not dependant on the contents of the file, e.g. a simple date
or an ls
.
A simple example of the above would be
awk 'BEGIN {
cmd = "ls -lrth"
while ( ( cmd | getline result ) > 0 ) {
print result
}
close(cmd);
}'
When the command to run is part of the columnar content of a file, you generate the cmd
string in the main {..}
as below. E.g. consider a file whose $2
contains the name of the file and you want it to be replaced with the md5sum
hash content of the file. You can do
awk '{ cmd = "md5sum "$2
while ( ( cmd | getline md5result ) > 0 ) {
$2 = md5result
}
close(cmd);
}1'
Another frequent usage involving external commands in awk
is during date
processing when your awk
does not support time functions out of the box with mktime()
, strftime()
functions.
Consider a case when you have Unix EPOCH timestamp stored in a column and you want to convert that to a human readable date format. Assuming GNU date
is available
awk '{ cmd = "date -d @" $1 " +\"%d-%m-%Y %H:%M:%S\""
while ( ( cmd | getline fmtDate) > 0 ) {
$1 = fmtDate
}
close(cmd);
}1'
for an input string as
1572608319 foo bar zoo
the above command produces an output as
01-11-2019 07:38:39 foo bar zoo
The command can be tailored to modify the date
fields on any of the columns in a given line. Note that -d
is a GNU specific extension, the *BSD variants support -f
( though not exactly similar to -d
).
More information about getline
can be referred to from this AllAboutGetline article at awk.freeshell.org page.
I use the power of awk to delete some of my stopped docker containers. Observe carefully how i construct the cmd
string first before passing it to system
.
docker ps -a | awk '$3 ~ "/bin/clish" { cmd="docker rm "$1;system(cmd)}'
Here, I use the 3rd column having the pattern "/bin/clish" and then I extract the container ID in the first column to construct my cmd
string and passed that to system
.
I was able to have this done via below method
cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk '{system(`date`); print $1}'
awk has a function called system it enables you to execute any linux bash command within the output of awk.
Something as simple as this will work
awk 'BEGIN{system("echo hello")}'
and
awk 'BEGIN { system("date"); close("date")}'
It really depends :) One of the handy linux core utils (info coreutils
) is xargs
. If you are using awk
you probably have a more involved use-case in mind - your question is not very detailled.
printf "1 2\n3 4" | awk '{ print $2 }' | xargs touch
Will execute touch 2 4
. Here touch
could be replaced by your program. More info at info xargs
and man xargs
(really, read these).
I believe you would like to replace touch
with your program.
Breakdown of beforementioned script:
printf "1 2\n3 4"
# Output:
1 2
3 4
# The pipe (|) makes the output of the left command the input of
# the right command (simplified)
printf "1 2\n3 4" | awk '{ print $2 }'
# Output (of the awk command):
2
4
# xargs will execute a command with arguments. The arguments
# are made up taking the input to xargs (in this case the output
# of the awk command, which is "2 4".
printf "1 2\n3 4" | awk '{ print $2 }' | xargs touch
# No output, but executes: `touch 2 4` which will create (or update
# timestamp if the files already exist) files with the name "2" and "4"
Update In the original answer, I used echo
instead of printf
. However, printf
is the better and more portable alternative as was pointed out by a comment (where great links with discussions can be found).
There are several ways.
awk has a system()
function that will run a shell command:
system("cmd")
You can print to a pipe:
print "blah" | "cmd"
You can have awk construct commands, and pipe all the output to the shell:
awk 'some script' | sh
#!/usr/bin/awk -f
BEGIN {
command = "ls -lh"
command |getline
}
Runs "ls -lh" in an awk script
Source: Stackoverflow.com