Script which removes itself after the first execution - linux

I want to develop a shell script that remove itself at the end of the execution.
How can this be done?

Simply [[ -f "$0" ]] && rm "$0". Might want to protect from write failures and otherwise.

Related

How do I write a one-liner cd command for the following case?

I have 2 directories
testing_dir
testing_dir_win
So I need to cd to testing_dir. But here is the case
the directories can be
testing_dir or testing_dir-2.1.0
testing_dir_win or testing_dir_win-1.3.0
and my script should only take testing_dir or testing_dir-2.1.0 (based on which is available)
I have the long way of writing it:
str=`ls folder_name|grep ^testing_dir`
arr=(${str//" "/ })
ret=""
for i in "${arr[#]}"
do
if [[ $i != *"testing_dir_win"* ]] ; then
ret=$i
fi
done
but is there a one-liner for this problem? something like cd testing_dir[\-]?(This doesn't work by the way).
If your script contains
shopt -s extglob
you can use:
cd testing_dir?(-[[:digit:]]*) || exit
...if you have a guarantee that only one match will exist.
Without that guarantee, you can directly set
arr=( testing_dir?(-[[:digit:]]*) )
cd "${arr[0]}" || exit
use command with grep filters:
cd `ls | grep -w testing_dir`
this command will match the testing_dir directory without worrying for version.
P.S in case of many versions it will go inside the earliest version so add "head -1, tail -1" according to your usecase

have arbitrary executable inherit errexit, if script is bash

I have a folder of executable scripts, and some of them have Python shebangs, while others have Bash shebangs, etc. We have a cron job that runs this folder of scripts nightly, and the hope is that any error in any script will exit the job.
The scripts are run with something like: for FILE in $FILES; do ./$FILE; done
The scripts are provided by various people, and while the Python scripts always exit after an error, sometimes developers forget to add set -e in their Bash scripts.
I could have the for-loop use bash -e, but then I need to detect whether the current script is Bash/Python/etc.
I could set -e from the parent script, and then source scripts, but I still need to know which language each script is in, and I'd prefer them to run as subshells so script contributors don't have to worry about messing up the parent.
greping the shebangs is a short tweak, but knowing the flexibility of Bash, I'd be surprised if there weren't a way to "export" an option that affected all child scripts, in the same way you can export a variable. And, there have been many cases in general where I've forgotten "set -e", so it could be nice to know more options for fool-proofing things.
I see some options for inheriting -e for subshells involved in command substitution, but not in general.
Disclaimer: Never, ever do this! It's a huge disservice to everyone involved. You will introduce failures both in scripts with meticulous error handling, and in scripts without it.
Anyways, no one likes being told "don't do that" on StackOverflow, so my suggestion would be to identify scripts and invoke them with their shebang string plus -e:
for f in ./*
do
# Determine if the script is a shell script
if [[ $(file -i "$f") == *text/x-shellscript* ]]
then
# Read the first line
read -r shebang < "$f"
# The script shouldn't have been identified as a shell script without
# a shebang, but check anyways
if [[ $shebang != "#!"* ]]
then
echo "No idea what $f is" >&2
continue
fi
# Strip off the #! and run it with -e and the file
shebang=${shebang#??}
$shebang -e "$f"
else
# It's some other kind of executable, just run it directly
"$f"
fi
done
Here's a script with correct error handling that now stops working:
#!/bin/bash
my-service start
ret=$?
if [ $ret -eq 127 ]
then
# Use legacy invocation instead
start-my-service
ret=$?
fi
exit "$ret"
Here's a script without error handling that now stops working:
#!/bin/sh
err=$(grep "ERROR" file.log)
if [ -z "$err" ]
then
echo "Run was successful"
exit 0
else
echo "Run failed: $err"
exit 1
fi

Run bash script with defaults to piped commands set within the script

Two questions about the same thing I think...
Question one:
Is it possible to have a bash script run with default parameters/options? ...in the sense if someone were to run the script:
./somescript.sh
it would actually run with ./somescript.sh | tee /tmp/build.txt?
Question two:
Would it also possible to prepend the script with defaults? For example, if you were to run the script ./somescript.sh
it would actually run
script -q -c "./somescript.sh" /tmp/build.txt | aha > /tmp/build.html?
Any help or guidance is very much appreciated.
You need a wrapper script that handles all such scenario for you.
For example, your wrapper script can take parameters that helps you decide.
./wrapper_script.sh --input /tmp/build.txt --ouput /tmp/build.html
By default, --input and --output can be set to values you want when they are empty.
You can use the builtin $# to know how many arguments you have and take action based on that. If you want to do your second part, for example, you could do something like
if [[ $# -eq 0 ]]; then
script -q -c "$0 /tmp/build.txt | aha /tmp/build.html
exit
fi
# do everything if you have at least one argument
Though this will have problems if your script/path have spaces, so you're probably better putting the real path to your script in the script command instead of $0
You can also use exec instead of running the command and exiting, but make sure you have your quotes in the right place:
if [[ $# -eq 0 ]]; then
exec script -q -c "$0 /tmp/build.txt | aha /tmp/build.html"
fi
# do everything when you have at least 1 argument

How to run bash script when a program open in liunx

Is there a way to execute bash script when I click a program like NetBeans or DropBox on Ubuntu
and execute a bash script when exit it
My idea create bash script on cronjob #reboot check every second if the program exist in the current processes
#!/bin/bash
NameOfprogram="NetBeans"
while [[ true ]]; do
countOfprocess=$(ps -ef |grep $NameOfprogram | wc -l)
if [[ $countOfprocess -gt 1 ]]; then
#execute bash
fi
sleep 1
done
But I think this idea not the best ,Is there a better way to achieve it?
A better approach is to wrap the executable in a script. That means you put a script with the name of the program in your path (probably $HOME/bin) and Linux will use that instead of the real executable.
Now you can execute the real program using:
/usr/bin/NetBeans "$#"
So to execute the real executable, you just put the absolute path in front of the name. The odd "$#" too pass on any arguments someone might have given the script.
Put a loop around this:
while [[ true ]]; do
/usr/bin/NetBeans "$#"
done
But there is a problem: You can't exit this program anymore. As soon as you try, it restarts. So if you just want a restart when it crashes:
while [[ true ]]; do
/usr/bin/NetBeans "$#" && exit 0
done
As long as the program exits because of an error, it will be restarted. If you quit it, the script will stop.

Running a command only once from a script, even script is executed multiple times

I need some help. I'm having a script 'Script 1', which will call 'Script 2' to run in background which checks something periodically. But I want the Script 2 to get started only once, even Script 1 is called multiple times. Is there a way to do it?
It would be even more helpful, if someone suggests some commands to achieve this.
Thanks in advance
Sure, you can put something like this at the top of Script2:
if [[ -f /tmp/Script2HasRun ]] ; then
exit
fi
touch /tmp/Script2HasRun
That will stop Script2 from ever running again by using a sentinel file, unless the file is deleted of course, and it probably will be at some point since it's in /tmp.
So you probably want to put it somewhere else where it can be better protected.
If you don't want to stop it from ever running again, you need some mechanism to delete the sentinel file.
For example, if your intent is to only have one copy running at a time:
if [[ -f /tmp/Script2IsRunning ]] ; then
exit
fi
touch /tmp/Script2IsRunning
# Do whatever you have to do.
rm -f /tmp/Script2IsRunning
And keep in mind there's a race condition in there that could result in two copies running. There are ways to mitigate that as well by using the content as well as the existence, something like:
if [[ -f /tmp/Script2IsRunning ]] ; then
exit
fi
echo $$ >/tmp/Script2IsRunning
sleep 1
if [[ "$(cat /tmp/Script2IsRunning 2>/dev/null)" != $$ ]] ; then
exit
fi
# Do whatever you have to do.
rm -f /tmp/Script2IsRunning
There are more levels of protection beyond that but they become complex, and I usually find that suffices for most things.

Resources