Why is this script doing nothing after the for loop? - bash

I have this bash script. It uses cqlsh to wait for a cassandra schema to be set up. The arguments to the script are the cassandra db keyspaces. Essentially it is checking that there is at least 1 entry in the schema_updates table. This table records all database migrations. If there is any entry in this table, it means that the keyspace that table is now available.
The issue is that none of the commands after the for loop are being executed when I use this script as a docker-compose entrypoint. It works fine if I just call it up directly.
I don't think the problem has anything to do with cassandra or the cassandra query. I have tested each line individually, I have run the the whole script on my local, I have gone into the container started up by the docker-compose file to start the script manually and it works exactly as expected in all three cases.
#!/usr/bin/env bash
for keyspace in "$#";
do
KEYSPACEFOUND=1
until [[ $KEYSPACEFOUND = 0 ]];
do
cqlsh -u cassuser -p casspwd cassandra -e "select filename from $keyspace.schema_updates limit 1" 2>/dev/null | grep "(1 rows)" >/dev/null 2>&1
let KEYSPACEFOUND=$?
done
done
echo "All keyspaces are available"
exec ./bin/applicationStartScript

It turns out that one of the arguments I was passing to the script was not a valid keyspace. This meant that the until loop would never terminate and therefore neither would the for loop.

Related

Why is my function only being partially executed when embedded in a case statement?

I have a .conf file that I am calling in my main script, which contains a case statement.
In this file, I have a series of ssh commands that I am combining into a single variable/array/function (I've tried multiple methods) to be executed when the condition is met in my case statement. For context, this is a script to auto-shutdown clients.
~/variables.conf
#!/bin/sh
CLIENT_1="ssh admin#1.1.1.1 shutdown -r now"
CLIENT_2="ssh admin#1.1.1.2 shutdown -r now"
CLIENT_ALL() { $CLIENT_1 ; $CLIENT_2 ; }
#also tried with similar results
#CLIENT_ALL="$CLIENT_1; $CLIENT_2"
#CLIENT_ALL=($CLIENT_1 $CLIENT_2)
To make sure this portion of code is working and the variables are passing, I run a test.sh and execute from CLI.
~/variables.test.sh
#!/bin/sh
. ~/variables.conf
CLIENT_ALL
Great, everything works. My two clients restart successfully - ssh keys stored so no prompt to enter password.
But when this is called from my case statement, things go wrong:
~/script.sh
#!/bin/sh
. ~/variables.conf
case $1 in
trigger1)
logger <message> #this is working fine
printf <message> | msmtp <email> #this is working fine
CLIENT_ALL
;;
*)
logger "Unrecognized command: $1"
;;
esac
What happens when this triggers: it logs, it sends an email but only the first client gets the ssh command to reboot. It passes the first variable $CLIENT_1 and then stops. I've tried a variety of ways to define and package the ssh commands, as well as a variety of ways to call them in the case statement, but always with the same results. I am certain that there is something about case statement rules/logic that I am overlooking that will explain this behavior and a correct way to make this work.
For my use-case, I need to use a case statement. My goal is to have a single command in the case statement so that the main script doesn't have to be modified - only the .conf needs to be updated if clients are added/removed.
Any help would be greatly appreciated.

The 2nd command is not executed before terminating the previous one

I'm very new to bash. I'm running a bash script. It is supposed to start Neo4j and then execute a series of queries located in a file called "cypher.ex1". Here is the code:
#!/bin/bash
./bin/neo4j console
./bin/cypher-shell -u neo4j -p 123456 --file cypher.ex1
In order to use Cypher-shell, we should start the Neo4j service first. So, this line:
./bin/neo4j console
starts the Neo4j, so that cypher-shell can be used using the following line:
./bin/cypher-shell -u neo4j -p 123456 --file cypher.ex1
The problem is that since ./bin/neo4j console starts the Neo4j service, the next command (./bin/cypher-shell -u neo4j -p 123456 --file cypher.ex1) is not executed unless I press the "Ctrl + C". If I press "Ctrl + C", the Neo4j service will be stopped and the following command will not be executed too (I get "connection refused" error). What should I do in order to start the Neo4j service and then run the cypher shell in this bash script?
I tried the solutions given in Run a command in background and another command in frontground in the same line. None of them worked for me. For example, When I execute the code with "(command1 &); command2" (As it was suggested in the proposed topic), my script is executed 2 times automatically. The first time command2 is executed and since the command1 is not executed I get "connection refused" error; The second time command1 is executed and command2 is not executed.
As it it mentioned in first answer in the Q/A you should exec the commands on this way:
#!/bin/bash
./bin/neo4j console &
./bin/cypher-shell -u neo4j -p 123456 --file cypher.ex1
This will run ./bin/neo4j console in background. So you need to take care about this process and stop it in case of need:
PID=$(jobs -l |awk '{print $2}')
kill $PID

