logic of this piece of bashquery - linux

Not able to understand what this is doing
TEST_DEBUG=${TEST_DEBUG:-false}
[[ "$TEST_DEBUG" == false ]] || TEST_DEBUG=true
and in further down the code in multiple places..this code is present
$TEST_DEBUG && echo 1>&2

TEST_DEBUG=${TEST_DEBUG:-false}
This assing false to $TEST_DEBUG unless it already has a value (see Parameter Expansion in man bash).
[[ "$TEST_DEBUG" == false ]] || TEST_DEBUG=true
The condition inside [[ ... ]] returns true when $TEST_DEBUG has the value of false. If it returns false, i.e. the value is different, then $TEST_DEBUG is assigned true.
$TEST_DEBUG && echo 1>&2
This runs the echo only if $TEST_DEBUG is set to true.
echo without parameters just outputs an empty line to standard output. 1>&2 redirects standard output to standard error, so in this case, the empty line is printed to standard error.

In first statement, the operator :- Tests if TEST_DEBUG variable exists within the braces and is set, if it is set, it is assigned the value in the TEST_DEBUG if not set or has a null value, it is assigned false.
TEST_DEBUG=${TEST_DEBUG:-false}
in the second statement
[[ "$TEST_DEBUG" == false ]] || TEST_DEBUG=true
Bash checks if TEST_DEBUG is set to false, if not, it assigns it a value true.
for more information on how this works in detail, please check out GNU bash documentation.
https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html#Conditional-Constructs

Related

Variable set with `elif [[ -n ${var=$(mycommand ...args...)} ]]` unexpectedly empty

I'm not sure if this is a good way to define a variable inside an elif statement.
I want to set VALUE with the value of CUSTOM_KEY if it contains something else get the value from the configmap.
It seems that sometimes it can take few seconds to run the command in the second elif statement and I'm unsure if it can affect the result of the command.
if [[ -n "${CUSTOM_KEY}" ]]; then
VALUE="${CUSTOM_KEY}"
echo "VALUE: ${VALUE} set from CUSTOM_KEY"
elif [[ -n "${VALUE="$(kubectl get configmap configmapvalue -n "${N}" -o jsonpath="{.data.VALUE}")"}" ]]; then
echo "VALUE: ${VALUE} set from configmap configmapvalue"
else
echo "Please, define a CUSTOM_VALUE"
fi
echo "${VALUE}"
The immediate problem is that ${var=value} only assigns to var when the variable is previously unset.
We don't know that it's unset, because [ -n "$var" ] tests only if it's empty. A variable can be set to an empty value, in which case ${var=default} won't change it, but ${var:=default} will.
You don't need to use ${var=default} or ${var:=default}, though, because if the elif clause is executed at all, you know that you need to update the value from kubectl. Thus:
elif VALUE=$(kubectl get configmap configmapvalue -n "$N" -o jsonpath='{.data.VALUE}') && [[ $VALUE ]]; then

Read command in if clause in bash

