Convert for loop to while loop in bash script - bash

I have a for loop as follows:
mapfile -t ipLast < SippIPs.txt
echo " ---- SIPp ---- "
echo "Please give count of SIPps needed to generate calls.."
read -p 'Sipps count starts from: ' start; read -p 'Sipps count ends on: ' end
if [[ -z $start ]] || [[ -z $end ]]; then echo "User pressed ENTER with no input text"; fi
for ((j=$start; j<=$end; j++)); do
sipps=${j[#]}
ipList=(${ipLast[sipps-1]})
if [[ "$end" -eq 0 ]]; then
echo "No way it cannot end on 0"
exit
fi
echo " ---- Launching SIPp $sipps ---- "
sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root#$ipList <<EOF1
pkill -f sipp
screen -S sipp -d -m bash -c 'cd /usr/local/src/sipp-3.3; ulimit -Hn 65535; ulimit -Sn 65535; ./sipp -i $ipList -mi $ipList -sf HA_demo.xml -inf HA_demo.csv 10.171.0.231:5060 -p 5060 -r 1 -rp 1s -l 1 -m 1 -watchdog_minor_threshold 1500 -watchdog_major_threshold 4000 -watchdog_major_maxtriggers 30 -trace_err -aa -d 350s -oocsn ooc_default -t u1 -trace_screen -skip_rlimit && exec bash'
exit
EOF1
done
I want to convert the for loop to while loop such that after giving the count it returns to the loop to ask the user if they want to quit or keep launching SIPp.
My try:
mapfile -t ipLast < SippIPs.txt
read -p 'Sipps count starts from: ' start; read -p 'Sipps count ends on: ' end
j=$start
while (j<=$end); do
sipps=${j[#]}
ipList=(${ipLast[sipps-1]})
if [[ "$end" -eq 0 ]]; then
echo "No way it cannot end on 0"
exit
fi
echo " ---- Launching SIPp $sipps ---- "
sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root#$ipList <<EOF1
pkill -f sipp
screen -S sipp -d -m bash -c 'cd /usr/local/src/sipp-3.3; ulimit -Hn 65535; ulimit -Sn 65535; ./sipp -i $ipList -mi $ipList -sf HA_demo.xml -inf HA_demo.csv 10.171.0.231:5060 -p 5060 -r 1 -rp 1s -l 1 -m 1 -watchdog_minor_threshold 1500 -watchdog_major_threshold 4000 -watchdog_major_maxtriggers 30 -trace_err -aa -d 350s -oocsn ooc_default -t u1 -trace_screen -skip_rlimit && exec bash'
exit
j++
EOF1
done

The immediate problem is that you need double ((...)) for an arithmetic evaluation. The expression (j<=$end) attempts to run the program j in a subshell with input from the file =$end.
Also, executing j++ on the remote host obviously will not update the local variable j even if you fix the syntax. You apparently want something like
j=$start
while ((j<=$end)); do
:
sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root#$ipList <<EOF1
:
EOF1
((j++))
done
The expression sipps=${j[#]} looks quite odd; j is not an array.
Anyway, there is no particular need to switch from a for loop to a while loop here; just break out of the loop if the user indicates that they want to stop looping.
The screen shenanigans look like you are probably Doing It Wrong but without more information about "it" it's hard for us how to suggest any changes. The exec bash is dubious; what should this code actually accomplish?
exit is redundant at the end of a script; the shell will always exit when it finishes executing the script. Perhaps review Pass commands as input to another command (su, ssh, sh, etc)
As always, you will want to avoid using read -p to receive parameters; a much superior design is to have the caller specify the start and end of the range to scan as command-line arguments. Then start will be $1 and end will be $2 (assuming you have no other command-line processing).

So this is what I was looking for:
while :
mapfile -t ipLast < SippIPs.txt
read -p 'Sipps count starts from: ' start; read -p 'Sipps count ends on: ' end
if [[ -z $start ]] || [[ -z $end ]]; then echo "User pressed ENTER with no input text"; fi
echo " ---- SIPp ---- "
echo "Please give count of SIPps needed to generate calls.."
do
for ((j=$start; j<=$end; j++)); do
sipps=${j[#]}
ipList=(${ipLast[sipps-1]})
if [[ "$end" -eq 0 ]]; then
echo "No way it cannot end on 0"
exit
fi
echo " ---- Launching SIPp $sipps ---- "
sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root#$ipList <<EOF1
pkill -f sipp
screen -S sipp -d -m bash -c 'cd /usr/local/src/sipp-3.3; ulimit -Hn 65535; ulimit -Sn 65535; ./sipp -i $ipList -mi $ipList -sf HA_demo.xml -inf HA_demo.csv 10.171.0.231:5060 -p 5060 -r 1 -rp 1s -l 1 -m 1 -watchdog_minor_threshold 1500 -watchdog_major_threshold 4000 -watchdog_major_maxtriggers 30 -trace_err -aa -d 350s -oocsn ooc_default -t u1 -trace_screen -skip_rlimit && exec bash'
exit
EOF1
done
read -p 'Do you want to perform failover..(y/n)' cc
if [[ $cc == "y" || $cc == "y" ]]; then
exit
fi
done
Thanks for the help!

Related

while loop read data from two colums

In my limited experience with while loop in shell script, i have a requirement to check the remote hosts connection in new public key.
cat JOBID_LIST.txt
HLC00101 abc#gbl67543.cloud.uk.hlc
HLC01110 absit#DEU010A.cloud.uk.hlc
HLC02568 abftp#GTB19494.systems.uk.hlc
HLC02590 wbsftp#batch.mose.dev.cloud.hlc
HLC02590 cmul1u11#batch.mose.dev.cloud.hlc
HLC02648 dmlfeat#lmd-fileserver-uat.systems.uk.hlc
HLC02648 dmsftp#lmd-fileserver-uat.systems.uk.hlc
#!/bin/bash
cat JOBID_LIST.txt | while read -r JOBID SFTPHOST
do
if [[ ${JOBID} != "HLC02648" ]]; then
ssh -q -o BatchMode=yes -o StrictHostkeyChecking=no ConnectTimeout=5 "$SFTPHOST" -i xxxx.pub 'exit 0'
if [[ $? == 0 ] ; then
echo "Connect to $SFTPHOST in $JOBID in new pubkey successfully."
else
echo "Failed to connect to $SFTPHOST in $JOBID in new pubkey "
fi
else
echo "Verify Completely"
exit 2.
fi
done
For some stange reason, the ssh command breaks out of the while-loop, therefore the third JOBID till the end are ignored.
How could i make it check till the end of file?
Apprciated for your advice.
Maybe adding a </dev/null before the ssh calls will help?
#!/bin/bash
while read -r JOBID SFTPHOST; do
if [ "$JOBID" != "HLC02648" ]; then
</dev/null \
ssh -q -o BatchMode=yes -o StrictHostkeyChecking=no \
ConnectTimeout=5 "$SFTPHOST" -i xxxx.pub 'exit 0'
if [ $? = 0 ]; then
echo "Connect to $SFTPHOST in $JOBID in new pubkey successfully."
else
echo "Failed to connect to $SFTPHOST in $JOBID in new pubkey "
fi
else
echo "Verify Completely"
exit 2
fi
done < JOBID_LIST.txt

Command not found in elif comparison > bash

For some reason commands are not running after the first if statement.
"/usr/local//backup.sh: sleep: not found" for example..
The first if statement goes like:
if [ "$command" == "start -c" ]; then
echo -e "${ORANGE}Starting website backup...${E}"
sleep 1
DT=`date +%Y-%m-%d`
echo -e "${ORANGE}Started backup at $DT ${E}"
sleep 1
tar -zcvf web-$DT.tar.gz /usr/local/www/nginx
echo -e "${ORANGE}Compatced files, moving to backup directory${E}"
sleep 1
mv web-$DT.tar.gz $PATH/web-$DT.tar.gz
echo -e "${CYAN}Moved to backups ($PATH/web-$DT.tar.gz)\nDo you want to upload to ftp?${E}\n${CYAN} 'y' or 'n'?${E}"
read answer
if [ "$answer" == "y" ]; then
echo -e "${ORANGE}Uploading to ftp server...${E}"
sleep 1
if ftp -in -u ftp://$USER:$PASS#$HOST/Backups/f $PATH/web-$DT.tar.gz; then
echo -e "${GREEN}Uploaded! Bye!${E}"
else
echo -e "${ORANGE}Couldn't upload with ftp command, trying with curl...${E}"
sleep 1
curl -T "$PATH/web-$DT.tar.gz" -u $USER:$PASS ftp://$HOST/Backups/f/
echo -e "${GREEN}Uploaded! Bye!${E}"
fi
else
echo -e "${GREEN}Bye!${E}"
fi
Everything works fine inside this statement, however, after the elif compassion it just doesn't.
Here's the problematic code:
elif [ "$command" == "start -d" ]; then
echo -e "${ORANGE}Starting database backup...${E}"
sleep 1
DT=`date +%Y-%m-%d`
echo -e "${ORANGE}Started backup at $DT ${E}"
sleep 1
umask 177
echo -e "${ORANGE}Dumping database 'account'\n${E}"
mysqldump --user=$DBUSER --password=$DBPASS --host=$HOST account > $PATH/account-$DT.sql
sleep 1
echo -e "${ORANGE}Dumping database 'game'\n${E}"
mysqldump --user=$DBUSER --password=$DBPASS --host=$HOST game > $PATH/game-$DT.sql
sleep 1
echo -e "${ORANGE}Dumping database 'forum'\n${E}"
mysqldump --user=$DBUSER --password=$DBPASS --host=$HOST forum > $PATH/forum-$DT.sql
sleep 1
echo -e "${CYAN}Moved to backups ($PATH/<database-date>.sql)\nDo you want to upload to ftp?${E}\n${CYAN} 'y' or 'n'?${E}"
read answer
if [ "$answer" == "y" ]; then
echo -e "${ORANGE}Uploading to ftp server...${E}"
sleep 1
curl -T "$PATH/account-$DT.sql" -u $USER:$PASS ftp://$HOST/Backups/f/Databases/
curl -T "$PATH/game-$DT.sql" -u $USER:$PASS ftp://$HOST/Backups/f/Databases/
curl -T "$PATH/forum-$DT.sql" -u $USER:$PASS ftp://$HOST/Backups/f/Databases/
sleep 1
echo -e "${GREEN}Uploaded! Bye!${E}"
else
echo -e "${GREEN}Bye!${E}"
fi
and then I just ended it..
else
echo -e "${RED}Sorry! Not found${E}"
fi
As you can see there's spaces in the if statements and all of that, so what's wrong with this??
I've the #!/bin/bash up top as well, all the variables exist too.
You seem to have overwritten the value of the PATH variable at some point in your code. The shell needs that variable in order to know where to find programs like sleep (Hence the "not found" error). Name your path variable something else.

How do I catch an error from a Bash sftp connection?

How do I try an SFTP connection with a heredoc 3 times and catch an error? How do I restructure this to be proper? Error is being thrown on the first semicolon on the last line right before do
count=0; until sftp -o StrictHostKeyChecking=no -i key.pem server#server.com <<END
cd subfolder
END
; do ((count++)); [[ $count -eq 3 ]] && echo 'error' && break && exit 64; done;
Try:
until echo "cd subfolder" | sftp -o StrictHostKeyChecking=no -i key.pem server#server.com
Or take a look at sftp's option -b.

How do I place a heredoc at the end of a Bash sftp connection attempt?

Trying to get this snippet working properly. I want to attempt an SFTP connection 3 times before breaking and exiting the shell. The catch is that there's a heredoc and sftp is not taking the heredoc as input when the connection is successful; the shell becomes interactive which I don't want.
count=0; until sftp -o StrictHostKeyChecking=no -i $key $server ; do ((count++)); [[ $count -eq 3 ]] && echo $count && break && exit 64; done; <<END
get docs/*
quit
END
I wouldn't write this this way at all (consider lftp rather than sftp), but:
count=0
until sftp -o StrictHostKeyChecking=no -i "$key" "$server" <<END
get docs/*
quit
END
do
if (( count++ >= 3 )); then echo "$count failures" >&2; exit 64; fi
END
Just make sure commands.txt contains your commands, one per line.
count=0
until sftp -o StrictHostKeyChecking=no -i "$key" -b commands.txt "$server"
do
((count++))
[[ $count -eq 3 ]] && echo $count && exit 64
done

Bash remote files system directory test

the more I learn bash the more questions I have, and the more I understand why very few people do bash. Easy is something else, but I like it.
I have managed to figure out how to test directories and there writablity, but have a problem the minute I try to do this with a remote server over ssh. The first instance testing the /tmp directory works fine, but when the second part is called, I get line 0: [: missing]'`
Now if I replace the \" with a single quote, it works, but I thought that single quotes turn of variable referencing ?? Can someone explain this to me please ? Assuming that the tmp directory does exist and is writable, here the script so far
#!/bin/bash
SshHost="hostname"
SshRsa="~/.ssh/id_rsa"
SshUser="user"
SshPort="22"
Base="/tmp"
Sub="one space/another space"
BaseBashExist="bash -c \"[ -d \"$Base\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseBashExist} )
echo -n $Base
if [ $? -eq 0 ]
then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
BaseBashPerm="bash -c \"[ -w \"$Base\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseBashPerm} )
if [ $? -eq 0 ]
then
echo "...writeable"
else
echo "...not writeable"
fi
BaseAndSub="$Base/$Sub"
BaseAndSubBashExist="bash -c \"[ -d \"$BaseAndSub\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseAndSubExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseAndSubBashExist} )
echo -n $BaseAndSub
if [ $? -eq 0 ]
then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
BaseAndSubBashPerm="bash -c \"[ -w \"$BaseAndSub\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseAndSubPerm=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseAndSubBashPerm} )
if [ $? -eq 0 ]
then
echo -n "...writeable"
else
echo "...not writeable"
fi
exit 0
The first thing you should do is refactor your code with simplicity in mind, then the quoting error will go away as well. Try:
if ssh [flags] test -w "'$file'"; then
Encapsulate your SSH flags in a ssh config to facilitate re-use, and your script will shorten dramatically.
You are fine with single quotes in this context; by the time the script is seen by the remote bash, your local bash has already substituted in the variables you want to substitute.
However, your script is a total mess. You should put the repetitive code in functions if you cannot drastically simplify it.
#!/bin/bash
remote () {
# most of the parameters here are at their default values;
# why do you feel you need to specify them?
#ssh -l "user" -i ~/.ssh/id_rsa -p 22 hostname "$#"
ssh hostname "$#"
# —---------^
# if you really actually need to wrap the remote
# commands in bash -c "..." then add that here
}
exists_and_writable () {
echo -n "$1"
if remote test -d "$1"; then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
if remote test -w "$1"; then
echo "...writeable"
else
echo "...not writeable"
fi
}
Base="/tmp"
# Note the need for additional quoting here
Sub="one\\ space/another\\ space"
exists_and_writable "$Base"
BaseAndSub="$Base/$Sub"
exist_and_writable "$BaseAndSub"
exit 0
ssh -qnx "useraccount#hostname"
"test -f ${file absolute path} ||
echo ${file absolute path} no such file or directory"

Resources