Loop trough docker output until I find a String in bash

I am quite new to bash (barely any experience at all) and I need some help with a bash script.
I am using docker-compose to create multiple containers - for this example let's say 2 containers. The 2nd container will execute a bash command, but before that, I need to check that the 1st container is operational and fully configured. Instead of using a sleep command I want to create a bash script that will be located in the 2nd container and once executed do the following:
Execute a command and log the console output in a file
Read that file and check if a String is present. The command that I will execute in the previous step will take a few seconds (5 - 10) seconds to complete and I need to read the file after it has finished executing. I suppose i can add sleep to make sure the command is finished executing or is there a better way to do this?
If the string is not present I want to execute the same command again until I find the String I am looking for
Once I find the string I am looking for I want to exit the loop and execute a different command
I found out how to do this in Java, but if I need to do this in a bash script.
The docker-containers have alpine as an operating system, but I updated the Dockerfile to install bash.
I tried this solution, but it does not work.
#!/bin/bash
[command to be executed] > allout.txt 2>&1
until
tail -n 0 -F /path/to/file | \
while read LINE
do
if echo "$LINE" | grep -q $string
then
echo -e "$string found in the console output"
fi
done
do
echo "String is not present. Executing command again"
sleep 5
[command to be executed] > allout.txt 2>&1
done
echo -e "String is found"
In your docker-compose file make use of depends_on option.
depends_on will take care of startup and shutdown sequence of your multiple containers.
But it does not check whether a container is ready before moving to another container startup. To handle this scenario check this out.
As described in this link,
You can use tools such as wait-for-it, dockerize, or sh-compatible wait-for. These are small wrapper scripts which you can include in your application’s image to poll a given host and port until it’s accepting TCP connections.
OR
Alternatively, write your own wrapper script to perform a more application-specific health check.
In case you don't want to make use of above tools then check this out. Here they use a combination of HEALTHCHECK and service_healthy condition as shown here. For complete example check this.
Just:
while :; do
# 1. Execute a command and log the console output in a file
command > output.log
# TODO: handle errors, etc.
# 2. Read that file and check if a String is present.
if grep -q "searched_string" output.log; then
# Once I find the string I am looking for I want to exit the loop
break;
fi
# 3. If the string is not present I want to execute the same command again until I find the String I am looking for
# add ex. sleep 0.1 for the loop to delay a little bit, not to use 100% cpu
done
# ...and execute a different command
different_command
You can timeout a command with timeout.
Notes:
colon is a utility that returns a zero exit status, much like true, I prefer while : instead of while true, they mean the same.
The code presented should work in any posix shell.

I do not want by Bash script to stop if a Hive command fails

I have a bash script sending a lot of HiveQL commands to hive. The problem is that I do not want it to stop if one of these commands fails. I tried the usual Bash command:
set +e
but it does not work (the script stops running if one of the Hive command fails). Do you know where is the problem ? An option in my hive config or something :-) ?
Thank you !
EDIT: I use the Hiveshell, doing something like this:
#Send my command to hive ...
hive -S -e "\"$MyCommand\""
#... but I want my script continue running if the command fails :-).

Write a report of what the shell would done

In my UNIX shell script I need to insert a parameter to start it. This parameter can assume two valors (test and production). Inside the code I make an insert in an Oracle db. After this insert I have to make a condition that if the parameter is test then write the spool in another file and don't connect the db, else connect the db and make the insert normally. Fundamentally there are two ways; in the test I just want to see what the shell is going to do and the production that it makes the normal insert and his operations. I try this after the insert but I get a error:
if [[ "$choice" = "test" ]];
then
${TMP_PART2DAT} > ${TMP_REPORT}
else
SP_SQLLOGIN="$ORACLE_DB_OWN/$ORACLE_PWD#$ORACLE_SID"
sqlplus -S -L ${SP_SQLLOGIN} #${TMP_PART2SQL}
fi
Any ideas?
Try running your shell script with "bash -x" mode. You would be able to trace the command execution.
Try
cat ${TMP_PART2DAT} > ${TMP_REPORT}
for line 3 of your script.
This will overwrite everything in TMP_REPORT with the contents of TMP_PART2DAT.

Resources