If ack finds results do this; else do that [duplicate] - bash

This question already has answers here:
How to use double or single brackets, parentheses, curly braces
(9 answers)
Closed 8 years ago.
I'm trying to write out a script that will automate one of my more tedious tasks. I've pretty much got everything down and can get the individual components of code to do what I want them to, but I'm running into trouble trying to get the if statement to work. Here's what I'm trying to do:
if [ ack --ignore-case 'foo' ]; then
Do this action
else
Do that action
fi
As of now it always does the else action, even if the ack parameter is true.
Thanks!

Just drop the square brackets
if ack --ignore-case 'foo' ; then
Do this action
else
Do that action
fi
You don't want to check that the string ack --ignore-case 'foo' is non-empty, you want to check ack's exit status.
You should have recieved a warning telling you so:
-bash: [: --ignore-spaces: binary operator expected

Remove the [ - you want to check the exit status of ack:
if ack --ignore-case 'foo'; then
ack returns a 0 (success) exit status if a match is encountered.
Although it may look like a syntactical construct, [ is in fact a function (synonymous with test), which returns 0 if the test passes. if is looking at the return code of this function. In this case, ack gives you the return code that you need instead, so you shouldn't also be using [.

Related

how to check if the result of a bash function is a specific string in while loop?

(I'm not a linux guy) and I want to check the status of a service when its updating (takes about 10 minutes) to make sure it is successful. I use a function to run the status command and while loop as follow:
get_status() { echo ...my command runs here and return the statue; }
I simply can get the status like $(get_status). Now I want to see what is the status and take action:
while $(get_status) == "PENDING"; do echo retrying... && sleep 5; done
I've tried different ways like single/double brackets but cannot get the while comparison to work properly? Can anybody help please?
The while loop doesn't know anything about comparison tests. It only knows how to check the exit status of a command, and $(get_status) == "PENDING" is not a command. The brackets you want are for either a test command or a bash conditional expression command.
while test "$(get_status)" = "PENDING"; do
or
# [ is a synonym for test, with the added requirement that
# there be a final argument ] to complete the illusion of
# syntax.
while [ "$(get_status) = "PENDING" ]; do
or
while [[ $(get_status) == "PENDING" ]]; do
In the first two cases, = is preferred as the correct equality operator for test/[. In the last case, == may be used, and the quotes can be dropped around $(get_status) because no word-splitting or filename generation is performed on expansions in [[ ... ]]. (The quotes could be dropped around the literal word PENDING in all three cases, but could remain necessary for some right-hand arguments inside [[ ... ]] for reasons beyond the scope of this question.)

Exit Code when called with No Arguments

I have a script that requires at least one argument. If the arguments are incorrect I will obviously return a non-zero exit code.
I have decided to print the usage instructions when called with no arguments, but I'm uncertain of the exit code. Should it be
0 (success)
one of the values [1-125] (error)
An argument could be made either way. Is some option recommended?
It depends on whether you want the callers of your script to know programatically why it failed.
If, for example, it will only ever be run by a human, you could just return 1 and rely on the error text to inform them.
You could even return zero regardless if you only ever want a human to easily know (via the output) if it failed but I would consider this very bad form - Microsoft have made this mistake in the past with some of their commands not setting %errorlevel%, making it very difficult for a script to figure out whether it's worked or not.
Even if you decide not to indicate why it failed, you should at least indicate that it failed.
If you want a program to easily figure out why it failed, return a different code for each discernible error type.
Any Unix command when it returns control to its parent process returns a code, number between 0 and 255.
Success is traditionally represented with exit 0; failure is normally indicated with a non-zero exit-code. This value can indicate different reasons for failure.
So what you have also is another case of unsuccessful completion of your program which should be treated as returning a proper error code and not 0.
Also note that traditional Unix system calls don't signal an error code for empty arguments, they have to be caught explicitly. There are ones for argument list too long (E2BIG) and invalid arguments (EINVAL).
This is what I decided on using, based mostly on Inians answer and the reserved exit codes presented here.
I decided on somewhat reusing the exit codes defined in /usr/include/asm-generic/errno-base.h1. There was nothing suitable for "too little arguments", so I picked the first one from the 64-113 range.
# Error codes
E2BIG=7
EINVAL=22
E2SMALL=64
NAME="my-script"
USAGE=$(cat << END
the help text
RETURN CODES
$NAME has the following return codes:
0 success
$E2BIG Argument list too long
$EINVAL Invalid argument
$E2SMALL Argument list too short
END
)
# This script requires exactly one argument. If less are provided it prints
# the USAGE instructions
if [ ${#} -lt 1 ] ; then
printf '%s\n' "${USAGE}"
exit $E2SMALL
fi
if [ "${1}" = "-h" ] || [ "${1}" = "--help" ] ; then
printf '%s\n' "${USAGE}"
exit 0
fi
if [ ${#} -gt 1 ] ; then
printf '%s\n' "${USAGE}"
exit $E2BIG
fi
It's a bit verbose, but at least there's a properly defined error code if the script is called improperly.
1 This may be debatable, but since the codes were already defined...

I found this code in an autoconf configure script what is the following code trying to do?

I found this code in an autoconf configure script. What is the following code trying to do?
if ${am_cv_autoconf_installed+:} false; then :
$as_echo_n "(cached) " >&6
else
Lots of stuff going on here. Let's break it down.
First of all, the syntax ${var+foo} is a common idiom for checking whether the variable var has been defined. If var is defined, then ${var+foo} will expand to the string foo. Otherwise, it will expand to an empty string.
Most commonly (in bash, anyway), this syntax is used as follows:
if [ -n "${var+foo}" ]; then
echo "var is defined"
else
echo "var is not defined"
fi
Note that foo is just any arbitrary text. You could just as well use x or abc or ilovetacos.
However, in your example, there are no brackets. So whatever ${am_cv_autoconf_installed+:} expands to (if anything) will be evaluated as a command. As it turns out, : is actually a shell command. Namely, it's the "null command". It has no effect, other than to set the command exit status to 0 (success). Likewise, false is a shell command that does nothing, but sets the exit status to 1 (failure).
So depending on whether the variable am_cv_autoconf_installed is defined, the script will then execute one of the following commands:
: false
-OR-
false
In the first case, it calls the null command with the string "false" as an argument, which is simply ignored, causing the if statement to evaluate to true. In the second case, it calls the false command, causing the if statement to evaluate to false.
So all this is really doing is checking whether am_cv_autoconf_installed is defined. If this were just an ordinary bash script and didn't require any particular level of portability, it would have been a lot simpler to just do:
if [ -n "${am_cv_autoconf_installed+x}" ]; then
However, since this is a configure script, it was no doubt written this way for maximum portability. Not all shells will have the -n test. Some may not even have the [ ] syntax.
The rest should be fairly self-explanatory. If the variable is defined, the if statement evaluates to true (or more accurately, it sets the exit status to 0), causing the $as_echo_n "(cached) " >&6 line to execute. Otherwise, it does whatever is in the else clause.
I'm guessing $as_echo_n is just the environment-specific version of echo -n, which means it will print "(cached) " with no trailing newline. The >&6 means the output will be redirected to file descriptor 6 which presumably is set up elsewhere in the script (probably a log file or some such).

script in bash not understood using terminal in Ubuntu 12.04

Can anyone tells me what does this script means found in a .sh file:
[ ! -n "$T_R" ] && echo "Message Appear" && exit 1;
Edit: Correcting for misinformation pointed out by tripleee
The brackets [ ]
are an alias for 'test', which tests whether a condition is met. Not to complicate matters, but do note that this is discrete from the the bash shell keyword [[ ]] (Thanks, tripleee for clearing that up!). See This post for further details. These days, most people seem to use the latter due to its more robust feature set.
Between the brackets, the script is testing to determine whether the variable "$T_R" is an empty string.
The -n operator returns true if the length of the string passed to it as an argument is non-empty.
The ! inverts the case (the test succeeds if the result is not
true). So in this case, test suceeds (returns 0) if the length of
the string variable "$T_R" is **not non-zero ** (i.e. if the
variable is an empty-string, or is non-existant).
The double-ampersand, && operator means only execute the subsequent code in the event of success, so the message "Message Appear" will only be echoed in the event the test succeeds (again, if "$T_R" is empty or unset).
Finally, the && exit 1 says to exit returning status 1 after successfully echoing the Message Appear message.
The bash and test man pages are extremely helpful on all of these topics and should be consulted for further details.
The chained && is a common short-circuit idiom.
Instead of writing
if true; then
if true; then
echo moo
fi
fi
you can abbreviate to just true && true && echo moo.
echo will usually succeed so true && echo moo && exit 1 will execute both the echo and the exit if true succeeds (which obviously it always will).
(There are probably extreme corner cases where echo could fail, but if that happens, you are toast anyways so I don't think it makes sense to try to guard against those.)
The [ is an alias for test which is a general comparison helper for shell scripts (in Bash, it's even a built-in). test -n checks whether a string is non-empty.
! is the general negation operator, so it inverts the test to checking for an empty string.
(This is slightly unidiomatic, because there is a separate test -z "$T_R" which checks specifically for the string being empty.)

How to evaluate a boolean variable in an if block in bash? [duplicate]

This question already has answers here:
How can I declare and use Boolean variables in a shell script?
(25 answers)
Checking the success of a command in a bash `if [ .. ]` statement
(1 answer)
Closed 5 years ago.
I have defined the following variable:
myVar=true
now I'd like to run something along the lines of this:
if [ myVar ]
then
echo "true"
else
echo "false"
fi
The above code does work, but if I try to set
myVar=false
it will still output true.
What might be the problem?
edit: I know I can do something of the form
if [ "$myVar" = "true" ]; then ...
but it is kinda awkward.
Thanks
bash doesn't know boolean variables, nor does test (which is what gets called when you use [).
A solution would be:
if $myVar ; then ... ; fi
because true and false are commands that return 0 or 1 respectively which is what if expects.
Note that the values are "swapped". The command after if must return 0 on success while 0 means "false" in most programming languages.
SECURITY WARNING: This works because BASH expands the variable, then tries to execute the result as a command! Make sure the variable can't contain malicious code like rm -rf /
Note that the if $myVar; then ... ;fi construct has a security problem you might want to avoid with
case $myvar in
(true) echo "is true";;
(false) echo "is false";;
(rm -rf*) echo "I just dodged a bullet";;
esac
You might also want to rethink why if [ "$myvar" = "true" ] appears awkward to you. It's a shell string comparison that beats possibly forking a process just to obtain an exit status. A fork is a heavy and expensive operation, while a string comparison is dead cheap. Think a few CPU cycles versus several thousand. My case solution is also handled without forks.

Resources