Exiting bash script without terminating ssh connection - linux

I'm pretty new to bash scripting and I'm attempting to write a script that does some basic operations.
I want to check certain conditions and if they are met, terminate the script. So for example, I want to check whether the zip of files was successful:
echo "Zipping file..."
for file in $fileList;
do
echo $file | zip -v $archive -#
if [[ $? != 0 ]];
then
echo "Error creating zip"
exit 1
fi
done
What happens though is that the exit 1 signal causes the ssh connection to terminate as well:
Zipping file...
Command 'zip' not found, but can be installed with:
sudo apt install zip
Error creating zip
Connection to 3.137.7.52 closed.
What's the correct way to terminate a script without also disconnecting from the server?

If you wrap it all in a script with shebang #!/bin/bash than exit 1 will be fine
but if you run this as a oneliner directly in console then this exit 1 means exit from console, and that would break ssh connection obvy
cat > ziper.sh << \EOF
#!/bin/bash
echo "Zipping file..."
for file in $fileList;
do
echo $file | zip -v $archive -#
if [[ $? != 0 ]];
then
echo "Error creating zip"
exit 1
fi
done
EOF
./ziper.sh
In oneliner use break

Related

How to avoid the command execution when appending lines to a file

I'm trying to save the content of script into a file using command line, but I noticed that when the tee command detects linux commands such as $(/usr/bin/id -u), it execute the commands rather than saving the lines as it is. How to avoid the execution of the commands and saving the text exactly as I entered it?
$tee -a test.sh << EOF
if [[ $(/usr/bin/id -u) -ne 0 ]]; then
echo You are not running as the root user.
exit 1;
fi;
EOF
if [[ 502 -ne 0 ]]; then
echo You are not running as the root user.
exit 1;
fi;
Complete script contains many more lines, but I chose /usr/bin/id -u as a sample.
This has nothing to do with tee or appending to the file, it's how here-documents work. Normally variable expansion and command substitution is done in them.
Put single quotes around the EOF marker. This will treat the here-document like a single-quoted string, so that $ will not expand variables or execute command substitutions.
tee -a test.sh << 'EOF'
if [[ $(/usr/bin/id -u) -ne 0 ]]; then
echo You are not running as the root user.
exit 1;
fi;
EOF
if [[ $(/usr/bin/id -u) -ne 0 ]]; then
echo You are not running as the root user.
exit 1;
fi;

SSH Remote command exit code

