I have written a small bash file to backup a repository. If the archive file doesn't exists, it should be created. Thereafter, files found should be appended to the existing file.
For some reason, the archive keeps getting (re)created/overwritten. This is my script below. Can anyone see where the logic error is coming from?
#!/bin/bash
REPOSITORY_DIR=$PWD/../repository
STORAGE_DAYS=30
#https://stackoverflow.com/questions/48585148/reading-names-of-imediate-child-folders-into-an-array-and-iterating-over-it?noredirect=1#comment84167181_48585148
while IFS= read -rd '' file;
do fbname=$(basename "$file");
# Find all persisted (.CSV) files that are older than $STORAGE_DAYS
files_to_process=($(find $REPOSITORY_DIR/$fbname -type f -name '*.csv' -mtime +$STORAGE_DAYS))
backup_datafile=$REPOSITORY_DIR/$fbname/$fbname.data.tar.gz
#echo $backup_datafile
# If the tar.gz file does not exist, we want to create it
# else (i.e. file exists), we want to add files to it
# Solution from: https://stackoverflow.com/questions/28185012/how-to-create-tar-for-files-older-than-7-days-using-linux-shell-scripting
NUM_FILES_FOUND=${#files_to_process[#]}
if [ $NUM_FILES_FOUND -gt 0 ]; then
echo "Found ${#files_to_process[#]} files to process ..."
if [ ! -f backup_datafile ]; then
# Creating a new tar.gz file, since file was not found
echo "Creating new backup file: $backup_datafile"
tar cvfz $backup_datafile "${files_to_process[#]}"
else
echo "Adding files to existing backup file: $backup_datafile"
# https://unix.stackexchange.com/questions/13093/add-update-a-file-to-an-existing-tar-gz-archive
gzip -dc $backup_datafile | tar -r "${files_to_process[#]}" | gzip >$backup_datafile.new
mv $backup_datafile.new $backup_datafile
fi
# remove processed files
for filename in "${files_to_process[#]}"; do
rm -f "$filename"
done
else
echo "Skipping directory: $REPOSITORY_DIR/$fbname/. No files found"
fi
done < <(find "$REPOSITORY_DIR" -maxdepth 1 -mindepth 1 -type d -print0)
This is where it went wrong:
if [ ! -f backup_datafile ]; then
I guess it should have been
if [ ! -f $backup_datafile ]; then
^
Or better yet, put that in quotes:
if [ ! -f "$backup_datafile" ]; then
if [ ! -f backup_datafile ]; then
i think you might be missing a "$" there
Related
I'm trying to write a BASH script that iterate over all files in directory and if the file is not zip than zip it
#!/bin/bash
echo "Start"
for f in *
do
echo "Start loop $f "
# if .bak backup file exists, read next file
if [ -${f} = *.zip ]
then
echo "Skiping $f file..."
continue # read next file and skip the cp command
fi
zip $f.zip $f
done
echo "Closing"
I have the following files in the directory: 1, 2, 3.zip, zipper.sh
the output of the script over the directory needs to be
1, 1.zip, 2, 2.zip, 3.zip, zipper.sh, zipper.sh.zip
but it also creating 3.zip.zip
Try this below code.
#!/bin/bash
for f in `find . -type f -not -name "*.zip"`;
do
#echo $f
zip "$f".zip $f
done
I have multiple JS files in folder, for example, foo.js, this_is_foo.js, foo_is_function.js.
I want to append a number which is passed as parameter in front of extension ".js", such as foo.1.js, this_is_foo.1.js, foo_is_function.1.js
I write a script to append a number successfully the first time, but if I run the script twice, it does not overwrite the first number but append right after that.
Actual result: foo.js --> foo.1.js (1st run) --> foo.1.2.js (2nd run).
Expected result: foo.js --> foo.1.js (1st run) --> foo.2.js (2nd run).
This is my script:
#!/bin/sh
param=$1
for file in *.js; do
ext="${file##*.}";
filename="${file%.*}";
mv "$file" "${filename}.${param}.${ext}";
done
How can I do that? I want to write pure bash script, not to use any tools.
Before doing the rename you can check if what is after the last dot in filename (${filename%.*}) is numeric. If so switch that with param instead of appending a new param
Since you are writing that you want to use pure bash I assume that it is ok to change the shebang to #!/bin/bash:
#!/bin/bash
param=$1
for file in *.js; do
ext="${file##*.}";
filename="${file%.*}";
# Check if what is after the last dot in filename is numeric
# Then assume that it should be switched to param
if [[ ${filename##*.} =~ ^[0-9]+$ ]]; then
mv "$file" "${filename%.*}.${param}.${ext}"
## Else add param
else
mv "$file" "${filename}.${param}.${ext}"
fi
done
Testrun
$> touch a.js && find -type f -name *.js && \
./test.sh 1 && find -type f -name *.js && \
./test.sh 2 && find -type f -name *.js
./a.js
./a.1.js
./a.2.js
You can use extended globbing to match an optional . (the one before the number) and any amount of digits before the .js suffix.
I also added the . to the $param variable if the variable is non-empty. This way you can call the script without parameter and .<number> is removed instead of added/changed.
#!/bin/bash
shopt -s extglob # enable extended globbing
param=$1
if [ -n "$param" ]; then
param=.${param} # add prefix `.`
fi
for file in *.js; do
newfile=${file%%?(.)*([0-9]).js}${param}.js
if [ "$file" = "$newfile" ]; then
echo "skipping \"${file}\", no need to rename"
elif [ -f "$newfile" ]; then
echo "skipping \"$file\", file \"$newfile\" already exists"
else
mv "$file" "$newfile"
fi
done
Usage:
./script.sh 1 # change suffix to `.1.js`
./script.sh 2 # change suffix to `.2.js`
./script.sh # change suffix to `.js`
Posix compliant solution, which allows you to keep using /bin/sh
#!/bin/sh
param=$1
for file in *.js; do
ext="${file##*.}";
filename="${file%.*}";
[ -z "${filename##*.##*[!0-9]*}" ] && mv "$file" "${filename}.${param}.${ext}" || mv "$file" "${filename%.*}.${param}.${ext}"
done
Testrun
$> touch a.js && find -type f -name *.js && \
./test.sh 1 && find -type f -name *.js && \
./test.sh 2 && find -type f -name *.js
./a.js
./a.1.js
./a.2.js
This might do what you want.
#!/usr/bin/env bash
counter=1
for file in *.js; do
if [[ $file =~ (^[^\.]+)(\.js)$ ]]; then
mv -v "$file" "${BASH_REMATCH[1]}.$counter${BASH_REMATCH[2]}"
elif [[ $file =~ (^[^\.]+)\.([[:digit:]]+)(\.js)$ ]]; then
first=${BASH_REMATCH[1]}
counter=${BASH_REMATCH[2]}
extension=${BASH_REMATCH[3]}
((counter++))
mv -v "$file" "$first.$counter$extension"
fi
done
In action.
mkdir -p /tmp/123 && cd /tmp/123
touch foo.js
touch this_is_foo.js
touch this_is_foucntion.js
First run
./myscript
Output
renamed 'foo.js' -> 'foo.1.js'
renamed 'this_is_foo.js' -> 'this_is_foo.1.js'
renamed 'this_is_foucntion.js' -> 'this_is_foucntion.1.js'
Second run.
renamed 'foo.1.js' -> 'foo.2.js'
renamed 'this_is_foo.1.js' -> 'this_is_foo.2.js'
renamed 'this_is_foucntion.1.js' -> 'this_is_foucntion.2.js'
Third run.
renamed 'foo.2.js' -> 'foo.3.js'
renamed 'this_is_foo.2.js' -> 'this_is_foo.3.js'
renamed 'this_is_foucntion.2.js' -> 'this_is_foucntion.3.js'
Using a for loop
for i in {1..5}; do ./script.sh ; done
Output
renamed 'foo.js' -> 'foo.1.js'
renamed 'this_is_foo.js' -> 'this_is_foo.1.js'
renamed 'this_is_foucntion.js' -> 'this_is_foucntion.1.js'
renamed 'foo.1.js' -> 'foo.2.js'
renamed 'this_is_foo.1.js' -> 'this_is_foo.2.js'
renamed 'this_is_foucntion.1.js' -> 'this_is_foucntion.2.js'
renamed 'foo.2.js' -> 'foo.3.js'
renamed 'this_is_foo.2.js' -> 'this_is_foo.3.js'
renamed 'this_is_foucntion.2.js' -> 'this_is_foucntion.3.js'
renamed 'foo.3.js' -> 'foo.4.js'
renamed 'this_is_foo.3.js' -> 'this_is_foo.4.js'
renamed 'this_is_foucntion.3.js' -> 'this_is_foucntion.4.js'
renamed 'foo.4.js' -> 'foo.5.js'
renamed 'this_is_foo.4.js' -> 'this_is_foo.5.js'
renamed 'this_is_foucntion.4.js' -> 'this_is_foucntion.5.js'
I have written a shell script to move files from source directory to destination directory.
/home/tmp/ to /home/from/
The move happens correctly but it displays message
mv: /home/tmp/testfile_retry_17072017.TIF
/home/tmp/testfile_retry_17072017.TIF are identical.
and if source directory is empty it displays
mv: cannot rename /home/tmp/* to /home/from/*
for file in /home/tmp/*
if [ -f "$file" ]
then
do
DIRPATH=$(dirname "${file}")
FILENAME=$(basename "${file}")
# echo "Dirpath = ${DIRPATH} Filename = ${FILENAME}"
mv "${DIRPATH}/"${FILENAME} /home/from
echo ${FILENAME} " moved to from directory"
done
else
echo "Directory is empty"
fi
You should use find instead of /home/tmp/* as shown.
for file in $(find /home/tmp/ -type f)
do
if [ -f "$file" ]
then
DIRPATH=$(dirname "${file}")
FILENAME=$(basename "${file}")
# echo "Dirpath = ${DIRPATH} Filename = ${FILENAME}"
mv "${DIRPATH}/"${FILENAME} /home/from
echo ${FILENAME} " moved to from directory"
else
echo "Directory is empty"
fi
done
You have things a bit out of order with:
for file in /home/tmp/*
if [ -f "$file" ]
then
do
Of course "$file" will exist -- you are looping for file in /home/tmp/*. It looks like you intended
for file in /home/tmp/*
do
FILENAME=$(basename "${file}")
if [ ! -f "/home/from/$FILENAME" ] ## if it doesn't already exist in dest
then
Note: POSIX shell include parameter expansions that allow you to avoid calling dirname and basename. Instead you can simply use "${file##*/}" for the filename (which just says remove everything from the left up to (and including) the last /). That is the only expansion you need (as you already know the destination directory name). This allows you to check [ -f "$dest/${f##*/}" ] to determine if a file with the same name you are moving already exists in /home/from
You could use that to your advantage with:
src=/home/tmp ## source dir
dst=/home/from ## destination dir
for f in "$src"/* ## for each file in src
do
[ "$f" = "$src/*" ] && break ## src is empty
if [ -f "$dst/${f##*/}" ] ## test if it already exists in dst
then
printf "file '%s' exists in '%s' - forcing mv.\n" "${f##*/}" "$dst"
mv -f "$f" "$dst" ## use -f to overwrite existing
else
mv "$f" "$dst" ## regular move otherwise
fi
done
There is a great resource for checking your shell code called ShellCheck.net. Just type your code into the webpage (or paste it) and it will analyze your logic and variable use and let you know where problem are identified.
Look things over and let me know if you have further questions.
I've been trying to write a script:
EFIDIR=/Volumes/EFI
KEXTDEST=$EFIDIR/EFI/CLOVER/kexts/Other
if [[ -d $EFIDIR/EFI/CLOVER/kexts/10.* ]]; then
echo "Directory found."
if [[ -d $EFIDIR/EFI/CLOVER/kexts/10.*/*.kext ]]; then
echo "Kext(s) found."
cp -R $EFIDIR/EFI/CLOVER/kexts/10.*/*.kext $KEXTDEST
fi
rm -R $EFIDIR/EFI/CLOVER/kexts/10.*
fi
I want to check whether any folder that starts with "10." (can be 10.10, 10.11... etc) exist then if any of those folders contains a folder that ends with (.kext) exists... copy to the destination folder.
How to write it the right way?
Thanks.
Try this:
EFIDIR=/Volumes/EFI
KEXTDEST=$EFIDIR/EFI/CLOVER/kexts/Other
for each in $(find $EFIDIR/EFI/CLOVER/kexts/ -name "10.*" -type d); do
echo "Directory found."
for innerdir in $(find $each -name "*.kext" -type d); do
echo "Kext(s) found."
cp -R $innerdir $KEXTDEST
done
rm -R $each
done
find $EFIDIR/EFI/CLOVER/kexts/ -name "10.*" -type d will look for directories (-type d) starting with name 10.* in $EFIDIR/EFI/CLOVER/kexts and if found will loop through every one in the for loop.
The inner for loop looks for directories starting with name *.kext .
I need help with Ubuntu Precise bash script.
I have several tiff files in various folders
masterFOlder--masterSub1 --masterSub1-1 --file1.tif
|--masterSub1-2 --masterSub1-2-1 --file2.tif
|
|--masterSub2 --masterSub1-2 .....
I need to run an Imagemagick command and save them to new folder "converted" while retaining the sub folder tree i.e. the new tree will be
converted --masterSub1 --masterSub1-1 --file1.png
|--masterSub1-2 --masterSub1-2-1 --file2.png
|
|--masterSub2 --masterSub1-2 .....
How do i split the filepath into folders, replace the first folder (masterFOlder to converted) and recreate a new file path?
Thanks to everyone reading this.
This script should work.
#!/bin/bash
shopt -s extglob && [[ $# -eq 2 && -n $1 && -n $2 ]] || exit
MASTERFOLDER=${1%%+(/)}/
CONVERTFOLDER=$2
OFFSET=${#MASTERFOLDER}
while read -r FILE; do
CPATH=${FILE:OFFSET}
CPATH=${CONVERTFOLDER}/${CPATH%.???}.png
CDIR=${CPATH%/*}
echo "Converting $FILE to $CPATH."
[[ -d $CDIR ]] || mkdir -p "$CDIR" && echo convert "$FILE" "$CPATH" || echo "Conversion failed."
done < <(exec find "${MASTERFOLDER}" -mindepth 1 -type f -iname '*.tif')
Just replace echo convert "$FILE" "$CPATH" with the actual command you use and run bash script.sh masterfolder convertedfolder