How can I use read timeouts with stat?
Asked Answered
S

2

0

I have the following code:

#!/bin/bash

read -t1 < <(stat -t "/my/mountpoint")
if [ $? -eq 1 ]; then
  echo NFS mount stale. Removing... 
  umount -f -l /my/mountpoint
fi

How do I mute the output of stat while at the same time being still able to detect its error level in the subsequent test?

Adding >/dev/null 2>&1 inside the subshell, or in the end of the read line does not work. But there must be a way...

Thanks for any insights on this!

Seavey answered 19/7, 2013 at 16:56 Comment(0)
U
3

Use Command-Subsitution, Not Process Substitution

Instead of reading in from process subsitution, consider using command substitution instead. For example:

mountpoint=$(stat -t "/my/mountpoint" 2>&1)

This will silence the output by storing standard output in a variable, but leave the results retrievable by dereferencing $mountpoint. This approach also leaves the exit status accessible through $?.

A Clearer Alternative

Alternatively, you might just rewrite this more simply as:

mountpoint="/my/mountpoint"
if stat -t "$mountpoint" 2>&-
then
    echo "NFS mount stale. Removing..."
    umount -f -l "$mountpoint"
fi

To me, this seems more intention-revealing and less error-prone, but your mileage may certainly vary.

(Ab)using Read Timeouts

In the comments, the OP asked whether read timeouts could be abused to handle hung input from stat. The answer is yes, if you close standard error and check for an empty $REPLY string. For example:

mountpoint="/my/mountpoint"
read -t1 < <(stat -t "$mountpoint" 2>&-)
if [[ -n "$REPLY" ]]; then
    echo "NFS mount stale. Removing..."
    umount -f -l "$mountpoint"
fi

This works for several reasons:

  1. When using the read builtin in Bash:

    If no NAMEs are supplied, the line read is stored in the REPLY variable.

  2. With standard error closed, $REPLY will be empty unless stat returns something on standard output, which it won't if it encounters an error. In other words, you're checking the contents of the $REPLY string instead of the exit status from read.
Unpractical answered 19/7, 2013 at 17:7 Comment(4)
Thanks for the reply! Is there any way to combine this with read? The reason it's there is to time out a command that would otherwise hang. This also happens with rpcinfo: read -t1 < <(rpcinfo -t 10.0.128.1 nfs) if [ $? -eq 0 ] ; then _RET=true else _RET=false fi If 10.0.128.1 is not reachable, rpcinfo by itself would hang for a few minutes. Redirection to read allows it to time out in 1 second instead. It is specifically in this context–with read–that I'm having difficulty suppressing the output.Seavey
Heh.. okay, accepted! :) You posted the follow-up at the same time.Seavey
Also, I wasn't aware of read's REPLY variable.. very useful, thank you!Seavey
It seems an exit status still works even with 2>&- in effect. The lines if [ $? -eq 0 ]; then ... and if [[ -n "$REPLY" ]] ; then ... seem to work equally well when read -t1 is used to time out the hung command, and 2>&- is used within the subshell to mute standard error (as in the example).Seavey
S
0

I think I got it! The redirection mentioned in your response seems to work within the subshell without wiping out the return code like 2>&1 did. So this works as expected:

read -t1 < <(rpcinfo -t 10.0.128.1 nfs 2>&-)
if [ $? -eq 0 ]; then
  echo "NFS server/service available!"
else
  echo "NFS server/service unavailable!"
fi

Where 10.0.128.1 is a 'bad' IP (no server/service responding). The script times out within a second and produces "NFS server/service unavailable!" response, but no output from rpcinfo. Likewise, when the IP is good, the desired response is output.

I upvoted your response!

Seavey answered 19/7, 2013 at 18:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.