I am making 2 scripts. The first script is going to take a file, and then move it to a directory named "Trash". The second script will recover this file and send it back to it's original directory. So far I have the first script moving the file correctly.
Here is my code so far:
For delete.sh
FILE=$1
DATEDELETED=$(date)
DIRECTORY=$(pwd)
mv $1 Trash
echo $FILE
echo $DATEDELETED
echo $DIRECTORY
Output:
trashfile
Sun Mar 2 21:37:21 CST 2014
/home/user
For undelete.sh:
PATH=/home/user/Trash
for file in $PATH
do
$file | echo "deleted on" | date -r $file
done
echo "Enter the filename to undelete from the above list:"
EDIT: So I realized that I don't need variables, I can just list all the files in the Trash directory and edit the output to what I want. I'm having a little trouble with my for statement though, I'm getting these two errors: ./undelete.sh: line 6: date: command not found
./undelete.sh: line 6: /home/user/Trash: Is a directory. So I'm not exactly sure what I'm doing wrong in my for statement.
Here is the expected output:
file1 deleted on Tue Mar 16 17:15:34 CDT 2010
file2 deleted on Tue Mar 16 17:15:47 CDT 2010
Enter the filename to undelete from the above list:
Well I've accomplished what could be a workaround for what your scenario is trying to accomplish.
Basically you can enter echo "script2variable=$script1variable" >> script2.sh from script1.sh. Then use the source command to call that script later from any script you desire. Might have to just play with the theories involved.
Good Luck!
Delete Script file
#!/bin/bash
# delete.sh file
# Usage: ./delete.sh [filename]
#DATEDELETED=$(date) #not best solution for this kind of application
DIR=$(pwd)
fn=$1
#Specify your trash directory or partition
trash=~/trash
#Set path and filename for simple use in the script
trashed=$trash/$fn.tgz
#Send variables to new manifest script.
echo "#!/bin/bash" > $1.mf.sh
echo "DIR=$DIR" >> $1.mf.sh
# Questionable need?
#echo "DATEDELETED=$DATEDELETED" >> $1.mf.sh
echo "mv $1 $DIR" >> $1.mf.sh
echo Compressing
tar -cvpzf $trashed $1 $1.mf.sh
if [ $? -ne 0 ]; then
echo Compression Failed
else
echo completed trash compression successfully
echo Trashbin lists the file as $trashed
rm $1 -f
rm $1.mf.sh -f
echo file removed successfully
fi
exit 0
Restore Script File
#!/bin/bash
# restore.sh
# Usage: ./restore.sh
# filename not required for this script, use index selection
fn=$1
#SET LOCATION OF TRASH DIRECTORY
trash=~/trash
listfile=($(ls $trash))
#SET COUNTER FOR LISTING FILES = 0
i=0
#THIS IS JUST A HEADER FOR YOUR OUTPUT.
clear #cleanup your shell
echo -e INDEX '\t' Filename '\t' '\t' '\t' Date Removed
#Echo a list of files from the array with the counter.
for FILES in "${listfile[#]}"
do
echo -e $i '\t' $FILES '\t' "deleted on $(date -r $trash/$FILES)"
let "i += 1"
done
#Output total number of items from the ls directory.
echo -e '\n' $i file\(s\) found in the trash!
# 1 Offset for 1 = 0, 2 = 1, and so on.
let "i -= 1"
#Require input of a single, double, or triple digit number only.
#Loop back prompt if not a number.
while true;
do
read -p "Enter an index number for file restoration: " indx
case $indx in
[0-9]|[0-9][0-9]|[0-9][0-9][0-9] ) break ;;
* ) read -p "Please enter a valid number 0-$i: " indx ;;
esac
done
#
script=$(echo ${listfile[$indx]}|sed 's/\.tgz/\.mf.sh/g')
tar -xvpzf $trash/${listfile[$indx]}
rm $trash/${listfile[$indx]}
sleep 2
chmod +x $script
source $script
rm $script
Run the script with source
source <yourscript>
or
. ./<yourscript>
In your case
. ./delete.sh && ./undelete.sh
Hope this will help
Related
I have some files stored on a server. I have to get all those files using a pattern and exclude the file which contains the current date as the file name.
Files are given below
/var/tomcat/logs/catalina.2022-05-11.log
/var/tomcat/logs/catalina.2022-05-13.log
/var/tomcat/logs/catalina.2022-05-14.log
/var/tomcat/logs/catalina.2022-05-16.log
/var/tomcat/logs/error_1.log
/var/tomcat/logs/error_2.log
/var/tomcat/logs/error_3.log
/var/tomcat/logs/error_4.log
For this, I have stored patterns in a file and I want to read the pattern of that file and find all files with the help of those patterns.
Pattern Input File content is given below, in below I have used '%Y-%m-%d' to identify the date format so that I can exclude the current date file.
/var/tomcat/logs/catalina.*.log;%Y-%m-%d
/var/tomcat/logs/error_*.log
I have developed a shell script which is given below
#!/bin/sh
pattern_filepath=$1
while IFS= read -r line || [ -n "$line" ]; do
pattern_var="$line"
echo pattern: "$pattern_var"
filepath=""
date_format=""
if [[ $pattern_var == *";"* ]];
then
echo "Semicolons ; separator is there"
filepath=($(echo "$pattern_var" | cut -f1 -d ';'))
echo filepath: "$filepath"
date_format=($(echo "$pattern_var" | cut -f2 -d ';'))
else
echo "Semicolons ; separator is not there"
filepath=$pattern_var
fi
echo "date_format: "$date_format
done < "$pattern_filepath"
Command to run the script
sh /var/monitoring/test.sh "/var/monitoring/pattern" > /var/monitoring/test.log
Inside the log file, I can see, that in the file path variable I am getting the value as a date but that should be with an asterisk instead of a date.
Log file 'test.log'
pattern: /var/tomcat/logs/catalina.*.log;%Y-%m-%d
Semicolons ; separator is there
filepath: /var/tomcat/logs/catalina.2022-05-11.log
date_format: %Y-%m-%d
pattern: /var/tomcat/logs/error_*.log
Semicolons ; separator is not there
date_format:
Please help me with this, how can I achieve this?
Simple, straight to the point. Achieves the requirement, without the complexity of patterns, or lists, or ...
#!/bin/bash
sourcedir="/var/tomcat/logs"
if [[ ! -d "$sourcedir" ]]
then
echo "ERROR: source directory $sourcedir does not exist."
exit 1
fi
targetdir="/tmp/somedir"
if [[ ! -d "$targetdir" ]]
then
echo "ERROR: target directory $targetdir does not exist."
exit 1
fi
# Get the catalina logs
cp "$sourcedir"/catalina.*.log "$targetdir"
# Remove the catalina log for today
filetoremove="$targetdir"/catalina.$(date +%Y-%m-%d).log
if [[ -f "$filetoremove" ]]
then
rm -f "$filetoremove"
fi
# Get the error logs
cp "$sourcedir"/error_*.log "$targetdir"
You can add error checking and recovery for the cp and rm commands.
The last thing I want to do in this script is take the userinput to rename the corresponding files to include .bak extension rather then .txt which will copy into a backup directory. I keep receiving an error messaging saying e.g.
mv: cannot stat '5.bak': No such file or directory
The snippet in question (right at the bottom of full code):
for i in ~/students/Stu$userinput/*_$userinput.txt;
do
mkdir -p ~/students/Backup; mv -- "$i" "${userinput%.txt}.bak" ~/students/Backup; #Change extension.
done
Full code:
#!/bin/bash
echo "Current User: $USER" >> system_info.txt #Inputs current user in .txt file.
echo "Current Directory: $PWD" >> system_info.txt #Inputs current user directory in .txt file.
#Creating the directory structure in the users home directory.
for i in {1..20}; #Create sub-directory of Stu from 1 to 20.
do
mkdir -p archive students/Stu${i}; #Two new dirctories created, with Stu having sub directories represented by {i},
done
i=1 #{i} to begin at 1.
until ((i>20)) #Each loop to check if i is greater than 20.
do
touch ~/students/Stu${i}/Notes_$i.txt #Creates a Notes page for every i up to 20.
touch ~/students/Stu${i}/Results_$i.txt #Similarily, creates a txt file for Results_$ up untill 20.
((i++))
done
for i in {1..20}; do #This is to echo the required sentence howcasing the current filename, user in the corresponding directory.
filename=~/students/Stu${i}/Notes_$i.txt
touch "$filename"
echo "The $(basename -- "$filename") file belonging to $USER was created in the Stu${i}." >> ~/students/Stu${i}/Notes_$i.txt
done
for i in {1..20}; do #This is to echo the required sentence howcasing the current filename, user in the corresponding directory.
filename=~/students/Stu${i}/Notes_$i.txt
touch "$filename"
echo "The $(basename -- "$filename") file belonging to $USER was created in the Stu${i}." >> ~/students/Stu${i}/Notes_$i.txt
done
for i in {1..20}; do
file_name=~/students/Stu${i}/Results_$i.txt
touch "$file_name"
echo "The $(basename -- "$file_name") file belonging to $USER was created in the Stu${i}." >> ~/students/Stu${i}/Results_$i.txt
done
while true;
do
echo -n "File to change: "
read userinput #Sets variable
if [ "$userinput" -ge 1 ] && [ "$userinput" -le 20 ];then #If userinput is greater than or equal to 1 or lss than or equal to 20/
echo "Valid number! File changed." #If fits crities, let user kniw
break
else #If critriea doesnt meet, try again.
echo "Invalid! File number must be between 1-20. Please try again."
fi
done
for i in ~/students/Stu$userinput/*_$userinput.txt;
do
mkdir -p ~/students/Backup; mv -- "$i" "${userinput%.txt}.bak" ~/students/Backup; #Change extension.
done
echo $?
The correct one would be
cp $i ~/students/Backup/$(basename ${i%.txt}.bak);
Note: mkdir -p ~/students/Backup is not needed to put in the loop
I have a folder with 20000 files in directory A and another folder
with 15000 file in another directory B i can loop through a directory
using:
DIR='/home/oracle/test/forms1/'
for FILE in "$DIR"*.mp
do
filedate=$( ls -l --time-style=+"date %d-%m-%Y_%H-%M" *.fmx |awk '{print $8 $7}')
echo "file New Name $FILE$filedate "
# echo "file New Name $FILE is copied "
done
I need to loop through all the files in directory A and check if they
exist in directory B
I tried the following but it doesn't seem to work:
testdir='/home/oracle/ideatest/test/'
livedir='/home/oracle/ideatest/live/'
for FILET in "$testdir" #
do
testfile=$(ls $FILET)
echo $testfile
for FILEL in "$livedir"
do
livefile=$(ls $FILEL)
if [ "$testfile" = "$livefile" ]
then
echo "$testfile"
echo "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
else
echo "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
fi
done
done
i'am trying to fix the result of years of bad version control we have
that very oly script that send a form to live enviorment but every
time it's compiled and sent the live version is named like
(testform.fmx) but in test dir there is like 10 files named like
(testform.fmx01-12-2018)
(testform.fmx12-12-2017)(testform.fmx04-05-2016) as a reuslt we lost
track of the last source sent to live enviroment that's why i created
this
filedate=$( ls -l --time-style=+"date %d-%m-%Y_%H-%M" *.fmx |awk
'{print $8 $7}')
echo "file New Name $FILE$filedate "
to match the format and loop through each dir and using ls i can find the last version by matching the size and the year and month
You can basicly use diff command to compare the files and directories. diff folderA folderB
I think you do not really need to use a loop for that..
If really you want to use a loop around, you may want to compare the files as well.
#!/bin/bash
DIR1="/home/A"
DIR2="/home/B"
CmpCmn=/usr/bin/cmp
DiffCmn=/usr/bin/diff
for file1 in $DIR1/*; do #Get the files under DIR1 one by one
filex=$(basename $file1) #Get only the name ofthe ile
echo "searching for $filex"
$DiffCmn $filex $DIR2 #Check whether the file is under DIR2 or not
if [ $? -ne 0 ]
then
echo " No file with $filex name under $DIR2 folder"
else
echo " $filex exists under $DIR2"
$CmpCmn $file1 $DIR2/$filex #Compare if the files are exactly same
if [ $? -ne 0 ]
then
echo " $filex is not same"
else
echo " $filex is the same"
fi
fi
done
This code is based on the code in the question:
testdir='/home/oracle/ideatest/test/'
livedir='/home/oracle/ideatest/live/'
shopt -s nullglob # Globs that match nothing expand to nothing
shopt -s dotglob # Globs match files whose names start with '.'
for testpath in "$testdir"*
do
[[ -f $testpath ]] || continue # Skip non-files
testfile=${testpath##*/} # Get file (base) name
printf '%s\n' "$testfile"
livepath=${livedir}${testfile} # Make path to (possible) file in livedir
if [[ -f $livepath ]]
then
printf '%s\n' "$testfile"
echo "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
else
echo "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
fi
done
You need to find files that are common in both A and B directories.
comm -12 \
<(cd A && find . -type f -maxdepth 1 | sort) \
<(cd B && find . -type f -maxdepth 1 | sort)
Live version available at tutorialspoint.
How it works? find's list the files in both A and B directories and comm displays only files/lines common in both inputs. comm needs input to be sorted, that's why | sort
Don't parse ls output. ls is for nice, formatted output. Use find . and parse it's output.
I am checking if the files have been modified and I need to echo what new strings have been added. When I try this script for a single file it works, but when I iterate through multiple files in a directory it does not work as it should. Any suggestion?
#! /bin/bash
GAP=5
while :
do
FILES=/home/Desktop/*
for f in $FILES
do
len=`wc -l $f | awk '{ print $1 }'`
if [ -N $f ]; then
echo "`date`: New entries in $f:"
newlen=`wc -l $f | awk '{ print $1 }'`
newlines=`expr $newlen - $len`
tail -$newlines $f
len=$newlen
fi
sleep $GAP
done
done
Continuing from the comments, here is the original solution I envisioned using inotifywait (from the inotify-tools package) and an associative array. The benefit here is inotifywait will block and will not waste resources endlessly checking the line count of each file on each loop iteration. I'll work on a solution using a temporary file, but when you go that route you open yourself up to a change occurring in between loop iterations. Here is the first solution:
#!/bin/bash
watchdir="${1:-$PWD}"
events="-e modify -e attrib -e close_write -e create -e delete -e move"
declare -A lines
for i in "$watchdir"/*; do
[ -f "$i" ] && lines[$i]=$(wc -l <"$i")
done
while :; do ## watch for changes in chosen dir
fname="${watchdir}/$(inotifywait -q $events --format '%f' "$watchdir")"
newlc=$(wc -l <"$fname") ## get line count for changed file
if [ "${lines[$fname]}" -ne "$newlc" ]; then ## if changed, print
printf " lines chanaged : %s -> %s (%s)\n" \
"${lines[$fname]}" "$newlc" "$fname"
lines[$fname]=$newlc ## update saved line count for file
fi
done
Original testfile.txt
$ cat dat/tmp/testfile.txt
1 1.2
2 2.2
Example Use/Output
Script saved in watchdir.sh. Start watchdir.sh so inotifywait is watching the dat/tmp directory
$ ./watchdir.sh dat/tmp
Using a second terminal, modify file in the dat/tmp directory
$ echo "newline" >> ~/scr/tmp/stack/dat/tmp/testfile.txt
$ echo "newline" >> ~/scr/tmp/stack/dat/tmp/testfile.txt
Output of watchdir.sh running in separate terminal (or background)
$ ./watchdir.sh dat/tmp
lines chanaged : 2 -> 3 (dat/tmp/testfile.txt)
lines chanaged : 3 -> 4 (dat/tmp/testfile.txt)
Resulting testfile.txt
$ cat dat/tmp/testfile.txt
1 1.2
2 2.2
newline
newline
Second Solution Using [ -N file ]
Here is a second solution a bit closer to your first attempt. It is a less robust way to approach the solution (it will miss multiple changes between tests, etc.). Look it over and let me know if you have questions
#!/bin/bash
watchdir="${1:-$PWD}"
gap=5
tmpfile="$TMPDIR/watchtmp" ## temp file in system $TMPDIR (/tmp)
:>"$tmpfile"
trap 'rm $tmpfile' SIGTERM EXIT ## remove tmpfile on exit
for i in "$watchdir"/*; do ## populate tmpfile with line counts
[ -f "$i" ] && echo "$i,$(wc -l <"$i")" >> "$tmpfile"
done
while :; do ## loop every $gap seconds
for i in "$watchdir"/*; do ## for each file
if [ -N "$i" ]; then ## check changed
cnt=$(wc -l <"$i") ## get new line count
oldcnt=$(grep "$i" "$tmpfile") ## get old count
oldcnt=${oldcnt##*,}
if [ "$cnt" -ne "$oldcnt" ]; then ## if not equal, print
printf " lines chanaged : %s -> %s (%s)\n" \
"$oldcnt" "$cnt" "$i"
## update tmpfile with new count
sed -i "s|^${i}[,][0-9][0-9]*.*$|${i},$cnt|" "$tmpfile"
fi
fi
done
sleep $gap
done
Use/Output
Start watchdir.sh
$ ./watchdir2.sh dat/tmp
In second terminal modify file
$ echo "newline" >> ~/scr/tmp/stack/dat/tmp/testfile.txt
wait for $gap to expire (if changed twice - it will not register)
$ echo "newline" >> ~/scr/tmp/stack/dat/tmp/testfile.txt
Results
$ ./watchdir2.sh dat/tmp
lines chanaged : 10 -> 11 (dat/tmp/testfile.txt)
lines chanaged : 11 -> 12 (dat/tmp/testfile.txt)
I am trying to make a simple backup script and i have problem creating a folder with the curent date for name
My script is that and basically the problem is on the last line
drivers=$(ls /media/)
declare -i c=0
for word in $drivers
do
echo "($c)$word"
c=c+1
done
read -n 1 drive
echo
c=0
for word in $drivers
do
if [ $c -eq $drive ]
then
backuppath="/media/$word/backup"
fi
c=c+1
done
echo "doing back up to $backuppath"
cp -r /home/stefanos/Programming $backuppath/$(date +%Y-%m-%d-%T)
Ouput:
(0)0362-BA96
(1)Data
(2)Windows
0
doing back up to /media/0362-BA96/backup
cp: cannot create directory `/media/0362-BA96/backup/2012-12-05-21:58:37': Invalid argument
The path is triply checked that is existing until /media/0362-BA96/
SOLVED:
Did what janisz said the final script looks like
drivers=$(ls /media/)
declare -i c=0
for word in $drivers
do
echo "($c)$word"
c=c+1
done
read -n 1 drive
echo
c=0
for word in $drivers
do
if [ $c -eq $drive ]
then
backuppath="/media/$word/backup"
fi
c=c+1
done
echo "doing back up to $backuppath"
backup(){
time_stamp=$(date +%Y_%m_%d_%H_%M_%S)
mkdir -p "${backuppath}/${time_stamp}$1"
cp -r "${1}" "${backuppath}/${time_stamp}$1"
echo "backup complete in $1"
}
#####################The paths to backup####################
backup "/home/stefanos/Programming"
backup "/home/stefanos/Android/Projects"
backup "/home/stefanos/Dropbox"
Trying changing it to:
time_stamp=$(date +%Y-%m-%d-%T)
mkdir -p "${backuppath}/${time_stamp}"
cp -r /home/stefanos/Programming "${backuppath}/${time_stamp}"
: is not valid on FAT (it is used to specify disk). Some of M$ invalid character works on GNU/Linux systems but it is safer to avoid them (just replace with .). Use following date format
date +%Y_%m_%d_%H_%M_%S
It should works on most file systems but it could be too long for MS DOS FAT. More info you will find here.