Surprise! The Shell Suggests Command Line Switches

Surprise! the shell suggests command line switches

You have discovered Bash's programmable completion feature.

How to enable tab-completion of command line switches in bash?

Take a look at Extended Bash Completion

bash, logic of: a && b && c

You're misunderstanding success/failure statuses and also what && and || mean in this context in bash.

An exit status of success is 0, while failure is non-zero so when you say true returns "error" (exit status 1), no it doesn't. Also, nothing in shell "returns" anything. Scripts and functions produce output and have an exit status - using the word "return" leads to confusion over which of those 2 separate things you mean. For example if we define this function:

foo() {
echo "hello"
return 7
}

and then use it to populate a variable:

var=$(foo)
$ echo "$var"
hello

did foo() "return" hello or did foo() "return" 7? The best answer is no, it didn't "return" either - it output hello and exited with status 7.

Although there's a poorly-named "return" keyword there what that REALLY is producing is an exit status for the function, the same as if you had a shell script that was just:

echo "hello"
exit 7

and you can see that if you test it ($? always holds the exit status of the most recently run command):

foo() {
echo "hello"
return 7
}

$ foo
hello

$ echo "$?"
7

I assume the shell creators chose "return" for the function keyword because "exit" already meant "exit from the running process" but IMHO that made things confusing, though I don't have a better suggestion and even if I did that ship has sailed long ago. If you read return 7 as set the exit status to 7 then return from the function without assuming the function is actually "returning" anything then you'd be right.

Note also that the function is outputting "hello" - that's also not a "return" but if you use it as var=$(foo) then var ends up containing hello so then some people incorrectly refer to that as a "return" too since in other languages like C if you wrote var=foo():

char *foo() {
return "hello"
}
var=foo()

then var would contain the argument that was given to return in the function but that is just not the same semantics as shell where, unlike the similar C code above, var=$(foo) sets var to the output from foo(), not the "return" (actually exit status) from foo().

So - the function above doesn't actually "return" anything, it outputs hello and exits with status 7.

So here's what your command line true && echo "problem" || echo "exit" actually does:

  • true = output nothing and exit with status 0 (success)
  • echo "problem" - output problem and exit with status 0 (success)
  • echo "exit" - output exit and exit with status 0 (success)

Now, what do && and || mean? What they really are is shorthand for if statements:

  • && foo = if the previously run command exited success then execute foo
  • || foo = if the previously run command exited failure then execute foo

So a command line like:

cmdA && cmdB || cmdC

in terms of success/fail status should be read as:

cmdA
ret=$?
if (( ret == 0 )); then
cmdB
ret=$?
fi
if (( ret != 0 )); then
cmdC
ret=$?
fi
( exit "$ret" )

We need the ret temp variable because the if itself has an exit status that'd overwrite $?. So cmdC will get called if cmdA exits with a failure status, but it'll also get called if cmdA succeeded and then cmdB exited with a failure status. At the end of cmdA && cmdB || cmdC the exit status as stored in $? will simply be the exit status of whichever command ran last, it will not, for example, be the product of boolean arithmetic on all of the exit statuses of all the commands that ran as apparently suggested in the question might be the case.

Note also that what that should NOT be read as is what you may intuitively have expected if you thought of && ... || ... as a ternary expression, which trips many people up, especially since that || is typically an error leg whose incorrect placement may escape your code inspectors/testers notice:

cmdA
if (( $? == 0 )); then
cmdB
else
cmdC
fi

Given the above, here's what your command lines actually mean:

  1. true && echo "problem" || echo "exit"
true
ret=$?
if (( ret == 0 )); then
echo "problem"
ret=$?
fi
if (( ret != 0 )); then
echo "exit"
ret=$?
fi
( exit "$ret" )

  1. true && echo "problem" && echo "exit"
true
ret=$?
if (( ret == 0 )); then
echo "problem"
ret=$?
fi
if (( ret == 0 )); then
echo "exit"
ret=$?
fi
( exit "$ret" )

and if what you WANTED to have happen instead of "2" above was actually:

true
if (( $? == 0 )); then
echo "problem"
else
echo "exit"
fi

then you should write that code or similar instead of using &&s and ||s (e.g. as 1 line you could write if true; then echo "problem"; else echo "exit"; fi) so you don't get unexpected output if you reach the echo "problem" leg and it fails for some reason thereby causing you to afterwards fall into the echo "exit" leg (unlikely with just echo but very possible with other commands).

Bash in Git for Windows: Weirdness when running a command with CMD.exe /C with args

This is actually documented in the ReleaseNotes file (in the top level folder of your installed Git for Windows)

Also, extra care has to be paid to pass Windows programs Windows paths, as they have no clue about MSys style POSIX paths -- You can use something like $(cmd //c echo "$POSIXPATH").

If you use cmd //c echo test it works as expected.

$ cmd //c echo test
test

The cause is to do with trying to ensure that posix paths end up being passed to the git utilities properly. For this reason, Git for Windows includes a modified MSYS layer that affects command arguments. You should note that it is not intended that the bash shell and tools provided with Git for Windows be used as general purpose unix tools for Windows. If you want a general purpose unix-style toolset then you should install MSYS or cygwin. The Git Bash shell is setup for working with git and sometimes that shows.

Bind a key to accept the first suggested word function in Fish

Yes, the binding is nextd-or-forward-word. So you could write:

bind \el nextd-or-forward-word

\el is probably alt-L on your system as well, but you can double check by running fish-key_reader.

Java command line shell with auto-complete

Check out JReadline and jline2.

Android emulator-5554 offline

In such a case, you can do all of the following in order to be assured that your emulator starts working again :

  1. Go to cmd and type adb kill-server
  2. Go to task manager and find adb in processes. If you find one, right click on it and click on end process tree.
  3. In eclipse, go to Window>Android Virtual Device Manager, click on the AVD you want to launch, click on start and uncheck "Launch From Snapshot" and then click on launch.

That's it! It will take a while and it should resolve your problem.



Related Topics



Leave a reply



Submit