awk
behaves differently when analyzing the output of tail -f
versus inotifywait -m
. Specifically I am searching for a matching string and want to exit awk
once it appears. This works fine for tail -f
, however in the case of inofitywait
, awk
needs to be triggered twice. Why so?
Reproducible Examples:
Say we are searching for a specific string ("OPEN") in either case and use a special exit code as marker. Let's also trigger it after a short wait (inotofywait
needs a moment) and return the exit code. Pseudo-code:
command | awk-analysis || get-non-0-exit-code & trigger
All good for tail -f
The following a) prints the line, b) returns the exit code and c) terminates. As expected.
tail -f test.file | awk '/OPEN/ { print $0 ; exit 100 }' || echo $? &
{ sleep 2 ; echo OPEN > test.file ; }
However with inotifywait -m
the result is quite different.
inotifywait -m -e OPEN | awk '/OPEN/ { print $0 ; exit 100 }' || echo $? &
{ sleep 2 ; touch test.file ; }
This will print the line (so inotifywait
is triggered and awk
sees it) but NOT show the exit code nor terminate. Only another trigger like touch test.file
is able to stop awk
Maybe control characters?
I thought maybe I am missing a singal awk
uses here, so I tried to analyze with cat -A
(results file in parent folder, so otherwise a second "OPEN" is triggered in inotifywait
):
tail -f test.file | tee >(cat -A >../stream) | ....
cat ../stream
OPEN$
and
inotifywait -m -e OPEN | tee >(cat -A >../stream) | ....
cat ../stream
./ OPEN test.file$
So no unseen control characters missed.
What is the reason for this behaviour?
Am I missing a newline? How comes awk
does print the line, but not run the exit
command in the same code block? Why does it work with tail
, though?
Verisons
awk --verison
: GNU Awk 4.2.1, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.1.2)
inotifywait -h
: inotifywait 3.14
tail --verison
: tail (GNU coreutils) 8.30
EDIT due to Kusalananda's comments:
tail -f
test.file
exists and has the following content:
*case 1
OPEN
spam
*case 2
spam
OPEN
*case 3 (file is empty)
Trigger as above is NOT run, i.e.
tail -f test.file | awk '/OPEN/ {print $0 ; exit 100 }' || echo $?
Case 1 & 2 : immediately returns the matching line, exit code and is terminated.
Case 3: waits, open other terminal and echo OPEN >> 3
or echo OPEN > 3
returns string, exit code and terminates.
tail -f
example, is the line containingOPEN
the last line in the file? If not, try again withOPEN
only on the last line of that file. Also try with appendingOPEN
to the file instead of truncating it. In either case, the left hand side would not terminate immediately just becauseawk
exits, it would need to try (and fail) to write across the pipe.tail
implementation (which would work withinotifywait
too).