How can I use a pipe in a while condition?
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
Related videos on Youtube
dlamblin
I had something here once. It was about work. #SOreadytohelp
Updated on September 18, 2022Comments
-
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 over 7 yearsYeah it looks like my real problem wasn't the pipe, but not clearly thinking about the
-v
on a line by line basis. -
John1024 over 7 years@dlamblin Yes, it is a subtle point.
-v
negates thegrep
test but, for multi-line output, that is not the same as a negation of thegrep
exit code. -
dlamblin over 7 yearsI 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 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. Withmountpoint
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 over 7 yearsoh, 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.