self-deleting shell script - bash

I've looked around for an answer to this one but couldn't find one.
I have written a simple script that does initial server settings and I'd like it to remove/unlink itself from the root directory on completion. I've tried a number of solutions i googled ( for example /bin/rm $test.sh) but the script always seems to remain in place. Is this possible? Below is my script so far.
#! /bin/bash
cd /root/
wget -r -nH -np --cut-dirs=1 http://myhost.com/install/scripts/
rm -f index.html* *.gif */index.html* */*.gif robots.txt
ls -al /root/
if [ -d /usr/local/psa ]
then
echo plesk > /root/bin/INST_SERVER_TYPE.txt
chmod 775 /root/bin/*
/root/bin/setting_server_ve.sh
rm -rf /root/etc | rm -rf /root/bin | rm -rf /root/log | rm -rf /root/old
sed -i "75s/false/true/" /etc/permissions/jail.conf
exit 1;
elif [ -d /var/webmin ]
then
echo webmin > /root/bin/INST_SERVER_TYPE.txt
chmod 775 /root/bin/*
/root/bin/setting_server_ve.sh
rm -rf /root/etc | rm -rf /root/bin | rm -rf /root/log | rm -rf /root/old
sed -i "67s/false/true/" /etc/permissions/jail.conf
break
exit 1;
else
echo no-gui > /root/bin/INST_SERVER_TYPE.txt
chmod 775 /root/bin/*
/root/bin/setting_server_ve.sh
rm -rf /root/etc | rm -rf /root/bin | rm -rf /root/log | rm -rf /root/old
sed -i "67s/false/true/" /etc/permissions/jail.conf
break
exit 1;
fi

rm -- "$0"
Ought to do the trick. $0 is a magic variable for the full path of the executed script.

This works for me:
#!/bin/sh
rm test.sh
Maybe you didn't really mean to have the '$' in '$test.sh'?

The script can delete itself via the shred command (as a secure deletion) when it exits.
#!/bin/bash
currentscript="$0"
# Function that is called when the script exits:
function finish {
echo "Securely shredding ${currentscript}"; shred -u ${currentscript};
}
# Do your bashing here...
# When your script is finished, exit with a call to the function, "finish":
trap finish EXIT

The simplest one:
#!/path/to/rm
Usage: ./path/to/the/script/above
Note: /path/to/rm must not have blank characters at all.

I wrote a small script that adds a grace period to a self deleting script based on
user742030's answer https://stackoverflow.com/a/34303677/10772577.
function selfShred {
SHREDDING_GRACE_SECONDS=${SHREDDING_GRACE_SECONDS:-5}
if (( $SHREDDING_GRACE_SECONDS > 0 )); then
echo -e "Shreding ${0} in $SHREDDING_GRACE_SECONDS seconds \e[1;31mCTRL-C TO KEEP FILE\e[0m"
BOMB="●"
FUZE='~'
SPARK="\e[1;31m*\e[0m"
SLEEP_LEFT=$SHREDDING_GRACE_SECONDS
while (( $SLEEP_LEFT > 0 )); do
LINE="$BOMB"
for (( j=0; j < $SLEEP_LEFT - 1; j++ )); do
LINE+="$FUZE"
done
LINE+="$SPARK"
echo -en $LINE "\r"
sleep 1
(( SLEEP_LEFT-- ))
done
fi
shred -u "${0}"
}
trap selfShred EXIT
See the repo here: https://github.com/reedHam/self-shred

$0 may not contain the script's name/path in certain circumstances. Please check the following: https://stackoverflow.com/a/35006505/5113030 (Choosing between $0 and BASH_SOURCE...)
The following script should work as expected in these cases:
source script.sh - the script is sourced;
./script.sh - executed interactively;
/bin/bash -- script.sh - passed as an argument to a shell program.
#!/usr/bin/env bash
# ...
rm -- "$( readlink -f -- "${BASH_SOURCE[0]:-$0}" 2> '/dev/null'; )";
Please check the following regarding shell script source reading and execution since it may affect the behavior when a script is deleted while running: https://unix.stackexchange.com/a/121025/133353 (How Does Linux deal with shell scripts?...)
Related: https://stackoverflow.com/a/246128/5113030 (How can I get the source directory of a Bash script from...)

Just add to the end:
rm -- "$0"

Why remove the script at all? As other have mentioned it means you have to keep a copy elsewhere.
A suggestion is to use a "firstboot" like approach. Simply create an empty file in e.g. /etc/sysconfig that triggers the execution of this script if it is present. Then remove that file at the end of the script.
Modify the script so it has the necessary chkconfig headers and place it in /etc/init.d/ so it is run at every boot.
That way you can rerun the script at a later time simply by recreating the trigger script.
Hope this helps.

Related

Send files to folders using bash script

I want to copy the functionality of a windows program called files2folder, which basically lets you right-click a bunch of files and send them to their own individual folders.
So
1.mkv 2.png 3.doc
gets put into directories called
1 2 3
I have got it to work using this script but it throws out errors sometimes while still accomplishing what I want
#!/bin/bash
ls > list.txt
sed -i '/list.txt/d' ./list.txt
sed 's/.$//;s/.$//;s/.$//;s/.$//' ./list.txt > list2.txt
for i in $(cat list2.txt); do
mkdir $i
mv $i.* ./$i
done
rm *.txt
is there a better way of doing this? Thanks
EDIT: My script failed with real world filenames as they contained more than one . so I had to use a different sed command which makes it work. this is an example filename I'm working with
Captain.America.The.First.Avenger.2011.INTERNAL.2160p.UHD.BluRay.X265-IAMABLE
I guess you are getting errors on . and .. so change your call to ls to:
ls -A > list.txt
-A List all entries except for . and ... Always set for the super-user.
You don't have to create a file to achieve the same result, just assign the output of your ls command to a variable. Doing something like this:
files=`ls -A`
for file in $files; do
echo $file
done
You can also check if the resource is a file or directory like this:
files=`ls -A`
for res in $files; do
if [[ -d $res ]];
then
echo "$res is a folder"
fi
done
This script will do what you ask for:
files2folder:
#!/usr/bin/env sh
for file; do
dir="${file%.*}"
{ ! [ -f "$file" ] || [ "$file" = "$dir" ]; } && continue
echo mkdir -p -- "$dir"
echo mv -n -- "$file" "$dir/"
done
Example directory/files structure:
ls -1 dir/*.jar
dir/paper-279.jar
dir/paper.jar
Running the script above:
chmod +x ./files2folder
./files2folder dir/*.jar
Output:
mkdir -p -- dir/paper-279
mv -n -- dir/paper-279.jar dir/paper-279/
mkdir -p -- dir/paper
mv -n -- dir/paper.jar dir/paper/
To make it actually create the directories and move the files, remove all echo

bash move is failing

I am running below commands in a script
move_jobs() {
cd $JOB_DIR
for i in `cat $JOBS_FILE`
do
if [ `ls | grep -i ^${i}- | wc -l` -gt 0 ]; then
cd $i
if [ ! -d jobs ]; then
mkdir jobs && cd .. && mv "${i}"-* "${i}"/jobs/
else
cd .. && mv "${i}"-* "${i}"/jobs/
fi
error_handler $?
fi
done
}
but it failing as
mv: cannot stat `folder-*': No such file or directory
Not sure why move command is failing with regular expression
Your script is overly complicated and has several issues, one of which will be the problem, I guess it's the ls | grep ... part, but to find that out, you should include some debug logging.
for i in $(cat ...) loops through words, not lines.
Do not parse ls
And if you still do, do not ever grep for filenames but include it in your ls call: ls "${i}"-* | wc -l.
You do not need to check if a folder exists when the only thing that is different then is that you create it. You can use mkdir -p instead.
Jumping around folders in your script makes it almost unreadable, as you need to keep track of all cd commands when reading your script.
You could simply write the following, which I think will do what you want:
xargs -a "$JOBS_FILE" -I{} \
sh -c "
mkdir -p '$JOB_DIR/{}/jobs';
mv '$JOB_DIR/{}-'* '$JOB_DIR/{}/jobs';
"
or if you need more control:
while IFS= read -r jid; do
if ls "$JOB_DIR/$jid-"* &>/dev/null; then
TARGET_DIR="$JOB_DIR/$jid/jobs"
mkdir -p "$TARGET_DIR"
mv "$JOB_DIR/$jid-"* "$TARGET_DIR"
echo "OK"
else
echo "No files to move."
fi
done < "$JOBS_FILE"

Syntax error: "(" unexpected in bash script

EDIT: I have fixed my script. It seems to be working. If anyone has any suggestions for improvement I would love the help. Apparently I needed to run it using bash instead of sh.
Here is the updated script:
#!/bin/bash
for file in /home/corey/box/*/*
do
dir=$(basename $"(dirname "$file")")
sudo chmod 0777 /var/log/torrentwatch.log
sudo chmod -R 0777 /home/corey/box/*/*
if [[ "$file" = /home/corey/box/*/*.torrent ]]
then
echo "[$(date)]" "$file added to queue." >> /var/log/torrentwatch.log
/usr/bin/transmission-remote localhost:9091 --auth=transmission:transmission -w /media/Media/Torrents/"$dir" -a "$file"
sleep 40 && rm "$file"
sleep 3 && sudo chmod -R 777 /media/Media && sudo chown -R debian-transmission:debian-transmission /media/Media/info
fi
done
The script is for adding torrent files to a folder and having them added to transmission. Here's the original version of the script:
#!/bin/bash
for file in /home/me/box/*/*
do
dir=$(basename $(dirname "$file"));
sudo chmod 0777 /var/log/torrentwatch.log
sudo chmod -R 0777 /home/me/box/*/*
if "$file" = "/home/me/box/*/*.torrent"; then
echo [`date`] "$file" added to queue. >> /var/log/torrentwatch.log
/usr/bin/transmission-remote localhost:9091 --auth=transmission:transmission -l -w /media/Media/Torrents/$dir -a "$file"
sleep 40 && rm "$file"
sleep 3 && sudo chmod -R 777 /media/Media && sudo chown -R debian-transmission:debian-transmission /media/Media/info
fi
done
The problem is that when I run the script I get
/home/me/box/TV/Name.of.file.torrent: Syntax error: "(" unexpected
I've tried running the script with bash, sh, and zsh, and none seem to work. I can't figure out what the problem is.
This is the immediate problem:
if "$file" = "/home/me/box/*/*.torrent"
It's running the following:
/home/me/box/TV/Name.of.file.torrent = "/home/me/box/*/*.torrent"
...which is to say, it's trying to start the .torrent file as a script (with its first argument being = and its second argument being /home/me/box/*/*.torrent), which generates a syntax error. Instead, use:
if [[ $file = /home/me/box/*/*.torrent ]]
There are other issues elsewhere in this script -- I strongly recommend running it through http://shellcheck.net/.

understanding a shell script code using expand function

I am working on shell script.
EXEC $CXCHOME+"/etc/expand_in_place" $MMSHOME+"/PDM/bin/pmr_pdm_aos"**
CXCHOME "/opt/ericsson/aos/PDM"
MMSHOME "/opt/ericsson/aos"
the code of expand_in_place is as below -
#!/bin/bash
. $INST_DATADIR/$PKG/install/aosbootcommon.sh
filename=`basename $1`
tmpfile="/tmp/$filename.$$"
rm -f "$tmpfile"
cp -p "$1" "$tmpfile"
echoLog "Expanding $1..."
expand "$tmpfile" "$1"
rm -f "$tmpfile"
cleanExit 0
I wanted to know the working of "expand_in_place".
Long answer:
#!/bin/bash
Use /bin/bash program to process the code that follows.
. $INST_DATADIR/$PKG/install/aosbootcommon.sh
Read and execute the code in this file in the same process
filename=`basename $1`
Run the basename program, passing-in the first command-line argument (use man basename to find out what that does). The back-ticks are a deprecated way to capture the output from a program. In this case the output from basename is placed into the filename variable.
tmpfile="/tmp/$filename.$$"
Set the variable tmpfile to be /tmp, followed by the values of filename, followed by out current process id. The $ is an operator which gives us the value of a variable. $$ gives us the value of our current PID.
rm -f "$tmpfile"
Run the rm program passing these parameters : use man rm to find out what that does.
cp -p "$1" "$tmpfile"
Run the cp program passing those parameters: use man cp to find out what that does.
echoLog "Expanding $1..."
I have no idea what echoLog does, it is probably a local function defined in $INST_DATADIR/$PKG/install/aosbootcommon.sh
expand "$tmpfile" "$1"
Run the expand program using those parameters, use man expand to find out what that does.
rm -f "$tmpfile"
Run the rm program passing these parameters : use man rm to find out what that does.
cleanExit 0
I have no idea what cleanExit does, it is probably a local function defined in $INST_DATADIR/$PKG/install/aosbootcommon.sh

Temporary operation in a temporary directory in shell script

I need a fresh temporary directory to do some work in a shell script. When the work is done (or if I kill the job midway), I want the script to change back to the old working directory and wipe out the temporary one. In Ruby, it might look like this:
require 'tmpdir'
Dir.mktmpdir 'my_build' do |temp_dir|
puts "Temporary workspace is #{temp_dir}"
do_some_stuff(temp_dir)
end
puts "Temporary directory already deleted"
What would be the best bang for the buck to do that in a Bash script?
Here is my current implementation. Any thoughts or suggestions?
here=$( pwd )
tdir=$( mktemp -d )
trap 'return_here' INT TERM EXIT
return_here () {
cd "$here"
[ -d "$tdir" ] && rm -rf "$tdir"
}
do_stuff # This may succeed, fail, change dir, or I may ^C it.
return_here
Here you go:
#!/bin/bash
TDIR=`mktemp -d`
trap "{ cd - ; rm -rf $TDIR; exit 255; }" SIGINT
cd $TDIR
# do important stuff here
cd -
rm -rf $TDIR
exit 0
The usual utility to get yourself a temporary directory is mktemp -d (and the -p option lets you specify a prefix directory).
I'm not sure if "I want to trap" was a question too, but bash does let you trap signals with (surprise!) trap - see the documentation.
Assuming mktemp -d returns a relative pathname, I would forget about $here and do this instead:
tdir=
cleanup() {
test -n "$tdir" && test -d "$tdir" && rm -rf "$tdir"
}
tdir="$(pwd)/$(mktemp -d)"
trap cleanup EXIT
trap 'cleanup; exit 127' INT TERM
# no need to call cleanup explicitly, unless the shell itself crashes, the EXIT trap will run it for you

Resources