I am creating a script for copying files or directory with a date attached to its name, for example if the file name is test it will be test-20130901.bkup
and this is my script
#!/usr/bin/bash
set -x
getopts fd TYPE
[ $TYPE = "d" ] && alias cp="cp -r"
backup_error() {
echo "${0##*/}: $1"
exit -1
}
typeset -r FROM_DIR=$2 TO_DIR=$3
if [ ! -e $FROM_DIR -a ! -d $FROM_DIR ] || [ ! -e $TO_DIR -a ! -d $TO_DIR ]
then
backup_error "One of the directories isn't exist or it maybe a file";
fi
typeset -r DATE=$(date "+%Y%m%d")
for filename in $FROM_DIR/*
do
if [ -$TYPE $filename ]
then
cp $filename $TO_DIR/${filename##*/}-$DATE.bkup
fi
done
unalias cp
In the script I check if the user wants to run the script on files only or on directories only.
-f for files only
-d for directories only
[ $TYPE = "d" ] && alias cp="cp -r", this line to check if the script runs for directory I must use cp -r so I make an alias for cp to be cp -r
but when I use set -x to debug I find the when a user use -d option the cp command in the if still the original one not the alias.
Debugging:
> ./backup.sh -d . .
+ getopts fdb TYPE
+ '[' d = d ']'
+ alias 'cp=cp -r'
+ typeset -r FROM_DIR=. TO_DIR=.
+ '[' '!' -e . -a '!' -d . ']'
+ '[' '!' -e . -a '!' -d . ']'
++ date +%Y%m%d
+ typeset -r DATE=20130901
+ '[' -d ./backup.sh ']'
+ '[' -d ./dir1 ']'
+ cp ./dir1 ./dir1-20130901.bkup
cp: ./dir1: is a directory
+ '[' -d ./file1 ']'
+ '[' -d ./file2 ']'
+ '[' -d ./test.sh ']'
+ unalias cp
Use a function instead:
if [[ $TYPE == d ]]; then
function cp {
command cp -r "$#"
}
fi
And when in Bash, [[ ]] is recommended over test or [ ].
Also quote please quote your variables properly between "" to prevent word splitting and unexpected pathname expansion.
Other caveats:
exit -1 ## exit can only accept 8-bit integral values from 0 to 255. -1 here is orthodox and is equivalent to 255.
You should quote the variables here or use [[ ]]:
if [[ ! -e $FROM_DIR && ! -d $FROM_DIR ]] || [[ ! -e $TO_DIR && ! -d $TO_DIR ]]
if [ "-$TYPE" "$filename" ] ## for custom operators, test is better: test "-$TYPE" "$filename"
cp "$filename" "$TO_DIR/${filename##*/}-$DATE.bkup"
for filename in "$FROM_DIR"/*
Lastly make sure you run your script as:
bash script.sh -f from_dir to_dir
# Or
bash script.sh -d from_dir to_dir
Related
I am trying to write a bash/shell script for downloading BuildTools and compiling the jars with it, after that I want to move them to my webserver (/var/www/html/jars/) from within the script at /home/buildtools/
BuildTools downloads/compiles the jars and places them at the base directory, except the vanilla jar, which is located at work/ inside the base directory.
Even though it does download/compile the jars, they aren't all moving to the desired directories.
This is the code I am using at the moment (I think it might all be relevant to provide):
directory="$(pwd)/"
jar="BuildTools.jar"
path="${directory}${jar}"
output="/var/www/html/jars"
version=$1
if [[ ( -d "BuildData" ) || ( -d "Spigot" ) || ( -d "CraftBukkit" ) || ( -d "Bukkit" ) || ( -d "work" ) || ( -d "apache-maven-*" ) || ( -f "BuildTools.log.txt" ) ]]; then
echo "Cleaning up..."
rm -f -r BuildData/ Spigot/ CraftBukkit/ Bukkit/ work/ apache-maven-*/
rm -f BuildTools.log.txt spigot-*.jar craftbukkit-*.jar vanilla-*.jar
fi
if [[ ! -f "${jar}" ]]; then
echo "Downloading BuildTools..."
wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O ${jar}
chmod 775 ${jar}
fi
if [[ ! -z "${version}" ]]; then
echo "Compiling jars for version ${version}..."
java -jar ${jar} --rev ${version}
else
echo "No version specified."
echo "Compiling jars for the latest version..."
java -jar ${jar} --rev latest
fi
if [[ ( -f "${directory}spigot-*.jar" ) || ( -f "${directory}craftbukkit-*.jar" ) ]]; then
echo "Compilation is done. Re-organizing..."
if [[ ! -z "${version}" ]]; then
mv work/minecraft_server.*.jar ${directory}/vanilla-${version}.jar
else
mv work/minecraft_server.*.jar ${directory}/vanilla-latest.jar
fi
echo "Moving jars to the webserver..."
mv ${directory}/vanilla-*.jar ${output}/
mv ${directory}/spigot-*.jar ${output}/
mv ${directory}/craftbukkit-*.jar ${output}/
else
echo "Could not re-organize, the jars hasn't been moved."
fi
Edit:
By executing the command: ./compile.sh 1.8.6
For some reason the jarfiles aren't the right names.
Result of the code.
directory="$(pwd)/"
jar="BuildTools.jar"
path="${directory}${jar}"
output="/var/www/html/jars"
version=$1
if [[ ( -d "BuildData" ) || ( -d "Spigot" ) || ( -d "CraftBukkit" ) || ( -d "Bukkit" ) || ( -d "work" ) || ( -d "apache-maven-*" ) || ( -f "BuildTools.log.txt" ) ]]; then
echo "Cleaning up..."
rm -f -r BuildData/ Spigot/ CraftBukkit/ Bukkit/ work/ apache-maven-*/
rm -f BuildTools.log.txt done.txt spigot-*.jar craftbukkit-*.jar vanilla-*.jar
fi
if [[ ! -f "${jar}" ]]; then
echo "Downloading BuildTools..."
wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O ${jar}
chmod 775 ${jar}
fi
if [[ ! -z "${version}" ]]; then
echo "Compiling jars for version ${version}..."
java -jar ${jar} --rev ${version}
echo "done" > done.txt
else
echo "No version specified. Compiling jars for the latest version..."
java -jar ${jar} --rev latest
echo "done" > done.txt
fi
if [[ -f "done.txt" ]]; then
echo "Compilation is done. Re-organizing..."
for x in $(find ${directory} \( -name "*.jar" \)); do
name=$(basename "${x}" ".jar")
if [[ ${name} =~ ^(spigot|craftbukkit|minecraft_server)(-)?(.*)? ]]; then
fullname="${name}.jar"
echo "Jar found: ${fullname}, Moving to webserver..."
if [[ ! -z "${version}" ]]; then
outpath=${output}/${version}
if [[ ! -d ${outpath} ]]; then
mkdir ${outpath}
fi
mv -f ${x} ${outpath}/${fullname}
else
outpath=${output}/latest
if [[ ! -d ${outpath} ]]; then
mkdir ${outpath}
fi
rm -f -r ${outpath}
mv -f ${x} ${outpath}/${fullname}
fi
fi
done
echo "Jars uploaded."
else
echo "Could not re-organize, the jars hasn't been moved."
fi
And additionally, I would like to only have one file of each uploaded (Vanilla, Spigot, Craftbukkit), how do I do that?
It's because of the parenthesis inside your conditional expression, as well as trying to use globs on the wrong part of the expression (you can't use tests like that with globs).
To fix this you should do something like:
#set nullglob so non-matching globs return an empty string instead of an error
shopt -s nullglob
# assing the globs to arrays, note the quoting
spigotfiles=("${directory}"spigot-*.jar)
bukkitfiles=("${directory}"craftbukkit-*.jar)
# using an array without an index gives us the first item in the array
if [[ -f "$spigotfiles" || -f "$bukkitfiles" ]]; then
...
fi
The same error with parenthesis is in your cleanup-code too, which you can handle by just removing the parens (e.g. [[ -d "dirname" || -d "fooname" ]] )
You should also quote your variable expansions (i.e. "${jar}" etc.) in every case (like in a part of a command).
Also using [[ ! -z $foo ]] is the same as [[ -n $foo ]]
Edit:
Don't do
for x in $(find ${directory} \( -name "*.jar" \)); do
but instead just:
for x in *.jar; do
or if you want only your versioned files, you can do:
for x in *"-${version}.jar"; do
You still have the parens in the cleanup check, see the answer above for that.
And in the end of the script these lines are counterproductive:
if [[ ! -d ${outpath} ]]; then
mkdir ${outpath}
fi
rm -f -r ${outpath}
mv -f ${x} ${outpath}/${fullname}
As you first create a dir, then remove it and then try to move things into it (hint: remove the rm line)
I am trying to create a basic recycle bin concept in a VM using bash scripting. It will need to delete files that have been entered and place them into a directory that is created and save the path(origin) to a log file to be later used in a restore function.
I will start off with my delete/recycle code which I believe works just fine but seems kind of untidy/contains redundant code:
#!/bin/sh
if [ ! -d ~/recycle ]
then mkdir ~/recycle
fi
if [ ! -d ~/recycle/recycle_log ]
then mkdir ~/recycle/recycle_log
fi
if [ ! -d ~/recycle/recycle_bin ]
then mkdir ~/recycle/recycle_bin
fi
if [ -d ~/recycle ]
then
echo "$(readlink -f "$1")" >> "$HOME/recycle/recycle_log/log_file" && mv "$1" "$HOME/recycle/recycle_bin"
echo "$(readlink -f "$2")" >> "$HOME/recycle/recycle_log/log_file" && mv "$2" "$HOME/recycle/recycle_bin"
echo "$(readlink -f "$3")" >> "$HOME/recycle/recycle_log/log_file" && mv "$3" "$HOME/recycle/recycle_bin"
echo "$(readlink -f "$4")" >> "$HOME/recycle/recycle_log/log_file" && mv "$4" "$HOME/recycle/recycle_bin"
fi
#end
Thereafter what I have for my restore script is as follows:
#!/bin/sh
cd "$HOME/recycle/recycle_bin" || exit 1
mv -i "$(grep "$1" "$HOME/recycle/recycle_log")"
I imagine this is somewhat close to what I need to return any deleted file stored in the log/recycle bin to be restored to its origin but the error I am getting is:
mv: missing destination file operand after `'
Any thoughts on where I'm going wrong?
Try this:
recycle.sh
#!/bin/sh
set -e
check_dir() {
[ ! -d $1 ] || return 0
mkdir --parents $1
}
check_dir "${HOME}/recycle/recycle_bin"
touch "${HOME}/recycle/recycle_log"
for file in "$#"; do
echo "$(readlink -f "$file")" >> "${HOME}/recycle/recycle_log"
mv "$file" "${HOME}/recycle/recycle_bin"
done
#end
restore.sh
#!/bin/sh
set -e
cd "${HOME}/recycle/recycle_bin" || exit 1
for name in "$#"; do
file=$(grep "\/${name}\$" "${HOME}/recycle/recycle_log")
mv -i $name "$file"
sed -i "/\/${name}\$/ d" "${HOME}/recycle/recycle_log"
done
Some insights:
set -e: Abort on any error, to avoid some if's
$#: The array of arguments ($1, $2...)
[ ! -d $1 ] || return 0: Since we are using set -e, do not fail if the directory exists
grep "\/${name}\$" ...: Only matches the name at the end of the path
sed -i: sed in-place editing to remove the line
On my script, this -for unknown some reason- gives me errors when it reaches sed command:
function nzb() {
( [ -z "$1" ] ) && echo "No argument is given!" && return 1
hash="$(echo -n "$1" | md5sum | cut -d" " -f1)"
mkdir "${hash}" && rar a -m0 -v200M "${hash}"/"${hash}".rar "$1" && rm -rf "$1" &&
par2 c -r10 -l "${hash}"/"${hash}".par2 "${hash}"/* && ~/newsmangler-master/mangler.py
-c ~/.newsmangler.conf "{hash}" && sed -i "1i$1\n${hash}\n" ~/hashs.txt
}
.
ERROR: "{hash}" does not exist or is not a file!
ERROR: no valid arguments provided on command line!
But when I -out of curiosity- removed sed's preceding commands, it worked perfectly like it suppose to:
function nzb() {
( [ -z "$1" ] ) && echo "No argument is given!" && return 1
hash="$(echo -n "$1" | md5sum | cut -d" " -f1)"
sed -i "1i$1\n${hash}\n" ~/hashs.txt
}
.
Any Ideas?
EDIT: it seems the problem is located in this area:
. . . && ~/newsmangler-master/mangler.py -c ~/.newsmangler.conf "{hash}" && . . .
Because even this is working:
function nzb() {
( [ -z "$1" ] ) && echo "No argument is given!" && return 1
hash="$(echo -n "$1" | md5sum | cut -d" " -f1)"
mkdir "${hash}" && rar a -m0 -v200M "${hash}"/"${hash}".rar "$1" && rm -rf "$1" &&
par2 c -r10 -l "${hash}"/"${hash}".par2 "${hash}"/* && sed -i "1i$1\n${hash}\n"
~/hashs.txt
}
Replace "{hash}" with "${hash}"
I'm having a bit of trouble running this script. Every now and then, it will fail to execute a mv command or rm command referenced below. Then the next iteration will feel the full repercussions of that failure. Why is this happening, and how do I control for it? For reference, the syntax phyml -i $f [parameters] outputs the files $f_phyml_tree.txt and $f_phyml_stats.txt into the same directory as $f. I want to get both these files out of that directory while saving the tree somewhere else.
ber="_phyml_tree.txt"
for f in ~/randseqs/aa/*.txt;
do
echo $f
fpath=`echo $f | cut -d'/' -f 6`
if [ ! -f /home/mcb3421_10/phymlout/aa/$fpath$ber ] || [ ! -f /home/mcb3421_10/phymltimer/aa/$fpath ]; then
phyml -i $f -d aa -b 0 -m Blosum62 > ~/blown.txt
grep "Time used" < ~/blown.txt > ~/phymltimer/aa/$fpath
mv /home/mcb3421_10/randseqs/aa/*$ber phymlout/aa
if [ ! -f /home/mcb3421_10/phymlout/aa/$fpath$ber ]; then
echo $f failed to write, check the logfile /home/mcb3421_10/phymllogs/aa/$fpath
fi
rm ~/randseqs/aa/*_stat*
mv ~/blown.txt ~/phymllogs/aa/$fpath
fi
done
for f in ~/randseqs/nuc/*.txt;
do
echo $f
fpath=`echo $f | cut -d'/' -f 6`
if [ ! -f /home/mcb3421_10/phymlout/nuc/$fpath$ber ] || [ ! -f /home/mcb3421_10/phymltimer/nuc/$fpath ]; then
phyml -i $f -d nt -b 0 -m HKY85 > ~/blown.txt
grep "Time used" < ~/blown.txt > ~/phymltimer/nuc/$fpath
mv /home/mcb3421_10/randseqs/nuc/*$ber phymlout/nuc
if [ ! -f /home/mcb3421_10/phymlout/nuc/$fpath$ber ]; then
echo $f failed to write, check the logfile /home/mcb3421_10/phymllogs/nuc/$fpath
fi
rm ~/randseqs/nuc/*_stat*
mv ~/blown.txt ~/phymllogs/nuc/$fpath
fi
done
need some help with my script. I wanna convert ISO files to UTF-8. The problem is I don't know how to write the IF:
if [ `file -b {}` = "$UTF8" ] \
right and how can tell the sed program - that it ignores # comments ?
Here's my script :
#!/bin/bash
clear
echo -e '\E[37mThis script encodes recursively files from \E[31mISO-8859-1 \E[37mto \E[31mUTF-8 \E[37musing iconv.'
echo "Files of the following coded character sets will be encode: "
echo -e '\E[32m'
a='*.java'
b='*.txt'
c='*.php'
d='*.html'
e='*.aj'
f='*.patch'
g='*.css'
h='*.js'
i='*.conf'
j='*.jsp'
k='*.sh'
l='*.py'
m='*.pl'
n='*.rb'
for x in "$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h" "$i" "$j" "$k" "$l" "$m" "$n"
do
echo $x
done
echo
tput sgr0
#
# TODO: COMMENTS aren't ignored
# TOOD: IF-THEN aren't working right
#
for y in "$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h" "$i" "$j" "$k" "$l" "$m" "$n"
do
echo -e "\E[37mencoding all <\E[32m$y\E[37m> files ..."
find . -name "$y" -exec sh -c "( \
UTF=".*UTF-8 Unicode.*" \
FILE={} \
if [ `file -b {}` = "$UTF8" ] \
then \
iconv -f latin1 -t UTF-8 {} -o {}.iconv ; \
sed -n '
{
s/^ *#/#/#.*//g;
s/ä/0xE4;/g;
s/Ä/0xC4;/g;
s/ü/0xFC;/g;
s/Ü/0xDC;/g;
s/ö/0xF6;/g;
s/Ö/0xD6;/g;
s/ß/0xDF;/g;
p;
} {}.iconv > {}.iconv_sed \ '
mv {}.iconv_sed {} && rm {}.iconv ; \
else \
echo "$FILE is a UTF8 file. " \
fi \
)" \;
echo -e '\E[33m*** done ***'
done
echo
tput sgr0
exit 0
thanks
There appear to be more than a few things wrong in your script (for example, I don't see the "UTF8" variable defined anywhere), but you've made it extremely difficult on yourself in terms of debugging it. If it were me, I would:
put all the find's sh -c "... crap in a separate script so you can test it separately
if [ "`file -b $1`" = ...
probably put the sed stuff in a separate function and test that
not use sed -n and then explicitly p; every line, that's silly
properly quote the sed script; I believe you are trying to do redirection inside it
... five suggestions should be enough to get you started. Suggestion 0 is "write a more specific title for your question"