Pass Variable Name and Value in Bash Script - linux

I just want to verify that the script I wrote is doing what I think it's doing, and that it's doing it properly.
I wanted to write a script that takes an environment variable and a string value, and then sets that variable to the given value. So I can do something like setvar BOOST_HOME /home/me/boost/boost_1.52.0 and the script will export BOOST_HOME=/home/me/boost/boost_1.52.0
Something like:
#!/bin/bash
# Usage: setvar VAR VAR_VALUE
function setvar()
{
VAR=${1}
VAR_VALUE=${2}
if [ -d $2 ]
then
eval export $VAR=$2
fi
}
This seems to work, at least judging from a echo echo tests, but I am still not very comfortable with shell scripting, and would like someone to either verify what I am doing or point out what I am doing wrong / less correct.

You don't need the eval.
setvar() {
if [[ -d $2 ]]; then
export "$1=$2"
fi
}
Using [[ instead of [ avoids the need to quote $2, since the bash (and other shell) extension [[ does not word-split interior parameter expansions. If I'd stuck with the old-fashioned [ -d "$2" ], I would have had to quote the $2 in case its value included whitespace.

Related

Bash Script - Wrapping Variables in Quotes

I was doing some reading here and it suggested that I wrap my variables in quotes just in case the value contains spaces.
If I have the following script:
#!/bin/bash
function checkDirectory()
{
local checkDir=$1
if [[ -d $checkDir ]] ; then
echo "File is directory"
fi
}
checkDirectory "/home/someuser/Downloads/"
If I wrap my parameter, in this case, "/home/someuser/Downloads/" in quotes, do I still need to wrap $1 and checkDir in quotes as well?
No. You don't have to as $1 will be assigned to checkDir correctly and bash's [[ ]] won't do word splitting and your script will work as expected.
However, in case if you use sh test [ .. ] then you'll have a problem with:
if [ -d $checkDir ] ; then
echo "File is directory"
fi
So it's always good practice to quote your variables rather than having to remember it matters and when not.

What means the -z value in an if expression on a Linux script?

In this script I found this if expression:
if [ -z $1 ]; then
echo "Usage: createpkg.sh <rev package>"
exit
else
CURRENT_VERSION=$1
fi
My problem is that I can't find what exactly means this -z value.
From the content of the echo I can deduct that (maybe) $1 variable represents the sotware version. and that (maybe) -z is a void value. So if I execute the script without passing to it the version of the software that I would packing it print me the correct procedure to execute the script.
But I am not sure about the real meaning of the -z value.
From man test:
-z STRING
the length of STRING is zero
So the condition:
if [ -z $1 ]; then
means "if the variable $1 is empty". Where $1 is probably the first parameter of the script: if you execute it like ./script <parameter1> <parameter2>, then $1=parameter1, $2=parameter2 and so forth.
help test tells:
String operators:
-z STRING True if string is empty.
In your example, the script would print Usage: createpkg.sh <rev package> and exit if an argument was not supplied.

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

Bash ARGS help - getting random error

Trying to set rules if a certain variable is put into place, can someone identify wtf I'm missing here?
test.sh:
#!/bin/bash
args=($#)
if [ "$#" = "--cron" ]; then
echo "WORKS!";
else echo "FAILS"
fi
output of ./test.sh:
./test.sh: line 3: [: =: unary operator expected
FAILS
However, when I run ./test.sh --cron, it works, and WORKS is output.
The correct way to do this varies a bit depending on exactly what you're trying to do. If you want to check whether the first argument is --cron, use this:
if [ "$1" = "--cron" ]; then
If you want to check whether the only argument is --cron, use this:
if [ "$*" = "--cron" ]; then
(Note that this is one of very few cases where "$*" is the right way to do something -- it expands to all arguments separated by spaces, but treated as a single word for parsing purposes.)
If you want to check whether any argument is --cron, use this:
cronopt=false
for argument; do
if [ "$argument" = "--cron" ]; then
cronopt=true
break # note: if you are scanning the arguments for other things too, remove this
fi
done
if $cronopt; then
...
BTW, I'm not sure what you're using the args=($#) line for, but if you want to store the arguments in an array the correct way to do it is args=("$#") -- the quotes keep it from doing word splitting, filename expansion, etc before putting the args into the array.
This should work, but only for the first element, of you want more you might have to do a for or while loop to iterate thru the arguments.
#!/bin/bash
args=($1)
if [ $args ] && [ $args = "--cron" ]; then
echo "WORKS!";
else echo "FAILS"
fi
In this case, I believe "$#" is too well quoted.
Try comparing against "$1", or use:
#!/bin/bash
args=($#)
if [ "$*" = "--cron" ]; then
echo "WORKS!";
else
echo "FAILS"
fi

substituting a string in place of variable in shell

I pass a string as an argument to a shell script. and the shell script should tell me if the passed argument is a variable
something like this
if [ ! -z ${$1} ] ; then
echo yes! $1 is a variable and its value is ${$1}
fi
but this gives me bad substitution err..
I definitely know i'm missing something.. help me out!
Eg usage:
$ myscript.sh HOME
yes! HOME is a variable and its value is /home/raj
The syntax for this is:
${!VAR}
Example:
$ function hello() { echo ${!1}; }
$ hello HOME
/home/me
Found it here:
http://www.linuxquestions.org/questions/programming-9/bash-how-to-get-variable-name-from-variable-274718/
All you should do:
if [ ! -z ${!1} ]; then
echo yes $1 is a variable and its value is ${!1}
fi

Resources