Check if file exists and continue else exit in Bash - bash

I have a script that is one script in a chain of others that sends an email.
At the start of the script I want to check if a file exists and continue only if it exists, otherwise just quit.
Here is the start of my script:
if [ ! -f /scripts/alert ];
then
echo "File not found!" && exit 0
else
continue
fi
However I keep getting a message saying:
line 10: continue: only meaningful in a `for', `while', or `until' loop
Any pointers?

Change it to this:
{
if [ ! -f /scripts/alert ]; then
echo "File not found!"
exit 0
fi
}
A conditional isn't a loop, and there's no place you need to jump to. Execution simply continues after the conditional anyway.
(I also removed the needless &&. Not that it should happen, but just in case the echo fails there's no reason not to exit.)

Your problem is with the continue line which is normally used to skip to the next iteration of a for or while loop.
Therefore just removing the else part of your script should allow it to work.

Yes. Drop the else continue. It's entirely unneeded.

Related

what does "if { set -C; 2>/dev/null >~/test.lock; }" in a bash mean?

I have encountered this in a bash script:
if { set -C; 2>/dev/null >~/test.lock; }; then
echo "Acquired lock"
else
echo "Lock file exists… exiting"
exit 1
fi
It enters on the else flow. I know set -C will not overwrite the files, 2>/dev/null means something as : redirect errors to "void", but then I have >~/test.lock and will mean to redirect something in the lock file, (what exactly, the errors probably). I have test.lock the file in home, created, and empty. Being a if , it must return false in my case.
{ ... ; ... ; } is a compound command. That is bash executes every command in it, and the exit code is the one of the last one.
It is a bit like ( ... ; ... ), except that with ( you execute a subshell (a bit like sh -c "... ; ...") which is less efficient, and, moreover, prevent affecting local variables of your current shell, for example.
So, in short, { set -C; 2>/dev/null >~/test.lock; } means "do set -C, then do 2>/dev/null >~/test.lock and the return (exit code) is the one of that last command".
So if { set -C; 2>/dev/null >~/test.lock; } is "if 2>/dev/null >~/test.lock succeeds in that compound command, that is after set -C".
Now, set -C means that you can't overwrite existing files
And 2>/dev/null > ~/test.lock is an attempt to overwrite test.lock if it exists, or to create it if it doesn't.
So, what you have here, is
If lock file already exist, fail and say "lock file exists, exiting"
If lock file did not exit, create it, and say "lock acquired".
And it does it in one operation.
So it is different than
# Illustration of how NOT to do it. Do not use this code :-)
if [[ -f "test.lock" ]]
then
echo "lock file exists, exiting"
else
2>/dev/null > ~/test.lock
echo "lock file acquired"
fi
because that, clearer but wrong, version does not guarantee that something will have created the lock file between the evaluation of the if condition and the execution of 2>/dev/null > ~/test.lock.
The version you've shown has the advantage that the creation and test of lock is the same thing.
set -C disallows writing to existing files
2>/dev/null suppresses warnings
>~/test.lock attempts to write to a file called test.lock. If the file already exists this returns an error because of set -C. Otherwise it will create a new test.lock file, making the next instance of this script fail on this step.
The purpose of lock files is to ensure that only one instance of a script runs at the same time. When the program is finished it could delete ~/test.lock to let another instance run.

Unsure how to send error code if command within a shell script fails

I recently learned about an if statement that looks at previous command and if failed will send exit code 1 with a message. I can't remember the entire statement but it starts with the below:
if [ $? != "0" ]
How does this statement end? Does it follow every command within a script?
Don't do that. Explicitly referencing $? is almost never necessary. If you want to exit with status 1 when a command fails, you can simply do:
cmd || exit 1
If you want to exit with the same non-zero value returned by the command, you can simply do:
cmd || exit
There are a lot of examples of bad code out there that instead do things like:
cmd
if [ "$?" -ne 0 ]; then echo cmd failed >&2; exit 1; fi
and this is bad practice for many reasons. There's no point in having the shell print a generic message about failure; the command itself ought to have written a detailed error message already, and the vague "cmd failed" is just line noise. Also, you will often see set -e, which basically slaps a || exit on the end of every simple command but has a lot of unintended side effects and edge cases, and its implementation has changed throughout history and different versions of the same shell will handle the edge cases differently so it's really not a good idea to use it.
As to the question "how does this statement end?"; it ends with fi. The general form of if is if CMD; then ...; else ...; fi where CMD is some set of pipelines (eg, you can do if echo foo | grep bar; cmd2 | foo; then ....). If the CMD returns a 0 status the first set of commands (between "then" and "else") is executed. If CMD returns non-zero, the commands between "else" and "fi" are executed. The "else" clause is optional. Don't be fooled by [; it is simply a command. In my opinion, it would be clearer if you used its alternate spelling test, which does not require a final argument of ]. IOW, you could write if test "$?" -ne 0; then ...; fi.

Lockfile into a bash script with parameters

I have to create a bash script that check if there are other same scripts in execution. To do that I have implemented this solution
scriptToVerify="sl_dynamic_procedure.sh_${1}";
LOCKFILE=${SL_ROOT_FOLDER}/work/$scriptToVerify
if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then
sl_log "---------------------------Warning---------------------------"
sl_log "$scriptToVerify already in execution"
exit
fi
trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT
echo $$ > ${LOCKFILE}
I have addedd ${1} because my script has got a parameter.
If I try to execute a script without a parameter (without ${1}) it works correctly. If I try to execute more than once the script with the parameter sometimes works and sometimes not. How can I fix my code?
First, did you want to allow the script to execute even if another copy is running, so long as they have different arguments? Without knowing what the script does and what the argument is I can't know if that's sensible, but in general it looks like you're buying trouble.
Second, using a lockfile is common, but subject to a race condition. Much better to make the creation of the lock and the test for it a single atomic action. This is almost impossible with a file, but is really easy with a directory.
myLock=/tmp/ThisIsMySingleLockDirectoryName
lockMe() { mkdir $myLock 2>&-; }
unlockMe() { rmdir $myLock 2>&-; }
if lockMe
then : do stuff
unlockMe
else echo "Can't get a lock."
exit 1
fi
This is simplistic, as it throws away the stderr, and doesn't test reasons... but you get the idea.
The point is that the creation of the directory returns an error if it already exists.

How can I use an if statement in bash to check if no errors have occurred?

I have a bash script I want to self-destruct on execution. So far it works great but I'd like some final check that if no errors have occurred (any output to stderr), then go ahead and self destruct. Otherwise, I'd like to leave the script in tact. I have the code for everything except the error check. Not sure if I can just output err to a file and check if file is empty. I'm sure it's a simple solution.
How could I do this?
Thanks for any help.
You can try this out. $? contains the return code for the process last executed by command. Moreover standard nix derivatives demarcate 0 as (no error) and 1 - 255 as some kind of errors that happened. Note that this will report errors that do not necessarily have any stderr output.
command
if [ "$?" -ne 0 ]; then
echo "command failed";
# your termination logic here
exit 1;
fi
Assuming that your script returns the value 0 on success, a value from 1 to 255 if an error occur you can use the following command
if /path/to/myscript; then
echo success
else
echo failed
fi
you can also use the following (shorter) command
[[ /path/to/myscript ]] && echo success || echo failed

If Statement With Blank Variable

I can't get this to work correctly. If the wifissid is blank, it needs to display "Wireless: Not Connected". If the wifissid is not blank, it needs to display "Wireless: Connected To $wifissid"
wifissid=Test
if [ $wifissid = "*" ]; then
WirelessOutput=" Wireless: Connected To $wifissid"
else
WirelessOutput=" Wireless: Not Connected"
exit
fi
echo " $WirelessOutput"
Try this. The ! -z checks to see if $wifissid is not (!) empty/null (-z). Or use -n which basically is the same as ! -z. More details on these operators here:
#!/bin/bash
wifissid=Test
# if [ -n "$wifissid" ]; then
if [ ! -z "$wifissid" ]; then
WirelessOutput=" Wireless: Connected To $wifissid"
else
WirelessOutput=" Wireless: Not Connected"
fi
echo " $WirelessOutput"
exit
Also, I didn’t understand why you had an exit in the else statement since that would prevent the echo from ever happening. So I removed that and added it to the bottom of the script.
Additionally, I added #!/bin/bash to the top of the script because that is just something you should get in the habit of doing. It helps prevent issues such as if this script were running as a cron job, the default sh instead of bash would interpret the script & it would fail.
Might seem like small things, but it’s the little things that will drive you nuts if/when things don’t work out as expected.

Resources