I know there are lots of discussions about it but i need you help with ssh remote command exit codes. I have that code:
(scan is a script which scans for viruses in the given file)
for i in $FILES
do
RET_CODE=$(ssh $SSH_OPT $HOST "scan $i; echo $?")
if [ $? -eq 0 ]; then
SOME_CODE
The scan works and it returns either 0 or (1 for errors) or 2 if a virus is found. But somehow my return code is always 0. Even, if i scan a virus.
Here is set -x output:
++ ssh -i /home/USER/.ssh/id host 'scan Downloads/eicar.com; echo 0'
+ RET_CODE='File Downloads/eicar.com: VIRUS: Virus found.
code of the Eicar-Test-Signature virus
0'
Here is the Output if i run those commands on the "remote" machine without ssh:
[user#ws ~]$ scan eicar.com; echo $?
File eicar.com: VIRUS: Virus found.
code of the Eicar-Test-Signature virus
2
I just want to have the return Code, i dont need all the other output of scan.
!UPDATE!
It seems like, echo is the problem.
The reason your ssh is always returning 0 is because the final echo command is always succeeding! If you want to get the return code from scan, either remove the echo or assign it to a variable and use exit. On my system:
$ ssh host 'false'
$ echo $?
1
$ ssh host 'false; echo $?'
1
$ echo $?
0
$ ssh host 'false; ret=$?; echo $ret; exit $ret'
1
$ echo $?
1
ssh returns the exit status of the entire pipeline that it runs - in this case, that's the exit status of echo $?.
What you want to do is simply use the ssh result directly (since you say that you don't want any of the output):
for i in $FILES
do
if ssh $SSH_OPT $HOST "scan $i >/dev/lull 2>&1"
then
SOME_CODE
If you really feel you must print the return code, that you can do that without affecting the overall result by using an EXIT trap:
for i in $FILES
do
if ssh $SSH_OPT $HOST "trap 'echo \$?' EXIT; scan $i >/dev/lull 2>&1"
then
SOME_CODE
Demo:
$ ssh $host "trap 'echo \$?' EXIT; true"; echo $?
0
0
$ ssh $host "trap 'echo \$?' EXIT; false"; echo $?
1
1
BTW, I recommend you avoid uppercase variable names in your scripts - those are normally used for environment variables that change the behaviour of programs.

exit from STDIN from bash script when the user want to close it

I'm automating the file creation from a bash script. I generated a file rc_notes.txt which has commit messages from two tags and want to re-write that in a new file as rc_device.txt.
I want the user to write the customer release notes and exit from the BASH STDIN that I prompt in the terminal.
The problem in my script is I'm not able to trap the close of file.
Wondering how to do. I don't want to trap the close signal. I want to enter magic string example: Done or some string that triggers the closure of STDIN, that exit from the script gracefully.
My script:
#/bin/bash
set -e
echo "Creating the release candiate text"
rc_file=rc_updater_notes.txt
echo "=========Reading the released commit message file=========="
cat $rc_file
echo "=========End of the commit message file=========="
echo "Now write the release notes"
#exec < /dev/tty
while read line
do
echo "$line"
done < "${1:-/dev/stdin}" > rc_file.txt
It does create the file but I need to exit manually by entering ctrl+D or ctrl+z. I don't want to do that. Any suggestions?
To break the loop when "Done" is entered
while read line
do
if [[ $line = Done ]]; then
break;
fi
echo "$line"
done < "${1:-/dev/stdin}" > rc_file.txt
or
while read line && [[ $line != Done ]]
do
echo "$line"
done < "${1:-/dev/stdin}" > rc_file.txt

How to check if script is running or not from script itself?

Having below sample script sample.sh
#!/bin/bash
if ps aux | grep -o "sample.sh" >/dev/null
then
echo "Already script running"
exit 0
fi
echo "start script"
while true
do
echo "script running"
sleep 5
done
In above script i want to check if this script previously running or not if running then not run it again.
problem is check condition always become true (because to check the condition require to run script) and it always show me "Already script running" message.
Any idea how to solve it?
You need a proper lock. I'd do using flock like this:
exec 201> /tmp/lock.$(basename $0).file
if ! flock -n 201 ; then
echo "another instance of $0 is running";
exit 1
fi
# cmds
exec 201>&-
rm -rf /tmp/lock.$(basename $0).file
This basically creates lock for script using a temporary file. The temporary file has particular significance other than it's used to tell whether your script has acquired a lock.
When there's an instance of this program running, the next run of the same program can't run as the lock will prevent it.
For me will be safer to use a lock file , create it when process start and delete after completion.
Let the script record its own PID in a file. Before doing so, it first checks if that file currently contains an active PID, in which case it exits.
pid=$(< ${PID_FILE:?} || exit
kill -0 $PID && exit
The next exercise is to prevent race conditions when writing the file.
Try this, it gives number of sample.sh run by the user
ps -aux | awk -v app='sample.sh' '$0 ~ app { print $1 }' |grep $USERNAME|wc -l
Wtite a tmp file to the /tmp directory.
have your script check to see if the file exists, if it does then don't run.
#!/bin/sh
# our tmpfile
tmpfile="/tmp/mytmpfile"
# check to see if it exists.
# if it does then exit script
if [[ -f ${tmpfile} ]]; then
echo script already running.
exit
fi
# it doesn't exist at this point so lets make one
touch ${tmpfile}
# do whatever now.
# end of script
rm ${tmpfile}

Error trapping scp exit code not working

I have
# Transfer today's CMS backup to a remote backup server
scp -P 55 -r $localdumpdirectory/dirdump-cms-`date +%Y%m%d`.tar.gz root#someserver:/$remotedumpdirectory/ >/dev/null 2>&1
status=${$}
if [[ ${status} != 0 ]]
then
echo "Failed to secure copy directory, with code: ${status}"
exit 1
fi;
Everything is working except that even though the SCP succeeds, I get:
Failed to secure copy directory, with code: 27348
Ideas?
Exit code is $?, not $$. $$ is process ID.
status=${$}
should be
status=$? # or ${?} if you really insist.
If this is bash, see the section "Special Parameters" in the documentation.
Do you want
status=$?
That will give you the status of the last command.
status=$$
This is giving you the last PID
http://tldp.org/LDP/abs/html/internalvariables.html#PROCCID
BTW, you can shorten what you have to:
if scp -P 55 -r $localdumpdirectory/dirdump-cms-`date +%Y%m%d`.tar.gz root#someserver:/$remotedumpdirectory/ >/dev/null 2>&1
then
echo "Failed to secure copy directory, with code: ${status}"
exit 1
fi

Resources