errors running sh script [closed] - linux

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I keep getting these errors running my script and i just cannot work it out...
the error that keeps coming up is;
rm: cannot remove ~/my-documents/article:': Is a directory. The directory its referring to is $2...here is my script.
#! /bin/sh
SRC=$1
DES=$2
if [ $# -ne 2 ]; then
echo "1. Please enter the source directory"
echo "2. Please enter the destination directory"
echo "thankyou"
exit
fi
if [ ! -d $1 ]; then
echo "$1 is not a directory please enter a valid directory"
echo "thankyou"
exit
fi
#gives the user a error warning the source directory is invalid
if [ -d $2 ]; then
echo "output directory exists"
else
echo "Output directory does not exist, creating directory"
mkdir $2
fi
#creates the destination directory if one doesn't exist
IFILE=$GETFILES;
FINDFILE=$FINDFILE;
find $1 -name "*.doc" > FINDFILE
find $1 -name "*.pdf" > FINDFILE
find $1 -name "*.PDF" > FINDFILE
#finds doc, pdf & PDF files and sends data to findfile.
while read -r line;
do
cp $line $2
done < FINDFILE
#files read and copied to destination directory
IFILE=$2/$GETFILES;
ls -R $1 | egrep -i ".doc | .pdf" > IFILE;
LCOUNT=0
DIFFCOUNT=0
FOUND=0
ARCHIVE=1
BASE="${line%.*}"
EXTENSION="${line##*.}"
COUNT=$COUNT;
ls $2 | grep ${line%%.*} \; | wc -l
if [[ $COUNT -eq 0 ]];
then
cp $1/$line $2;
else
echo "there is already a file in the output so need to compare"
COMP=$2/$line
fi
while [[ $FOUND -eq 0 ]] && [[ $LCOUNT -lt $COUNT ]];
do
echo "diffcount is $DIFFCOUNT"
###compares the file from the input directory to the file in
###the output directory
if [ $DIFFCOUNT -eq 0 ];
then
echo "file has already been archived no action required"
FOUND=$FOUND [ $FOUND+1 ]
else
LCOUNT=$LCOUNT [ $LCOUNT+1 ]
COMP="OUT"/"$BASE"_"$LCOUNT"."$EXTENSION"
echo "line count for next compare is $LCOUNT"
echo "get the next file to compare"
echo "the comparison file is now $COMP"
fi
if [ $LCOUNT -ne $COUNT ]; then
ARCHIVE=$ [ $ARCHIVE+1 ]
else
ARCHIVE=0
fi
if [ $ARCHIVE -eq 0 ];
then
NEWOUT="OUT"/"$BASE"_"$LCOUNT"."$EXTENSION";
echo "newfile name is $NEWOUT"
cp $1/$LINE $NEWOUT
fi
done < $IFILE
rm $IFILE
OFILE=$2/DOCFILES;
ls $2 | grep ".doc" > $OFILE;
while read -r line;
do
BASE=${line%.*}
EXTENSION=${line##*.}
NEWEXTENSION=".pdf"
SEARCHFILE=$BASE$NEWEXTENSION
find $2 -name "$SEARCHFILE" -exec {} \;
done < $OFILE
rm $OFILE
### this will then remove any duplicate files so only
### individual .doc .pdf files will exist

a plain call to rm can only remove files, not directories.
$ touch /tmp/myfile
$ rm /tmp/myfile
$ mkdir /tmp/mydir
$ rm /tmp/mydir
rm: cannot remove ‘/tmp/mydir/’: Is a directory
You can remove directories by specifying the -d (to delete empty directories) or the -r (to delete directories and content recursively) flag:
$ mkdir /tmp/mydir
$ rm -r /tmp/mydir
$
this is well described in man rm.
apart from that, you seem to ignore quoting:
$ rm $OFILE
might break badly if the value of OFILE contains spaces, use quotes instead:
$ rm "${OFILE}"
and never parse the output of ls:
ls $2 | grep ".doc" > $OFILE
(e.g. if your "$2" is actually "/home/foo/my.doc.files/" it will put all files in this directory into $OFILE).
and then you iterate over the contents of this file?
instead, just use loop with file-globbing:
for o in "${2}"/*.doc
do
## loop code in here
done
or just do the filtering with find (and don't forget to call an executable with -exex):
find "$2" -name "$SEARCHFILE" -mindepth 1 -maxdepth 1 -type f -exec convertfile \{\} \;

Related

Backup script in bash

I need to write a script that will look for all files with the suffix ~ (eg file.txt ~) in current directory. If the script will find something, it should be copied to BACKUP directory.
If the BACKUP directory does not exist, the script should create it. If there is already a file (or other non-directory) named BACKUP, the script should report an error.
The problem is that on line if [ $x -eq BACKUP.* ];. Bash shows if [ $x -eq BACKUP.* ];
Appreciate any help
#!/bin/bash
if [ ! -d BACKUP ];
then
mkdir BACKUP;
fi
for x in *. *~ ; do
if [ $x -eq BACKUP.* ];
then
echo "Error, file BACKUP exist";
else
cp ./$x ./BACKUP;
fi
done
You mean something like that?
#!/bin/bash
BACKUP=./BACKUP
if [[ -e "$BACKUP" ]]; then
echo "$BACKUP already exists!" >&2
exit 1
fi
mkdir "$BACKUP"
find . -maxdepth 1 -type f -name "*~" -exec cp {} "$BACKUP" \;

File monitoring Bash script

I created this script for check whether specific files exist or not in the given location. but when I run this its always showing
Failed - Flag_lms_device_info_20160628.txt do not exist
Failed - Flag_lms_weekly_usage_info_20160628 do not exist
but both files are existing.
PREFIX="/opt/data"
REPORT="/tmp/report.txt"
DATE=$( date -d "${dtd} -1 days" +'%Y%m%d' )
rm -f "$REPORT"
FILENAME="Flag_lms_device_info_${DATE}.txt"
FULLFN="$PREFIX/$FILENAME"
if [ -f "$FULLFN" ]; then
echo "OK - $FILENAME exists" >> $REPORT
else
echo "Failed - $FILENAME do not exist" >> $REPORT
fi
FILENAME="Flag_lms_weekly_usage_info_${DATE}.txt"
FULLFN="$PREFIX/$FILENAME"
if [ -f "$FULLFN" ]; then
echo "OK - $FILENAME exists" >> $REPORT
else
echo "Failed - $FILENAME do not exist" >> $REPORT
fi
First of all, you have strange output in your question: your second line of output lacks a .txt extension. This might be an accident but if it's not it's worth investigating.
Assuming your date command is working correctly (I don't know that particular command), I would reduce your use of variables. In addition, I would use the -e test operator instead of -f because it's more inclusive. (If you haven't put data in the files yet, -f could return an error even if the file exists.) :
REPORT="/tmp/report.txt"
DATE=$( date -d "${dtd} -1 days" +'%Y%m%d' )
echo "" > "$REPORT" # Wipes file instead of completely removing it
filename="/opt/data/Flag_lms_device_info_$DATE.txt"
if [ -e "$filename" ]; then
echo "OK - Flag_lms_device_info_$DATE.txt exists" >> $REPORT
else
echo "Failed - Flag_lms_device_info_$DATE.txt doesn't exist" >> $REPORT
fi
filename="/opt/data/Flag_lms_weekly_usage_info_$DATE.txt"
if [ -e "$filename" ]; then
echo "OK - Flag_lms_weekly_usage_info_$DATE.txt exists" >> $REPORT
else
echo "Failed - Flag_lms_weekly_usage_info_$DATE.txt doesn't exist" >> $REPORT
fi
if [ -f "find "$FULLFN" -type f -name "$FILENAME"" ];then
Here you check for existance of a strange file named find... Use backquotes
if [ -f `find "$FULLFN" -type f -name "$FILENAME"` ];then
or, in bash,
if [ -f $(find "$FULLFN" -type f -name "$FILENAME") ];then
to get the command's output as a string.
Furthermore, your find invocation does not look promising. If you need to find a file named Flag_lms_device and so forth somewhere under /opt/data/, use find "$PREFIX" -type f -name "$FILENAME". If you know for sure that /opt/data is the exact location, then use
if [ -f "$FULLFN" ]
and you don't need to find the file.

Loop through filenames in folder and subfolders

#!/bin/bash
#sh j
find . -name "*first*" && echo "file found" || echo "file not found"
read -p "Run command $foo? [yn]" answer
case "$answer" in
y*) find . -type f -exec rename 's/(.*)\/(.*)first(.*)/$1\/beginning_$2changed$3/' {} + ;;
n*) echo "not renamed" ;;
esac
fi
I want the script to loop through folder and subfolders and find files that contain certain string and then have an option to rename the file or let it be(That is the y/n option) after selection the script should continue finding.
Also i have a problem that says "syntax error unexpected token 'fi' "
Try this:
#bin/bash
handle_file(){
local file=$0
local pattern=some_pattern
if [[ $(grep -c ${pattern} ${file}) -gt 0 ]];
then
......................................
do anything you want with your ${file}
......................................
fi
}
export -f handle_file
find . -type f -exec bash -c 'handle_file "$#"' {} \;
handle_file is a function that will be invoked as handle_function <filename>, so the <filename> is available as $0 inside the function.

remove files and prompt directories only

As I was deleting many obsolete file trees on a Linux machine I was wondering if there is an easy way to remove files recursively while prompting only on directories.
I could use rm -ri but there some much files that it would be really annoying to answer for every one of them. What really matter to me is being prompted on folders to have more control on what happens.
I am not a bash expert so I am asking if there is a simple way to do this.
Here is my attempt with a long bash script:
#!/bin/bash
promptRemoveDir()
{
fileCount=$(ls -1 $1 | wc -l)
prompt=1
while [ $prompt == 1 ]
do
read -p "remove directory: $1($fileCount files) ? [yl]: " answer
case $answer in
[yY])
rm -r $1
prompt=0
;;
l)
echo $(ls -A $1)
;;
*)
prompt=0
;;
esac
done
}
removeDir()
{
if [ "$(ls -A $1)" ]
then dirs=$(find $1/* -maxdepth 0 -type d)
fi
if [[ -z $dirs ]]
then
promptRemoveDir $1
else
for dir in $dirs
do
removeDir $dir
done
promptRemoveDir $1
fi
}
for i in $*
do
if [ -d $i ]
then
removeDir $i
else
rm $i
fi
done
If i understand your question properly this should work
Dirs=$(find . -type d)
Removes just the files in the directories specified
for i in "$Dirs"; do read -p "Delete files in "$i": ";if [[ $REPLY == [yY] ]]; then find $i -maxdepth 1 -type f | xargs -0 rm ; fi ;done
If you want to delete the folders as well, this will read from lowest directory(none below it) upwards.
for i in $(echo "$Dirs" | sed '1!G;h;$!d' ); do read -p "Delete files in $i: ";if [[ $REPLY == [yY] ]]; then rm -r "$i"; fi ;done
Here's a simplified version from me. There's no need to use ls and find.
#!/bin/bash
shopt -s nullglob
shopt -s dotglob
function remove_dir_i {
local DIR=$1 ## Optional. We can just use $1.
local SUBFILES=("$DIR"/*) FILE
for (( ;; )); do
read -p "Remove directory: $DIR (${#SUBFILES[#]} files)? [YNLQ]: "
case "$REPLY" in
[yY])
echo rm -fr "$DIR"
return 0
;;
[nN])
for FILE in "${SUBFILES[#]}"; do
if [[ -d $FILE ]]; then
remove_dir_i "$FILE" || return 1
# else
# ## Apparently we skip deleting a file. If we do this
# ## we could actually simplify the function further
# ## since we also delete the file at first loop.
# # echo "Removing file \"$FILE.\""
# # rm -f "$FILE"
fi
done
return 0
;;
[lL])
printf '%s\n' "${SUBFILES[#]}"
;;
[qQ])
return 1
;;
# *)
# echo "Please answer Y(es), N(o), L(ist) or Q(uit)."
# ;;
esac
done
}
for FILE; do
if [[ -d $FILE ]]; then
remove_dir_i "$FILE"
else
# echo "Removing file \"$FILE.\""
echo rm -f "$FILE"
fi
done
Remove echo from rm commands when you're sure it's working already. Test:
rm -f /tmp/tar-1.27.1/ABOUT-NLS
rm -f /tmp/tar-1.27.1/acinclude.m4
rm -f /tmp/tar-1.27.1/aclocal.m4
rm -f /tmp/tar-1.27.1/AUTHORS
Remove directory: /tmp/tar-1.27.1/build-aux (12 files)? [YNLQ]: n
Remove directory: /tmp/tar-1.27.1/build-aux/snippet (5 files)? [YNLQ]: n
rm -f /tmp/tar-1.27.1/ChangeLog
rm -f /tmp/tar-1.27.1/ChangeLog.1
rm -f /tmp/tar-1.27.1/config.h.in
rm -f /tmp/tar-1.27.1/configure
rm -f /tmp/tar-1.27.1/configure.ac
rm -f /tmp/tar-1.27.1/COPYING
Remove directory: /tmp/tar-1.27.1/doc (25 files)? [YNLQ]: n
Remove directory: /tmp/tar-1.27.1/gnu (358 files)? [YNLQ]: n
Remove directory: /tmp/tar-1.27.1/gnu/uniwidth (2 files)? [YNLQ]: n
rm -f /tmp/tar-1.27.1/INSTALL
Remove directory: /tmp/tar-1.27.1/lib (19 files)? [YNLQ]:
...
Actually I just came upon the -depth option of the find command that is exactly what I was looking for. I can't believe I just missed that:
-depth Process each directory's contents before the directory itself. The -delete action also implies -depth.
So similar to #Jidder's code, I can write this:
dirs=$(find ./test_script -depth -type d); for i in $dirs; do read -p "Delete files in $i? " REPLY; if [[ $REPLY == [yY] ]]; then rm -r $i; fi; done;
And for more readability:
dirs=$(find ./test_script -depth -type d)
for i in $dirs
do
read -p "Delete files in $i? " REPLY
if [[ $REPLY == [yY] ]]
then rm -r $i
fi
done;

Archive old files only AND re-construct folder tree in archive

I want to move all my files older than 1000 days, which are distributed over various subfolders, from /home/user/documents into /home/user/archive. The command I tried was
find /home/user/documents -type f -mtime +1000 -exec rsync -a --progress --remove-source-files {} /home/user/archive \;
The problem is, that (understandably) all files end up being moved into the single folder /home/user/archive. However, what I want is to re-construct the file tree below /home/user/documents inside /home/user/archive. I figure this should be possible by simply replacing a string with another somehow, but how? What is the command that serves this purpose?
Thank you!
I would take this route instead of rsync:
Change directories so we can deal with relative path names instead of absolute ones:
cd /home/user/documents
Run your find command and feed the output to cpio, requesting it to make hard-links (-l) to the files, creating the leading directories (-d) and preserve attributes (-m). The -print0 and -0 options use nulls as record terminators to correctly handle file names with whitespace in them. The -l option to cpio uses links instead of actually copying the files, so very little additional space is used (just what is needed for the new directories).
find . -type f -mtime +1000 -print0 | cpio -dumpl0 /home/user/archives
Re-run your find command and feed the output to xargs rm to remove the originals:
find . -type f -mtime +1000 -print0 | xargs -0 rm
Here's a script too.
#!/bin/bash
[ -n "$BASH_VERSION" ] && [[ BASH_VERSINFO -ge 4 ]] || {
echo "You need Bash version 4.0 to run this script."
exit 1
}
# SOURCE=/home/user/documents/
# DEST=/home/user/archive/
SOURCE=$1
DEST=$2
declare -i DAYSOLD=10
declare -a DIRS=()
declare -A DIRS_HASH=()
declare -a FILES=()
declare -i E=0
# Check directories.
[[ -n $SOURCE && -d $SOURCE && -n $DEST && -d $DEST ]] || {
echo "Source or destination directory may be invalid."
exit 1
}
# Format source and dest variables properly:
SOURCE=${SOURCE%/}
DEST=${DEST%/}
SOURCE_LENGTH=${#SOURCE}
# Copy directories first.
echo "Creating directories."
while read -r FILE; do
DIR=${FILE%/*}
if [[ -z ${DIRS_HASH[$DIR]} ]]; then
PARTIAL=${DIR:SOURCE_LENGTH}
if [[ -n $PARTIAL ]]; then
TARGET=${DEST}${PARTIAL}
echo "'$TARGET'"
mkdir -p "$TARGET" || (( E += $? ))
chmod --reference="$DIR" "$TARGET" || (( E += $? ))
chown --reference="$DIR" "$TARGET" || (( E += $? ))
touch --reference="$DIR" "$TARGET" || (( E += $? ))
DIRS+=("$DIR")
fi
DIRS_HASH[$DIR]=.
fi
done < <(exec find "$SOURCE" -mindepth 1 -type f -mtime +"$DAYSOLD")
# Copy files.
echo "Copying files."
while read -r FILE; do
PARTIAL=${FILE:SOURCE_LENGTH}
cp -av "$FILE" "${DEST}${PARTIAL}" || (( E += $? ))
FILES+=("$FILE")
done < <(exec find "$SOURCE" -mindepth 1 -type f -mtime +"$DAYSOLD")
# Remove old files.
if [[ E -eq 0 ]]; then
echo "Removing old files."
rm -fr "${DIRS[#]}" "${FILES[#]}"
else
echo "An error occurred during copy. Not removing old files."
exit 1
fi

Resources