The [
command is to evaluate conditional expressions. It's of no use here.
Because umount
doesn't output anything on its standard output (the errors go to stderr), `sudo umount mount`
expands to nothing.
So it's like:
while [ ]
do
sleep 0.1
done
The [
command, when not passed any argument beside [
and ]
returns false (a non-zero exit status), so you will not enter the loop.
Even if umount
had output its errors on stdout, using the [
command would not have made sense, because the words resulting of that output would never have made up a valid conditional expression.
Here you want:
until sudo umount mount
do
sleep 0.1
done
That is, you want to check the exit status of sudo/umount, not of a [
command.
If you wanted to check if umount
output any error or warning on its stderr, that's where the [
could have been useful. The -n "some-string"
is a conditional expression recognised by the [
command to test whether "some-string"
is empty or not, so something like:
while [ -n "$(sudo umount mount 2>&1 > /dev/null)" ]; do
sleep 0.1
done
But looking for the presence of error or warning messages is generally a bad idea. The umount
command tells us whether or not it succeeds with its exit code, that's much more reliable. It could succeed and still output some warning message. It could fail and not output an error (like when it's killed).
In this particular case, note that umount
might fail because the directory is not mounted, and you would loop forever in that case, so you could try another approach like:
while mountpoint -q mount && ! sudo umount mount; do
sleep 0.1
done
Or if "mount" may be mounted several times and you want to unmount them all:
while mountpoint -q mount; do
sudo umount mount || sleep 0.1
done
You (likely) read first out of two+ bytes. $keycode
in your script would be ESC when arrow key is pressed.
Arrow keys can be:
\x1b + some value
It always evaluates to true because of missing spaces in conditional expression.
Edit: an update on that statement.
Your if
operates on the exit status of the [
command. The [
command is equivalent to test
. The fact that it is a command is a very important fact. As a command it require spaces between arguments. The [
command is further special in that it require ]
as last argument.
[ EXPRESSION ]
The command exits with the status determined by EXPRESSION. 1 or 0, true or false.
It is not an exotic way to write parenthesis. In other words it is not part of the if
syntax as for example in C:
if (x == 39)
By:
if [ "$keycode"=39 ]; then
you issue:
[ "$keycode"=39 ]
which expands to
[ \x1b=39 ]
here \x1b=39
is read as one argument. When test
or [
is given one argument it exits with false only if EXPRESSION is null – which is is never going to be. Even if $keycode
was empty, it would result in =39
(which is not null / empty).
Another way to look at it is that you say:
if 0 ; then # When _command_ exit with 0.
if 1 ; then # When _command_ exit with 1.
Read these questions and answers for more details – as well as discussion on [
vs [[
:
In that regard you could also research back ticks `` vs $( )
Multibyte escape sequence with arrow keys:
As mentioned at the top: You (likely) read first out of two+ bytes. $keycode
in your script would be ESC when arrow key is pressed.
Arrow and other special keys result in escape sequences to be sent to the system. The ESC byte signals that "here comes some bytes that should be interpreted differently". As for arrow keys that would be the ASCII [
followed by ASCII A
, B
, C
or D
.
In other words you have to parse three bytes when dealing with arrow keys.
You could try something in the direction of this to check:
{ stty_state=$(stty -g)
stty raw isig -echo
keycode=$(dd bs=8 conv=sync count=1)
stty "$stty_state"
} </dev/tty 2>/dev/null
printf %s "$keycode" | xxd
Yield:
HEX ASCII
1b 5b 41 .[A # Up arrow
1b 5b 42 .[B # Down arrow
1b 5b 43 .[C # Right arrow
1b 5b 44 .[D # Left arrow
| | |
| | +------ ASCII A, B, C and D
| +--------- ASCII [
+------------ ASCII ESC
Not sure how portable this is, but have earlier played around with code like this for catching arrow keys. Press q
to quit:
while read -rsn1 ui; do
case "$ui" in
$'\x1b') # Handle ESC sequence.
# Flush read. We account for sequences for Fx keys as
# well. 6 should suffice far more then enough.
read -rsn1 -t 0.1 tmp
if [[ "$tmp" == "[" ]]; then
read -rsn1 -t 0.1 tmp
case "$tmp" in
"A") printf "Up\n";;
"B") printf "Down\n";;
"C") printf "Right\n";;
"D") printf "Left\n";;
esac
fi
# Flush "stdin" with 0.1 sec timeout.
read -rsn5 -t 0.1
;;
# Other one byte (char) cases. Here only quit.
q) break;;
esac
done
(As a minor note you also (intend to) test against decimal 39 – which looks like a mixup between decimal and hexadecimal. First byte in an escape sequence is ASCII value ESC, which is decimal 27 and hexadecimal 0x1b
, while decimal 39 is hexadecimal 0x27
.)
Best Answer
Maybe this helps you. I integrated both of them, with slight modifications though. Here's the result.
As you can see, I put the second script in place of the
sleep
command in the former first one. The time-out inread
now bears the time lapse function. Notice that the-N
option is needed forread
not to wait for Enter and react as soon as the first key has been pressed.