elif [ "$arg" == "--file" ] || [ "$arg" == "-f" ] && [[ read var ]]
then
touch $var
I'm writing a bash script which takes in a command-line input, either long-form or short-form along with the file name to create an empty file with touch command. the above snippet is what I tried to do, but there's an error unary "read: unary operator expected".please help
This happens for most commands:
$ [[ echo "hello world" ]]
bash: conditional binary operator expected
bash: syntax error near `world"'
This is because [[ .. ]] should be used to compare values, and not to run commands. To run a command, don't wrap it in anything:
$ echo "hello world"
hello world
Applied to your example:
echo "You are expected to type in a value, but you will receive no prompt."
arg="-f"
if [ "$arg" == "--file" ] || [ "$arg" == "-f" ] && read var
then
echo "You entered: $var"
fi
Bash needs to know that it's running a whole command
To make bash aware that it's running a command you can use the backtick syntax (not recommended) or the preferred $() command substitution syntax. Without this syntax, bash is assuming that you're putting two separate strings inside of that condition.
The error you're getting is saying that you are trying to compare two strings without an operator to do so (i.e. -eq or ==).
Here is an example of how to make it recognize your commands:
elif [[ ... ]] && [[ $(read var) ]]
then
However, this won't work. This will evaluate to false. This is because you haven't printed anything out and as such an empty string ("") is falsey.
echo your variable to test its value
elif [[ ... ]] && [[ $(read var; echo $var) ]]
then
This will read into the variable and then test if the user has typed anything into it. If the user doesn't type anything, it will evaluate to false, otherwise, it will evaluate to true and run the body of the elif statement.

Unable to compare date variable in unix

*I am having issue *
while comparing date variable in if clause, because i am getting one date variable value is "$'2014-04-19\r'" and another one is 2014-04-19.
how i come to know the value of variable is this
by set -x property in my shell script
value of variable in if condition has shown me in command line is below -
+ [ $'2014-04-19\r' == 2014-04-19 ]
so how can i compare because in simple text format both variable looks same, and i want to be true that condition.
can we remove $' and \r' from that variable...
You can compare using [[ and ]] in BASH like this:
s=$'2014-04-19\r'
[[ "$s" == '2014-04-19'? ]] && echo "similar"
OR more precisely:
[[ "$s" == '2014-04-19'$'\r' ]] && echo "similar"
you can use like :
sed 's/\'\\r\'//g' < your_input_file > your_output_file
It will replace the unwanted string with the space.

bash — boolean expression evaluation without condition

I tried to play around with bash, and even tried documentation and few threads though I cannot seem to get it right.
S=(true false)
if (( ${S[0]} || ${S[1]} ))
then
echo "true"
else
echo "false"
fi
how can the boolean expression be evaluated under bash? (any chance to fix the snippet above?)
is there any possibility to evaluate it without if, i.e. assign it to a variable directly (no if manipulation)?
Instead of S=(true false), you need to create your array like this:
S=(1 0)
Then this if block:
if (( ${S[0]} || ${S[1]} ))
then
echo "true"
else
echo "false"
fi
will output:
true
Please note that true/false are treated as literal strings "true" and "false" in BASH.
There isn't really such a thing as boolean in bash, only integral arithmetic expressions e.g. (( n )), which would return an exit code of 0 (no error or no failure code) if its value is greater than 1, or a nonzero code (has error code) if it evaluates to 0. if statements execute a then block if the command it calls returns 0 exit code, or on the else block otherwise. You can imitate boolean systems in bash like this though:
#!/bin/bash
true=1
false=0
A=true
B=false
# Compare by arithmetic:
if (( A || B )); then
echo "Arithmetic condition was true."
else
echo "Arithmetic condition was false."
fi
if (( (I > 1) == true )); then ## Same as (( I > 1 )) actually.
echo "Arithmetic condition was true."
else
echo "Arithmetic condition was false."
fi
# Compare by string
if [[ $A == true || $B == true ]]; then
echo "Conditional expression was true."
else
echo "Conditional expression was false."
fi
# Compare by builtin command
if "$A" || "$B"; then
echo "True concept builtin command was called."
else
echo "False concept builtin command was called."
fi
And I prefer the string comparison since it's a less hacky approach despite probably being a bit slower. But I could use the other methods too if I want too.
(( )), [[ ]], true, and false all are just builtin commands or expressions that return an exit code. It's better that you just think of the like that than thinking that they are really part of the shell's main syntax.

Bash Script is returning true for both but opposite string tests

Before I ran the script I have entered
# export CPIC_MAX_CONV=500
The following is the test1.script file
#!/bin/bash
function cpic () {
var="`export | grep -i "CPIC_MAX_CONV" | awk '/CPIC_MAX_CONV/ { print $NF } '`"
[[ $var=="" ]] && (echo "Empty String <<")
[[ $var!="" ]] && (echo "$CPIC_MAX_CONV")
echo "$var" ;
}
cpic
The output is:
# test1.script ---- Me running the file
Empty String <<
500
CPIC_MAX_CONV="500"
No matter what I use "" or '' or [ or [[ the result is the same. The CPIC_MAX_CONV variable is found by the above script.
I am running this on Linux/CentOS 6.3.
The idea is simple: To find if CPIC_MAX_CONV is defined in the environment and return the value of it. If an empty space is there then of course the variable is not present in the system.
Why do you always get true? Let's play a little bit in your terminal first:
$ [[ hello ]] && echo "True"
What do you think the output is? (try it!) And with the following?
$ [[ "" ]] && echo "True"
(try it!).
All right, so it seems that a non-empty string is equivalent to the true expression, and an empty string (or an unset variable) is equivalent to the false expression.
What you did is the following:
[[ $var=="" ]]
and
[[ $var!="" ]]
so you gave a non-empty string, which is true!
In order to perform the test, you actually need spaces between the tokens:
[[ $var == "" ]]
instead. Now, your test would be better written as:
if [[ -z "$var" ]]; then
echo "Empty String <<"
else
echo "$CPIC_MAX_CONV"
fi
(without the sub-shells, and with just one test).
There's more to say about your scripting style. With no offence, I would say it's really bad:
Don't use backticks! Use the $(...) construct instead. Hence:
var="$(export | grep -i "CPIC_MAX_CONV" | awk '/CPIC_MAX_CONV/ { print $NF } ')"
Don't use function blah to define a function. Your function should have been defined as:
cpic () {
local var="$(export | grep -i "CPIC_MAX_CONV" | awk '/CPIC_MAX_CONV/ { print $NF } ')"
if [[ -z "$var" ]]; then
echo "Empty String <<"
else
echo "$CPIC_MAX_CONV"
fi
}
Oh, I used the local keyword, because I guess you're not going to use the variable var outside of the function cpic.
Now, what's the purpose of the function cpic and in particular of the stuff where you're defining the variable var? It would be hard to describe (as there are so many cases you haven't thought of). (Btw, your grep seems really useless here). Here are a few cases you overlooked:
An exported variable is named somethingfunnyCPIC_MAX_CONVsomethingevenfunnier
An exported variable contains the string CPIC_MAX_CONV somewhere, e.g.,
export a_cool_variable="I want to screw up Randhawa's script and just for that, let's write CPIC_MAX_CONV somewhere here"
Ok, I don't want to describe what your line is doing exactly, but I kind of guess that your purpose is to know whether the variable CPIC_MAX_CONV is set and marked for export, right? In that case, you'd be better with just this:
cpic () {
if declare -x | grep -q '^declare -x CPIC_MAX_CONV='; then
echo "Empty String <<"
else
echo "$CPIC_MAX_CONV"
fi
}
It will be more efficient, and much more robust.
Oh, I'm now just reading the end of your post. If you want to just tell if variable CPIC_MAX_CONV is set (to some non-empty value — it seems you don't care if it's marked for export or not, correct me if I'm wrong), it's even simpler (and it will be much much more efficient):
cpic () {
if [[ "$CPIC_MAX_CONV" ]]; then
echo "Empty String <<"
else
echo "$CPIC_MAX_CONV"
fi
}
will do as well!
Do you really care whether CPIC_MAX_CONV is an environment variable versus just 'it is a variable that might be an environment variable'? Most likely, you won't, not least because if it is a variable but not an environment variable, any script you run won't see the value (but if you insist on using aliases and functions, then it might matter, but still probably won't).
It appears, then, that you are trying to test whether CPIC_MAX_CONV is set to a non-empty value. There are multiple easy ways to do that — and then there's the way you've tried.
: ${CPIC_MAX_CONV:=500}
This ensures that CPIC_MAX_CONV is set to a non-empty value; it uses 500 if there previously wasn't a value set. The : (colon) command evaluates its arguments and reports success. You can arrange to export the variable after it is created if you want to with export CPIC_MAX_CONV.
If you must have the variable set (there is no suitable default), then you use:
: ${CPIC_MAX_CONV:?}
or
: ${CPIC_MAX_CONV:?'The CPIC_MAX_CONV variable is not set but must be set'}
The difference is that you can use the default message ('CPIC_MAX_CONV: parameter null or not set') or specify your own.
If you're only going to use the value once, you can do an 'on the fly' substitution in a command with:
cpic_command -c ${CPIC_MAX_CONV:-500} ...
This does not create the variable if it does not exist, unlike the := notation which does.
In all these notations, I've been using a colon as part of the operation. That enforces 'null or not set'; you can omit the colon, but that allows an empty string as a valid value, which is probably not what you want. Note that a string consisting of just a blank is 'not empty'; if you need to validate that you've got a non-empty string, you have to work a little harder.
I'm not dissecting your misuse of the [[ command; gniourf_gniourf has provided an excellent deconstruction of that, but overlooked the simpler notations available to do what seems to be the job.
Try this:
#!/bin/bash
function cpic () {
var="`export | grep -i "CPIC_MAX_CONV"`"
[ "$var" = "" ] && (echo "Empty String <<")
[ "$var" != "" ] && echo "$CPIC_MAX_CONV"
}
cpic
You need spaces in your conditions.
#!/bin/bash
function cpic () {
var="`export | grep -i "CPIC_MAX_CONV" | awk '/CPIC_MAX_CONV/ { print $NF } '`"
[[ $var == "" ]] && (echo "Empty String <<")
[[ $var != "" ]] && (echo "$CPIC_MAX_CONV")
echo "$var" ;
}
cpic

Resources