I have below shell script where i want to create another parameter and instead of in in the line $JAVA_BIN $JAVA_OPTS --workflow test_method --config config/dbimport.$1.properties in i want to provide that parameter.
#!/bin/bash
if [[ $# -lt 1 ]]; then
echo "usage: test_method_full.sh <env> ; whereas env is one of dev|simu|prod"
exit 1
fi
# ******************** Check arguments **********
if [[ $1 != "dev" && $1 != "simu" && $1 != "prod" ]]; then
echo "env parameter has to be dev, simu or prod. Found ${1}"
exit 3
fi
# ***************** Java-Environment **************
# use given JAVA_HOME or openjava-1.8 if available
if [[ -z ${JAVA_HOME} ]]; then
# JAVA_HOME does not exist
if [[ -d /opt/java-1.8 ]]; then
JAVA_HOME=/opt/java-1.8
else
echo "JAVA_HOME could not be determined!"
exit 5
fi
fi
# set the Java binary based on JAVA_HOME
JAVA_BIN=${JAVA_HOME}/bin/java
$JAVA_BIN $JAVA_OPTS -classpath "/opt/Software/lib/*:/opt/Software/test_method/lib/*" --workflow test_method --config config/dbimport.$1.properties in
While running the script it should run like below:
test_method_full.sh simu /opt/Software/in
I dont want to hardcode /opt/Software/in/ in my shell script and make it changeable while runnig the script
You can choose to pass it as optional parameter (i.e. "${2:-/opt/Software/in/}"), which can override the default, but uses the default, if you don't pass a parameter, or use an environment variable for it, say: "${JAVA_ARG:-/opt/Software/in/}", in a similar way you are already doing it for JAVA_OPTS.
Related
I have an if statement which is used many times in my script:
if [[ $? -ne 0 ]]; then
echo [$JOB_NAME] failed.
exit 1
fi
is it possible to define a variable and assign this statement to it, and then call it each time I need ti?
Example of use:
echo [$JOB_NAME] extracting manifests...
unzip -o ZIP_FILE "*.yml"
# Push the app to CF
cf push -f $MANIFEST_FILE -p ZIP_FILE $NEW_APP
if [[ $? -ne 0 ]]; then
echo [$JOB_NAME] failed.
exit 1
fi
As mentioned in the comments, this should be a function, which could be written like this:
ensure_success () {
if [[ $# -eq 0 ]]; then
echo "no command passed to ensure_success."
elif ! "$#"; then
echo "[$JOB_NAME] failed."
exit 1
fi
}
"$#" expands to the full list of arguments passed to the function. I added a check based on Inian's suggestion in the comments, to ensure that at least one argument is passed to the function.
This combines running the command and checking the error code, so you can use it like:
ensure_success command arg1 arg2 arg3
So, based on the example in your question it would be:
ensure_success cf push -f "$MANIFEST_FILE" -p ZIP_FILE "$NEW_APP"
The quotes are free.
I'm not sure where $JOB_NAME is defined but presumably it is a global.
I'm retrieving a host-name from VMware Tools and trying to evaluate if two variables are present in my script:
selection=2
# Check if hostname is present in guestinfo
hostname="$(vmtoolsd --cmd "info-get guestinfo.startup.hostname")"
if [[ "$selection" = 2 && ! -z ${hostname+x} ]]
then
echo "Args present."
else
echo "Args NOT present."
fi
Regardless of whether hostname value is set in the VMX config file, the if statement returns "Args present."
I believe this is because the vmtoolsd command is executed, meaning the 'hostname' variable is not null. Unsure how to fix.
What is wrong?
First, clean up your tests-- don't use ! -z, when you have a -n.
In addition, if you are adding x to hostname, it will always be true (it will always return x by itself). Bash never needs the +x, get rid of it.
if [[ "$selection" = 2 && -n $hostname ]]; then
echo "Args present."
else
echo "Args NOT present."
fi
I have a heredoc that needs to call existing variables from the main script, and set its own variables to use later. Something like this:
count=0
ssh $other_host <<ENDSSH
if [[ "${count}" == "0" ]]; then
output="string1"
else
output="string2"
fi
echo output
ENDSSH
That doesn't work because 'output' doesn't get set to anything.
I tried using the solution from this question:
count=0
ssh $other_host << \ENDSSH
if [[ "${count}" == "0" ]]; then
output="string1"
else
output="string2"
fi
echo output
ENDSSH
It didn't work either. $output got set to "string2" because $count wasn't expanded.
How can I use a heredoc that expands variables from the parent script, and sets its own variables?
You can use:
count=0
ssh -t -t "$other_host" << ENDSSH
if [[ "${count}" == "0" ]]; then
output="string1"
else
output="string2"
fi
echo "\$output"
exit
ENDSSH
We use \$output so that it is expanded on remote host not locally.
It is better not to use stdin (such as by using here-docs) to pass commands to ssh.
If you use a command-line argument to pass your shell commands instead, you can better separate what is expanded locally and what will be executed remotely:
# Use a *literal* here-doc to read the script into a *variable*.
# Note how the script references parameter $1 instead of
# local variable $count.
read -d '' -r script <<'EOF'
[[ $1 == '0' ]] && output='zero' || output='nonzero'
echo "$output"
EOF
# The variable whose value to pass as a parameter.
# With value 0, the script will echo 'zero', otherwise 'nonzero'.
count=0
# Use `set -- '$<local-var>'...;` to pass the local variables as
# positional parameters, followed by the script code.
ssh localhost "set -- '$count'; $script"
You can escape the variables as #anubhava said, or, if you get too much variables for the escaping, you can do it in two steps:
# prepare the part which should not be expanded
# note the quoted 'EOF'
read -r -d '' commands <<'EOF'
if [[ "$count" == "0" ]]; then
echo "$count - $HOME"
else
echo "$count - $PATH"
fi
EOF
localcount=1
#use the unquoted ENDSSH
ssh me#nox.local <<ENDSSH
count=$localcount # count=1
#here will be inserted the above prepared commands
$commands
ENDSSH
will print something like:
1 - /usr/bin:/bin:/usr/sbin:/sbin
I'm wondering, if it is possible to write a shell script with options using getopt or getopts that won't allow to combine multiple options?
E.g., my script could be ran in two possible modes - long or short and with alpha or beta options, that's why I would like to use ./script.sh -l -a , ./script.sh -l -b or ./script.sh -s -a , ./script.sh -s -b, but it shouldn't be possible to run both options -l and -s or -a and -b at the same time.
I know it can be made a lot easier, because I can make option -a which will run long version alpha, option -b which will run long version beta, option -c which will run short version alpha, and option -d which will run short version beta, but I want to use two options, just understand if such way is possible.
Please find below code with "options" to choose using simple read, what I want to convert into getopt(s)
#!/bin/bash
echo "Please insert the text:"
read text
echo
echo "You entered $text"
echo "Choose version:
1) Long
2) Short
3) Quit
-> "
read option
# OPTION 1
if [ "$option" == "1" ]; then
echo "Choose method:
1) alpha
2) beta"
read method
# METHOD 1
if [ "$method" == "1" ]; then
longalpha
fi
# METHOD 2
if [ "$method" == "2" ]; then
longbeta
fi
fi
#OPTION 2
if [ "$option" == "2" ]; then
echo "Choose method:
1) alpha
2) beta"
read method2
# METHOD 1
if [ "$method2" == "1" ]; then
shortalpha
fi
# METHOD 2
if [ "$method2" == "2" ]; then
shortbeta
fi
fi
if [ "$option" == "3" ]; then
echo "Good Bye!"
fi
You should parse all the options first, and set variables indicating which have been passed and which have not.
Then, before actually executing anything, test if -l and -s are both present or both missing, and if so exit with the appropriate error message.
You can perform a similar check with -a and -b
Once you know you have everything that is needed, but nothing more, then you can have your script perform the appropriate operation.
When running getopts you can check if an exclusive flag has already been set by having unset variables representing that flag.
Let's say you have two variables that will determine what you want to do, and they start unset:
unset vers meth
And you also have a lookup table for flags to actions, like:
declare -A flags=([l]=long [s]=short [a]=alpha [b]=beta)
Then you can run getopts like:
while getopts "lsab" opt; do
case $opt in
(l|s) [[ $vers ]] && fail # we already set $vers
vers=${flags[$opt]} ;;
(a|b) [[ $meth ]] && fail # we already set $meth
meth=${flags[$opt]} ;;
('?') fail ;; # we got some unknown option
esac
done
The only thing that remains is to check that we did get something for $vers and $meth:
[[ $vers && meth ]] || fail
And then execute your task:
$vers$method
The way you handle this last part depends on the specifics of your code, but since you are calling shortalpha, etc., this way fits well. If you are instead calling some external code, this might be like prog --$vers --$meth, etc.
I am currently learning bash programming and dont really understand why the passing argument for me is not working.
i have a script like this
#!/bin/bash
# the following environment variables must be set before running this script
# SIM_DIR name of directory containing armsim
# TEST_DIR name of the directory containing this script and the expected outputs
# LOG_DIR name of the directory that your output is written to by the run_test2 script
# ARMSIM_VERBOSE set to "-v" for verbose logging or leave unset
# First check the environment variables are set
giveup=0
if [[ ${#SIM_DIR} -eq 0 || ${#TEST_DIR} -eq 0 || ${#LOG_DIR} -eq 0 ]] ; then
echo One or more of the following environment variables must be set:
echo SIM_DIR, TEST_DIR, LOG_DIR
giveup=1
fi
# Now check the verbose flag
if [[ ${#ARMSIM_VERBOSE} != 0 && "x${ARMSIM_VERBOSE}" != "x-v" ]] ; then
echo ARMSIM_VERBOSE must be unset, empty or set to -v
giveup=1
fi
# Stop if environment is not set up
if [ ${giveup} -eq 1 ] ; then
exit 0
fi
cd ${TEST_DIR}
for i in test2-*.sh; do
echo "**** Running test ${i%.sh} *****"
./$i > ${LOG_DIR}/${i%.sh}.log
done
When I run the .sh file and pass in 3 example argument as below:-
$ ./run_test2 SIM_DIR TEST_DIR LOG_DIR
It still show: One or more of the following environment variables must be set:
SIM_DIR, TEST_DIR, LOG_DIR
Can anyone guide me on this? Thank you.
That's not how it's intended to work. The environment variables must be set beforehand either in the script or in the terminal like
export SIM_DIR=/home/someone/simulations
export TEST_DIR=/home/someone/tests
export LOG_DIR=/home/someone/logs
./run_test2
If you use these variables frequently, you might want to export them in ~/.bashrc. The syntax is identical to the exports in the above example.
Environment variables aren't really arguments in the sense I understand from your question/example. It sounds to me like you want to give arguments to a function/script, if you do that you can find your arguments in $1-9 (I think bash supports even more, unsure), the number of arguments are stored in $#
Example function that expects two arguments:
my_func() {
if [ $# -ne 2 ]; then
printf "You need to give 2 arguments\n"
return
fi
printf "Your first argument: %s\n" "$1"
printf "Your second argument: $s\n" "$2"
}
# Call the functionl like this
my_func arg1 arg2