0

I want to ping a remote system, and have the date show up in my output, and then feed it along the pipeline to another program. I used cat in my examples below only to be a simple example.

I can use the -D option of the ping command to include the unix timestamp, and I can use a quick perl command to convert that timestamp into a readable time. But if I use perl to give me a easy to read time, it is somehow breaking the pipe, and the command I am sending the results to doesn't get anything. When I use set -x and run the broken command perl seems to run first for some reason, but I don't understand why.

Broken

testip=8.8.8.8
echo trace $testip
ping -W 1 -D -i 5 -t 3 -n $testip |
perl -p -e 's/^\[([0-9.]+)\]/"[".localtime($1)."]"/e' |
cat
# No output

# Output with set -x
+ perl -p -e 's/^\[([0-9.]+)\]/"[".localtime($1)."]"/e'
+ ping -W 1 -D -i 5 -t 3 -n 8.8.8.8
+ cat

But these work?

# working ping piping into cat
testip=8.8.8.8
echo trace $testip
ping -W 1 -D -i 5 -t 3 -n $testip |
cat

# Output
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
[1494968389.152046] From 169.204.238.1 icmp_seq=1 Time to live exceeded
[1494968394.156976] From 169.204.238.1 icmp_seq=2 Time to live exceeded

# working ping with perl fixing the time
testip=8.8.8.8
echo trace $testip
ping -W 1 -D -i 5 -t 3 -n $testip |
perl -p -e 's/^\[([0-9.]+)\]/"[".localtime($1)."]"/e'

# Output
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
[Tue May 16 14:02:02 2017] From 169.204.238.1 icmp_seq=1 Time to live exceeded
[Tue May 16 14:02:07 2017] From 169.204.238.1 icmp_seq=2 Time to live exceeded
Zoredache
  • 3,640
  • 2
    Because buffering. stdout is fully buffered by default when the output goes to a file or a pipe. If you wait long enough for the buffer to fill, you'll see a whole bunch of output at one go. Or if the program exits cleanly, e.g. if you had ping -c 2 so it doesn't go on indefinitely. See this question about the issue in general and this question for Perl. $| = 1; – ilkkachu May 16 '17 at 21:27
  • @ilkkachu Thanks. The unbuffer command suggested in the linked question seemed to be an adequate solution. – Zoredache May 16 '17 at 22:56
  • I ran out of characters in the comment to explain this in more words, but if the issue is just with a Perl script, you can just set $| = 1 to make Perl flush the output after every write. See the perlvar man page. unbuffer in particular seems a bit of a heavy hammer. – ilkkachu May 17 '17 at 10:07
  • @ilkkachu really in the long term I should probably do this entirely in python, perl or something. But at the moment I was just looking for a short term quick fix for monitoring of problem systems, and I couldn't get the $| = 1 to work right for some reason in my quick testing, but the unbuffer worked right way. – Zoredache May 17 '17 at 17:56

0 Answers0