LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices



Reply
 
Search this Thread
Old 09-28-2012, 04:48 PM   #1
calvarado777
LQ Newbie
 
Registered: Sep 2012
Posts: 20

Rep: Reputation: Disabled
Unhappy File Comparison with fstat()


Hello all! I am working on part2 of an assignment--2nd week learning scripting so I'm sure what I have so far is not super efficient..baby steps though! I really want to understand what I am writing so I would appreciate any explanations :-)

My script is supposed to take in only 2 directories as arguments, and exit if there aren't 2 or if the arguments are not directories or they don't exist.
(I think I have this part right!)

Then I am supposed to compare the 2 directories, if bar2 has files that are not in bar1 I need to copy them over. If bar1 has a file named the same as one in bar2, the file gets copied over to bar1 ONLY if the one in bar2 is newer (or more recently modified)

So this is where my code is at so far...my instructor suggested I use fstat to compare the times of the files in question, however I am not too sure how to implement it..here is the code...questions will follow

Code:
#!/bin/sh

EXPECTED_NUM_ARGS=2

die () {
        echo >&2 "$@"
        exit 1
}

if [ $# -ne $EXPECTED_NUM_ARGS ]
then
        echo "Invalid number of arguments!"
        exit
fi

[ -d "$1" ] || die "Directory $1 does not exist. "      #return true if arg is a directory or dies
[ -d "$2" ] || die "Directory $2 does n't exist. "
[ -w "$1" ] || die "You are not allowed to do that! " #return true if user can write or dies
[ -w "$2" ] || die "You can't do that! "

#cp --no-clobber $2 $1

cd $2

for FILE in `find . -type f`
do
        if [ ! -e $1/$FILE ]
        then
        cp $FILE $1/$FILE
        elif [ -e $1/$FILE]
        then 
                timeInBar1 = fstat $1/$FILE
                timeInBar2 = fstat $2/$FILE
                if [ timeInBar2 > timeInBar1 ]
                then
                        cp $FILE $1/$FILE
         
        fi
done     
        
exit
so I am not too sure about the syntax when I am creating the variables for the fstat result, in addition, I can't really figure out how I am supposed to just pull out the time information?

Man pages show
Code:
fstat(int fildes, struct stat *buf);
but that confuses me even more...

can anyone point me in the right direction?

Thanks so much! you guys are awesome!!
 
Old 09-29-2012, 10:31 AM   #2
nugat
Member
 
Registered: Sep 2012
Posts: 122

Rep: Reputation: 31
that fstat info looks like a C library function or call, not a userspace program. Instead, you could use the binary "stat" for getting file information, e.g.:

Code:
stat /etc/hosts
that will dump a mess of info about the file /etc/hosts.

You could just print a given attribute, though, say last modified time (in seconds since the Epoch), like this:

Code:
stat -c %Y /etc/hosts
that will give you a number (seconds) that you can easily use in calculation with other files.

Of course, another way is to just use rsync...
 
Old 09-29-2012, 12:03 PM   #3
calvarado777
LQ Newbie
 
Registered: Sep 2012
Posts: 20

Original Poster
Rep: Reputation: Disabled
Unhappy Copy problem

Ah yes! Thanks for the heads up on stat! I was apparently looking at system man pages and I didn't really understand the difference between the two... so I have the program running without error, however, I have now run into an issue with my copy...

When I call the script from the command line, I call ./scriptName dir1 dir2

I have set up these two dummy directories to make sure everything works. I have one file inside of dir2 to first check and see that the copy from dir2 to dir1 is actually working...but something really funny happens...

When I correctly call it as I think I should ./scriptName dir1 dir2 -- I get an error saying
Code:
cp: cannot create regular file `bar1/./fileInBar2First.c': No such file or directory
I then switched around the directories to see what would happen and called ./scriptName dir2 dir1
and I did not get the same error (cause there was no file to copy)

However, it is just not doing what I want...can anyone see my mistake? Thanks!!

Here is the code again as I have it so far

Code:
#!/bin/sh

EXPECTED_NUM_ARGS=2

die () {
        echo >&2 "$@"
        exit 1
}

if [ $# -ne $EXPECTED_NUM_ARGS ]
then
        echo "Invalid number of arguments!"
        exit
fi

[ -d "$1" ] || die "Directory $1 does not exist. "      #return true if arg is a directory or dies
[ -d "$2" ] || die "Directory $2 does n't exist. "
[ -w "$1" ] || die "You are not allowed to do that! " #return true if user can write or dies
[ -w "$2" ] || die "You can't do that! "

cd $2

for FILE in `find . -type f`
do
        if [ ! -e $1/$FILE ]
        then
        cp $FILE $1/$FILE
        elif [ -e $1/$FILE]
        then
                timeInBar1 = `stat -c %Y $1/$FILE`      #%Y gives seconds 
                timeInBar2 = `stat -c %Y $2/$FILE`
                if [ timeInBar2 > timeInBar1 ]
                then
                        cp $FILE $1/$FILE
                fi
        fi
done

exit
 
Old 09-29-2012, 12:18 PM   #4
nugat
Member
 
Registered: Sep 2012
Posts: 122

Rep: Reputation: 31
try using the absolute paths to the directories.

also, you should probably limit the find to the one directory and not be recursive.

Code:
dir1=$(readlink -f $1)
dir2=$(readlink -f $2)

cd $dir2

for FILE in `find . -mindepth 1 -maxdepth 1 -type f`; do
  if ! [ -e $dir1/$FILE ]; then
    cp $FILE $dir1/$FILE
  elif [ -e $dir1/$FILE ]; then
    timeInBar1 = `stat -c %Y $dir1/$FILE`      #%Y gives seconds 
    timeInBar2 = `stat -c %Y $dir2/$FILE`
    if [ timeInBar2 > timeInBar1 ]; then
      cp $FILE $dir1/$FILE
    fi
  fi
done
 
Old 09-29-2012, 12:22 PM   #5
calvarado777
LQ Newbie
 
Registered: Sep 2012
Posts: 20

Original Poster
Rep: Reputation: Disabled
ok so I changed
for FILE in `find . -type f` to for FILE in `find * -type f`

and that takes away the extra ./ in the path but I am still getting the same error ...
 
Old 09-29-2012, 03:56 PM   #6
calvarado777
LQ Newbie
 
Registered: Sep 2012
Posts: 20

Original Poster
Rep: Reputation: Disabled
Talking Fantastic!!

Thanks so much! It works flawlessly! Can I ask you a couple questions regarding some of the reasoning behind your changes so that I can understand?

1) is there an advantage to letting variables hold the arguments?
you show this
Code:
dir1=$(readlink -f $1)
      dir2=$(readlink -f $2)
and also, the way I read this is "let variable dir1 equal the 1st argument which is passed in...and you are using readlink because we know that the arguments being passed on are going to be directories--which are soft or symbolic links. -f refers to the format which says it should be a file." *** why is this not a -d to indicate that the file type will be a directory, not just a file?**

2)
Code:
for FILE in `find . -mindepth 1 -maxdepth 1 -type f`;
The above statement as you mentioned won't be recursive and it will only search for file in the current directory and not any sub-directories correct?

3) does moving the "!" outside the bracket mean to negate the output of the following test? why can it not remain inside the brackets?

Thanks so much for your help!! I think I may get to enjoy a little of my weekend now!
 
Old 09-29-2012, 04:19 PM   #7
calvarado777
LQ Newbie
 
Registered: Sep 2012
Posts: 20

Original Poster
Rep: Reputation: Disabled
Question I spoke too soon!

I thought it was working...and then I started to play around with testing it to make sure everything was being copied over,
and at some point it stopped recognizing the stat command?

my error shows this
Code:
line 31: timeInBar1: command not found
line 32: timeInBar2: command not found
which are these lines
Code:
timeInBar1 = `stat -c %Y $dir1/$FILE`      #%Y gives seconds 
    timeInBar2 = `stat -c %Y $dir2/$FILE`

I don't understand what happened? I don't think that it lost the path to where the commands are...because all of the other commands aren't giving me errors...I'm so confused! I did change the name of the file after I had run it and it worked to match what the requirements were but that shouldn't make a difference right?

UPDATE!! This error ONLY occurs if I have a file by the same name in bar1 and bar2. If I made a change to the file in Bar 2, the script should compare the two timestamps and rewrite the file only if the version in bar2 is newer. I didn't notice the bug the first time I ran it because the script never actually made it to that part of the code since I initially had bar1 empty.

Any ideas?

Last edited by calvarado777; 09-29-2012 at 05:08 PM. Reason: update from last question
 
Old 09-29-2012, 05:56 PM   #8
calvarado777
LQ Newbie
 
Registered: Sep 2012
Posts: 20

Original Poster
Rep: Reputation: Disabled
Thumbs up Figured it out!

This is the final code that ended up working nicely for me...I was never able to get the stat to work properly and my comparison of files changed slightly. Thanks to all for your help and suggestions!

Code:
EXPECTED_NUM_ARGS=2

die () {                                                #die function
        echo >&2 "$@"
        exit 1
}

if [ $# -ne $EXPECTED_NUM_ARGS ]                        #argument number condition -> must be == 2 arguements ONLY
then
        echo "Invalid number of arguments!"
        exit
fi

[ -d "$1" ] || die "Directory $1 does not exist. "      #return true if arg is a directory or dies
[ -d "$2" ] || die "Directory $2 doesn't exist. "
[ -w "$1" ] || die "You are not allowed to do that! "    #return true if user can write or dies
[ -w "$2" ] || die "You can't do that! "


dir1=$(readlink -f $1)                                  #variable for arg1 - uses readlink for softlink -> directory
dir2=$(readlink -f $2)

cd $dir2                                                #change directories

for FILE in `find . -mindepth 1 -maxdepth 1 -type f`; do        #extra condition, do not recurse into subdirectories
        if ! [ -e $dir1/$FILE ]; then                           #if the file doesn't exist in the 1st directory, copy the file in
                cp $FILE $dir1/$FILE
        elif [ -e $dir1/$FILE ]; then                           #if the file does exist, only copy if it's newer
                if [ $dir2/$FILE -nt $dir1/$FILE ]; then
                        cp $FILE $dir1/$FILE
                fi
        fi
done

exit 0
 
Old 09-30-2012, 02:25 PM   #9
nugat
Member
 
Registered: Sep 2012
Posts: 122

Rep: Reputation: 31
Quote:
Originally Posted by calvarado777 View Post
I thought it was working...and then I started to play around with testing it to make sure everything was being copied over,
and at some point it stopped recognizing the stat command?

my error shows this
Code:
line 31: timeInBar1: command not found
line 32: timeInBar2: command not found
which are these lines
Code:
timeInBar1 = `stat -c %Y $dir1/$FILE`      #%Y gives seconds 
    timeInBar2 = `stat -c %Y $dir2/$FILE`

I don't understand what happened? I don't think that it lost the path to where the commands are...because all of the other commands aren't giving me errors...I'm so confused! I did change the name of the file after I had run it and it worked to match what the requirements were but that shouldn't make a difference right?

UPDATE!! This error ONLY occurs if I have a file by the same name in bar1 and bar2. If I made a change to the file in Bar 2, the script should compare the two timestamps and rewrite the file only if the version in bar2 is newer. I didn't notice the bug the first time I ran it because the script never actually made it to that part of the code since I initially had bar1 empty.

Any ideas?
that error is b/c you have spaces around the "=" sign. instead try this syntax:
Code:
timeInBar2=`stat -c %Y $dir2/$FILE`
also, it is better practice to save command output in bash using this syntax, instead of backticks:

Code:
timeInBar=$(stat -c %Y $FILE)
as it provides nesting, etc. but anyway, you got it sorted...
 
  


Reply

Tags
bash, stat


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Checking file type with fstat Skyrius Linux - General 1 05-12-2012 07:35 AM
more file comparison Stannjudy Linux - Newbie 7 04-15-2008 01:08 PM
Trying to get hold of fstat for debian jimieee Linux - Software 2 05-05-2005 07:43 AM
Troubles using fstat() on assembler... Arelys Monge Programming 1 05-06-2004 10:29 AM
Using fstat() tim_l Linux - Software 0 10-10-2003 11:20 AM


All times are GMT -5. The time now is 04:51 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration