How can I use a pipe in a while condition?

10,321

Solution 1

To get the logic right, just minor changes are required. Use:

while ! df | grep '/toBeMounted'
do
  sleep 2
done
echo -e '\a'Hey, I think you wanted to know that /toBeMounted is available finally.

Discussion

The corresponding code in the question was:

while df | grep -v '/toBeMounted'

The exit code of a pipeline is the exit code of the last command in the pipeline. grep -v '/toBeMounted' will return true (code=0) if at least one line of input does not match /toBeMounted. Thus, this tests whether there are other things mounted besides /toBeMounted. This is not at all what you are looking for.

To use df and grep to test whether /toBeMounted is mounted, we need

df | grep '/toBeMounted'

This returns true if /toBeMounted is mounted. What you actually need is the negation of this: you need a condition that is true if /toBeMounted is not mounted. To do that, we just need to use negation, denoted by !:

! df | grep '/toBeMounted'

And, this is what we use in the code above.

Documentation

From the Bash manual:

The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully. If the reserved word ! precedes a pipeline, the exit status of that pipeline is the logical negation of the exit status as described above. The shell waits for all commands in the pipeline to terminate before returning a value.

Solution 2

The fact that you're using df with grep tells me that you're filtering output of df until some device mounts to specific directory, i.e. whether or not it's on the list.

Instead of filtering the list focus on the directory that you want. Luckly for us, the utility mountpoint allows us to do exactly that, and allows to deal with exit status of that command. Consider this:

$ mountpoint  /mnt/HDD/                                                        
/mnt/HDD/ is a mountpoint
$ echo $?
0
$ mountpoint  ~                                                                
/home/xieerqi is not a mountpoint
$ echo $?
1

Your script thus, can be rewritten as

while ! mountput /toBeMounted > /dev/null
do
   sleep 3
done
echo "Yup, /toBeMounted got mounted!"

Sample run with my own disk:

$ while ! mountpoint /mnt/HDD > /dev/null
> do 
>     echo "Waiting"
>     sleep 1
> done && echo "/mnt/HDD is mounted"
Waiting
Waiting
Waiting
Waiting
Waiting
/mnt/HDD is mounted

On a side note, you can fairly easy implement your own version of mountpoint command, for instance , in python , like i did:

#!/usr/bin/env python3
from os import path
import sys

def main():

    if not sys.argv[1]:
       print('Missing a path')
       sys.exit(1)

    full_path = path.realpath(sys.argv[1])
    with open('/proc/self/mounts') as mounts:
       print
       for line in mounts:
           if full_path in line:
              print(full_path,' is mountpoint')
              sys.exit(0)
    print(full_path,' is not a mountpoint')
    sys.exit(1)

if __name__ == '__main__':
    main()

Sample run:

$ python3 ./is_mountpoint.py /mnt/HDD                                          
/mnt/HDD  is mountpoint
$ python3 ./is_mountpoint.py ~                                                 
/home/xieerqi  is not a mountpoint
Share:
10,321

Related videos on Youtube

dlamblin
Author by

dlamblin

I had something here once. It was about work. #SOreadytohelp

Updated on September 18, 2022

Comments

  • dlamblin
    dlamblin over 1 year

    I want to loop while grep does or does not find something I can write:

    while grep 'matches' inLogFile.txt
    do
      echo good.
      sleep 10
    done
    

    Or

    while grep -v 'notHereYet' inLogFile.txt
    do
      sleep 2
    done
    echo -e '\a'Yo! It is here now.
    

    I'm typing these at the interactive shell prompt.

    So I wanted to repeatedly check df for when a volume actually got mounted, kind of like:

    while df | grep -v '/toBeMounted'
    do
      sleep 2
    done
    echo -e '\a'Hey, I think you wanted to know that /toBeMounted is available finally.
    

    I'm having trouble figuring out how to group the pipe into the condition.

    I know I could do something like:

    while [ -z "$(df|grep '/toBeMounted')" ]
    do
      sleep 2
    done
    echo -e '\a'Okay that is finally present now.
    

    Yet I feel as though there should be a way to do it using exit values instead of the string comparison.

  • dlamblin
    dlamblin over 7 years
    Yeah it looks like my real problem wasn't the pipe, but not clearly thinking about the -v on a line by line basis.
  • John1024
    John1024 over 7 years
    @dlamblin Yes, it is a subtle point. -v negates the grep test but, for multi-line output, that is not the same as a negation of the grep exit code.
  • dlamblin
    dlamblin over 7 years
    I was generally unclear on using a pipe in a conditional statement. But the specific case of checking for a mounted device, mountpoint sounds perfect, thanks. Though conceptually in this case I could have also just done: while [ ! -d /toBeMounted ]; do sleep 2; done; echo -e \\aDing the directory is available now.
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy over 7 years
    @dlamblin well , [ ! -d /toBeMounted ] tells me that you're expecting that directory to be created, though that is not usually how mounting works. Sometimes a sysadmin has dedicated directory where stuff is mounted, so that directory is already created. I mean, it really depends on what you're looking for. With mountpoint it's better because you have simple syntax and it works for either created directory case or to-be created case. As for pipes in conditional statements, they're messy , so I'd recommend avoiding them , since the exit status of last piped command is not always what we want
  • dlamblin
    dlamblin over 7 years
    oh, right, I'd need to look for a sub-directory I know to be on the drive but not at the mount point. like [ ! -d /toBeMounted/stuff ] where as mountpoint can tell if a directory currently has something mounted on it, I suppose.