Or maybe you just want to tar up only directories and subdirectories, excluding files…
I’ve mentioned a few times lately that I’m working on my backup plan for GNU/Linux. I started by looking at great free software tools like Samba’s rsync and GNU Tar, and I don’t think I need to look much further than them. There is also GNU Cpio, which I haven’t really investigated yet.
I may have more to say later about my rsync and tar adventures, but for today here’s something I came up with to emulate a feature of a tool I had in Windows that I couldn’t find how to do with existing tools in GNU. The xcopy DOS command lets you recursively copy files modified after a certain date by using the /D:date option.
your questions:
Why would you want to do this? Well, one reason would be for offsite backups. I regularly store backup discs in a bank safe deposit box. I then occasionally want to copy changed files from the last dropoff, encrypt them, and send to my gmail account or carry around on a USB thumb drive. I’d like to have a lightweight way to do this that didn’t rely on a system of incremental backups.
Doesn’t tar take care of this with the --after-date option? Yes, but I haven’t been able to figure out how to get it to exclude directories that are empty of files after the date. The only mention of “prune” in nearly one megabyte of documentation is in reference to the fruit. (The documentation is thorough and good; I wouldn’t be surprised if what I want is possible and I just missed it.)
If I have a hierarchy with hundreds of folders and only a handful of files have changed, I don’t want to store all of the empty directories in my tar file. (Nor do I want to extract them later if it becomes necessary.) It’s not that big of a deal, but I became motivated by the challenge of figuring out a way to do this, and kept scratching this (very minor) itch.

Well, why don’t you just use [some easy/obvious method]? Now you tell me! I’d be very interested to learn about built-in ways to accomplish what I’m trying to do, whether it’s copying files to a target directory or directly in to an archive file. I might feel silly if it’s really obvious or something I should have found in the documentation or my searches, but I wouldn’t regret the time I’ve spent cobbling together these scripts. I learned a lot about the tools and about bash scripting.
It’s often best for me to struggle with things to get the lessons embedded in my pulpy grey matter. In previous entries I’ve railed against the free software migration and learning process because my time is in such short supply, but I’m getting past that. It will take as long as it takes.
And I’m enjoying the learning. I’ve always known the Unix command line is a powerful tool, and learning how to make it go is fun for me. You can find a lot of information about shell scripting online, of course, but I also recommend the O’Reilly book Learning the bash Shell. It’s a good introduction and reference.
Ok, let’s get to it. Read below the fold for information about the cpafter.sh script and to download it if you think it will make your life complete…
cpafter.sh administrative preliminary
First things first, keep in mind my site disclaimer and the notice at the top of the script files. Run these scripts at your own risk. They are pretty simple and you can use your own judgment about how safe they are to run. (I think they are as safe and as risky as the cp command when used with the “recursive” and “force” options.)
I considered releasing these in to the public domain, since there isn’t much to them, but since one of my motivations in starting this site was to promote free software, I decided to release them under the GNU General Public License as a way of proudly stating my belief in the GNU philosophy. It may seem like a lot of thought and extra lines (for the license notification) to put in to a couple of clumsy shell scripts, but it makes me feel good to counter all the anti-innovative (antovative?!) proprietary claims out there with the statement that here is something free for anybody to use and copy.
question
How are we going to recursively copy files that have been modified after a certain date?
answer
We’ll use the find, mkdir, and cp commands as our building blocks.
find -daystart -mtime n
Find lets you search for files last modified n*24 hours ago (or more recently). You can read the man page to see how the -mtime option works, but how about if we try some examples? I do much better with examples.
Let’s say it’s 3pm today and you have three files:
- file_today_2pm
- file_yesterday_4pm
- file_yesterday_2pm
If you run find . -type f -mtime 0, you’ll find files #1 and #2.
If you run find . -type f -mtime 1, you’ll find file #3.
This is because -mtime causes find to look at things in discrete 24-hour time periods, starting from right now. At 3pm, files #1 and #2 are in the first time period (counting backwards), and #3 is in the next.
If you wanted to see all files modified in the first two time periods (counting backwards!), you would use find . -type f -mtime -1, which would return files 1-3.
To make things cleaner, you might want to use time periods that start at midnight. You’d use the -daystart option for this, and:
find . -type f -daystart -mtime 0 would get you file #1.
find . -type f -daystart -mtime 1 would return files #2 and #3.
The cumulative “minus” modifier behaves differently than what I’d expect:
find . -type f -daystart -mtime -1 only gives you file #1.
find . -type f -daystart -mtime -2 returns all three files.
Once we find the files we care about, we’ll want to copy them. For this, we can call on the -exec option. I’ve used -exec for years with grep in HP-UX (their grep doesn’t have a recursive option), and now I had the chance to learn some more about it. -exec allows you to call another program to operate on each of the found files. Let’s look at the grep example first, since it’s simple:
find . -type f -exec grep some_string {} \;
This will take each file and tell grep to look for some_string in that file. {} is an argument for grep — it’s the “found” filename. The semi-colon terminates the grep command. (The man page for find says that both the ‘{}’ and ‘;’ may need to be escaped with a \backslash or quoted to protect them from expansion by the shell. In my experience in HP-UX and GNU/Linux, it’s just the semi-colon that needs the backslash.)
mkdir and cp
My HP-UX find-and-grep experience suggested the answer for my problem. I could use find -mtime to find my files and then call another command to copy them to the target hierarchy. Since cp (as far as I can tell) doesn’t allow you to force creation of parent directories if needed, I would need a second script to be called via -exec. It would simply make the target directory if necessary and then copy the file over.
logical operation

Let’s say we have:
~/test/
file1.txt
file2.txt
apple/
green.txt
red.txt
jupiter/
moon/
io.txt
europa.txt
red_spot/
storm.txt
~/test_target/
And we want to copy files modified in the past couple of days from “test” to “test_target”. Maybe that includes ~/test/apple/red.txt and ~/test/jupiter/moon/europa.txt. cpafter.sh will descend in to ~/test/ so that:
find . -type f -daystart -mtime -2 will give these results:
./apple/red.txt
./jupiter/moon/europa.txt
We’ll pass these via -exec to copy_it.sh along with our target_dir with the understanding that it will build those paths (if necessary) under ~/test_target/ and then copy the files.
let’s look at the scripts (finally)
I added some command line option parsing and checks in an attempt to make the program more generally useful and robust, but haven’t spent a lot of time on this since I created it for my own itch and I don’t expect a large audience for this thing. In the spirit of the free and open source development process, I would be happy to entertain any improvements that are offered back to me.
cpafter.sh
Let’s take a look at selected parts of the script and its operation. Here’s the usage/help information for cpafter.sh:
Copies files modified on or after the given date from source dir to target dir, creating any subdirectories as needed. usage: cpafter.sh [-vf] -a after_date_YYYYMMDD -s source_dir -t target_dir -v verbose -f force target dir creation or copying to non-empty target dir
To manage the parameters, I learned how to use the nice getopts built-in command. Unfortunately, getopts doesn’t handle long option names, but I can live with that for the moment. (There is also the older external command “getopt” that can be made to work with long option names.)
while getopts ":vfa:s:t:" opt
do
case $opt in
v ) verbose=" -v " ;;
f ) force="true" ;;
a ) after_date=$OPTARG ;;
s ) from_dir=$OPTARG ;;
t ) to_dir=$OPTARG ;;
\\? ) echo -e $usage
exit 1
esac
done
My bash book goes in to these features, and I also found a lot of web pages explaining them. Try searching for [bash getopt getopts]. This is one of those things that slows you down: trying to learn the right way to do something. But I think it will be a good habit to get in to. Enough said on this since this post is supposed to be about copying files.
It seemed more natural and less ambiguous to pass in a date as an argument rather than the number of days, so the first thing we need to do is convert our YYYYMMDD formatted date in to a number for -mtime, so let’s skip by some error checking to the date stuff:
after_date_epochal=$(date -d $after_date +%s) today=$(date +%Y%m%d) today_epochal=$(date -d $today +%s) date_dif=$(( (($after_date_epochal - $today_epochal) / 60 / 60 / 24) - 1))
$after_date_epochal is the number of seconds since the epoch (1 Jan 1970) for our “after date.” Then we get midnight of the current day as seconds also, and do some math to find the difference for our -mtime number, $date_dif. That extra “- 1” on the end makes up for the unexpected (to me) extra one that we had to subtract in our example above.
Now for some funny business with our directories:
orig_dir=$PWD
cd $to_dir
to_dir=$PWD
cd $orig_dir
cd $from_dir
I wanted to make certain assumptions in copy_it.sh about the target dir which wouldn’t work if a path with no slashes was used for the target directory, and the above seemed like an easy (if not elegant) way to do it. Then we descend in to the “from dir,” which works whether it is relative or absolute because we first return to the original directory that the script started in.
Now! Let’s run our big find command:
find . -type f -daystart -mtime $date_dif -exec copy_it.sh $verbose -s {} -t $to_dir \;
find . -type l -daystart -mtime $date_dif -exec copy_it.sh $verbose -s {} -t $to_dir \;
I run it twice to look for -type f (regular files) and -type l (symbolic links). I think those are the only things I’d want to use this for. I don’t know of a way to search for both at the same time, which seems like it would be prettier.
copy_it.sh
Here’s the usage/help information for copy_it.sh:
Copies a file to a dir, using the path information from the file to build a path from the given dir root if necessary. Meant to be used with cpafter.sh. usage: copy_it.sh [-v] -s source_file -t target_directory_root -v verbose (just lists the source file)
And here is the meat of the script:
#regex -- does string start with dot slash?
if [[ ! "$from_file" =~ ^\./ ]]; then
from_file="./$from_file" #in case only a filename was given
fi
#return $from_file up to (but not including) last slash
add_to_target=${from_file%/*}
if [[ ! -d "$to_dir/$add_to_target" ]]; then
mkdir -p "$to_dir/$add_to_target"
fi
cp -pdf "$curdir/$from_file" "$to_dir/$from_file"
mkdir -p causes any necessary parent directories to be created. cp -pdf preserves permissions, etc., doesn’t follow symbolic links, and forces a copy if the destination file cannot be opened (removes it and tries again). (Thanks to Trip for pointing out that $to_dir/$add_to_target in the mkdir line needs to be quoted to handle spaces in filenames. I guess I originally tested with spaces in filenames but not dirs.)
cpafter.sh download
cpafter.tar.gz (14 KB)
contains:
- cpafter.sh (3.1 KB)
- copy_it.sh (2.5 KB)
- LICENSE (GNU GPL)
run it
Using our earlier dir structure, let’s say we tried from our home dir:
cpafter.sh -v -a 20070414 -s test -t test_target
The verbose output would be:
copying from /home/username/test
to /home/username/test_target
(mkdir) ./apple/
./apple/red.txt
(mkdir) ./jupiter/moon/
./jupiter/moon/europa.txt
And you would have:
~/test_target/apple/red.txt ~/test_target/jupiter/moon/europa.txt
holy cow, where did the time go?
Phew! It really takes a long time to write these things up. I often wonder if I should spend so much time but then it usually turns out someone finds the post useful so I feel like it was time well spent. Thank you for your patronage.
Update, 8 July 2007
I ran in to some trouble with differences in the behavior of the =~ regex matching operator between bash 3.2 (included with my Ubuntu 7.04/Feisty Fawn install) and bash 3.1 (included with Ubuntu 6.10/Edgy Eft and where I originally developed these scripts). I had seen warnings about this change in 3.2, and was able to make one thing compatible between the two versions, but couldn’t make parentheses capture a match in ${BASH_REMATCH[1]} in version 3.2. Also saw some other strange differences in behavior. In the end, I worked out a different way to do things using the pattern matching operator ${variable%pattern}, and have included that in the updated copy_it.sh script.
While I was at it, I made a change to use the more modern and easier to use $(cmd) syntax for running an external command rather than the backtick method: `cmd`.
And I updated the license to use GPLv3.
The old tar.gz file can be found at cpafter-v01.tar.gz.
Update, 12 August 2007
Trip helpfully pointed out in comments that $to_dir/$add_to_target should be quoted for the mkdir command in the copy_it.sh script so that spaces and other odd characters will be handled correctly. This has been fixed.
Also, Wolfgang Murth (alwag at gmx dot at) very kindly submitted a change for specifying dates differently, by number of days instead of passing in the date as YYYYMMDD. I really appreciate the time and effort, but I’m going to hold off on adding something like that for now. It makes the script more flexible and it would handle copying things older than N days also, but I can’t think of enough scenarios where I would use this feature and I’d prefer to keep things simple if possible. But you can see for yourself: cpafter_alternate_date_option.sh. Thanks, Wolfgang!
The old tar.gz file can be found at cpafter-v02.tar.gz.
Update, 27 September 2007
I created a Google Code Project for these scripts at http://code.google.com/p/bash-cpafter/. I’m not sure if I’ll do much with it. I mostly just wanted to test out the project hosting there. It looks pretty good, offering an SVN repository and issues tracking and other goodies. I like having stuff here, but I may not want to run and maintain these more sophisticated features myself.

26 Comments
It’s nice to see someone using getopts to parse the command line.
Another way to achieve what you’re doing is to use find’s -newer switch. The way this would work is to copy all the files newer than a reference file and then at the end of the copy, update the time on the reference file. Like this:
Performance can be an issue if there are thousands of files because -exec is called for every file find finds. (Say that really fast three times. :-)
xargs is your friend. Something like:
xargs takes stdin, and uses it to feed arguments to a command (or in my example, a shell function). The really cool thing here is that _several_ files are copied at once.
This is really efficient and also a good way to search through files:
find . -type f |xargs grep "mario"
This searches through all the regular files for the string “mario”. xargs is passing filenames to grep as arguments. And since grep is receiving multiple file names, it will print the filename at the beginning of each line just though you had typed:
grep "mario" /etc/passwd /etc/group /etc/foobar ...
Mario
16 April 2007 at 3:07 pm
Thanks, Mario! xargs sounds vaguely familiar — I see that it’s something I should know about. I like that you can call a function with it also.
In
myfunc()above, I think we’d still need something to build the dir if necessary, right? Is there a shortcut of some kind to do that?Briefly looking at the man page for xargs, it looks like some care would need to be taken to use the -0 option to account for filenames with spaces and then -print0 with find to use null as a separator.
(I know spaces in filenames is kind of a Windows things to do, and I generally don’t use them in *nix, but most of my music files and pictures have them and it seems much easier to read the long file names that way, so I may continue using there…)
16 April 2007 at 8:30 pm
Spaces are relatively easy to handle. I usually use sed, the Unix stream editor, for this. Using my last example,
find . -type f |sed 's,^,",; s,$,",' |xargs grep mario
will handle files with spaces in them because sed is putting quotes around the filenames. This doesn’t work in all cases; for example if you have a filename with $ character. But usually, you’ll have bigger problems if that’s the case.
As for the sed expression I used, it says substitute the beginning of the line with a quote, and then substitute the end of the line with a quote. Regular expressions in Unix are very powerful, and one of my favourite features of the “Find and Replace” function of Openoffice.
Mario
17 April 2007 at 11:48 am
I heart regular expressions. I have Jeffrey Friedl’s O’Reilly book Mastering Regular Expressions and wish I had more time right now (or would make more time) to really dig in and learn from it.
17 April 2007 at 3:17 pm
Hi Scott,
Had the same problem ages ago and spent a few weeks writing a giant ball of cruft in bash to sort (ish) this one.
It wants fixing still; functionally it runs and was in daily use for 3 years. Very few probs.
This is “TIBS” – a name I later found I can’t use, as it is in use by an… archive company. ANyhow. My “TIBS” was supposed to mean “Transparent Iterative Backup System”.
It was 100% transparent to the users. All they had to do was to click on a link and Presto! all their work from X days ago was there.
The whole thing was in support of a Windows 9x network of 6 machines. A common archived workspace was served from a Mandrake box (this was 2001). 9 gigs I remember.
Every night (say night N), the system did this:
create a new delta image for the workspace on a backup disc
populate the new image with workspace dir structure
scan workspace looking for any changes to any file
copy the changed files into the right image dir
for ALL unchanged files (whew..):
create a link to the last good image of that file as per prior directory (ie whatever is in delta N-1).
stats and management info reporting + logs.
* This moved all the work to the overnight job *
Thus: look at any intermediate dir and see: ALL FILES in plain; the “new” ones for that date + transparent links to the unchanged files. A 100% perfect, in plain copy of that days workspace (actually, mostly links – but Windows across a network can’t tell that).
Very sweet – and local paths worked; impressed the webmaster for that Co. when I could fire up their webpage from Nov 2 years ago – and the whole lot ran, right off the archive in seconds flat.
{Webmaster – ugh, wasn’t it AWFUL then! Those colors! etc}
The 0th (oldest) directory was a full 1:1 image, no links.
Over the years I got this to de-link OK (so I could blow intermediate backup dirs away, to save space. Would scavenge all deltas over 4 weeks old except Mondays, so dropped from daily to weekly snapshots).
Biggest problem was with evil MS file names esp. MULTIPLE SPACES eg “this $ is __ an allowed filename”. Nice; bash will not do this as multiple spaces compressed to 1 :)
The disc utilisation rate was good; even though everything was in plain that 9 gig workspace + 40-60 days of delta images would sit fine in 15gig.
Duplicated this onto a AMD K6-III 500MHz machine as a server-archiver for a guy working with media (400meg files). It worked fine for over a year. The reason that I mention this is:
a) the 500MHz rig (slackware on that) was x4 faster at file serving then a 2.2GHz box running XP, and
b) just to torment 98SE, we tried to do a “Properies” on the root dir of the archive (so it goes counts the size of all the images, multiply counting the same file when linked in for 60 days etc). Hey, 98 knew to count into TB !
Even got it to work multi-volumes so could swap in / swap out drives & it would recognise & run with that – idea being take-a-drive-off-site etc.
But, knowing what I do now, I’d write it in python not bash.
Or just use rsync.
You are welcome to play with TIBS if you want. WARNING: you might need a spare brane, a few weeks to hand and cruft-resistant shades…
:)
brodders
23 April 2007 at 1:22 pm
Hi, brodders. I received a good tip about using rsync with hard links earlier this year and have crafted some custom backup scripts for myself using that technique.
I like the idea you mention of dropping some dailies to keep weeklies. I was thinking I’d keep as many as 60 daily backups of my main data folder but maybe would be just as well to keep 30 daily and then weeklies to 4, 8, or whatever more weeks back, simply by deleting the dailies in between Mondays or whatever.
Paul Sundvall was the one who mentioned using rsync + hard links. He pointed me to some backup utils he wrote and also referenced a good page about snapshot-style backups with rsync. I used some ideas from both pages while crafting my own solution. Good learning exercise and also everyone has their own requirements. And it’s fun, since I’m a geek.
Thanks for commenting!
23 April 2007 at 7:53 pm
Ei…. Thanks for your program!! It’s almost… PERFECT!!! Only need to change line 70 to this and a problem with folder names with the spaces is solved!! :D Good work!!! And thanks again!
Old code in line 70:
mkdir -p $to_dir/$add_to_targetNew code:
mkdir -p "$to_dir/$add_to_target"11 August 2007 at 9:35 pm
Thanks, Trip! I must have tested with files that have spaces, but not dirs, so didn’t catch this. Oops.
It’s nice to hear that people are actually using this thing.
12 August 2007 at 10:16 am
Hi experts,
I have to write a script to copy the Files in FIFO style betwwn
two machines.
I gave an explanation below:
Script scenario:
I have two machines “A”, “B”.
for every 5mnts some files are written into directory “DIR1″ on
Machine “A” with naming convention
and the count
increases in day. Now I have to run the script on machine “B” to
get the files from machine “A”. Here I have to read the files in
FIFO manner ( as they reach DIR1 on “A”) and each files resides
in DIR1 on “A” upto 7days. So I have to ensure that each file is
copied only once from DIR1 on “A” to macine “B”, though we run
the script several times. I mean, files which are copied once
from “A” to “B” to be ignored in future. I remind that we can’t
remove the files after reading from A:/DIR1.
For that I developed the below script. But this is simply
copying all files from Machine A-to-Machine B.
#!/bin/ksh
clear
echo “Start of the script ”
HOST=hostname
USER=user1
PASSWD=userpw1
scrdir=/users/user1/TEST
ftp -n $HOST
12 October 2007 at 1:06 pm
Hi Rahul,
You’ll want to look at rsync. It copies files that have changed and that are new from one place to another. To do what you want, you’d do something like this from machine B:
rsync -a A:/mydir /foo
This will copy all the new files from A:/mydir to /foo on B. rsync requires rsh or ssh to copy over a network, or you can set up the rsync protocol.
19 October 2007 at 10:28 pm
Hi Scott,
I found this script really useful. After doing the obvious “find -exec cp” messed up my directory structure. cpafter was easy to implement.
I had an error
I found the problem on cpafter.sh line 101-108. After setting cd to the /source/ directory. copy_it.sh is called however it’s not on the /source/ directory. I rewrote your script hard linking this to my local root location.
find . -type f -daystart -mtime $date_dif -exec bash ~/copy_it.sh $verbose -s {} -t $to_dir \; find . -type l -daystart -mtime $date_dif -exec bash ~/copy_it.sh $verbose -s {} -t $to_dir \;On a tangent, I’m new to bash. And was wondering why the append command
+=doesn’t work in my version.e.g.
pluto ~ # bash cpafter.sh -v -a 20071120 -s "/source/" -t "/target/" cpafter.sh: line 24: usage+=to target dir, creating any subdirectories as needed.\n\n: command not found cpafter.sh: line 25: usage+=\tusage: cpafter.sh [-vf] -a after_date_YYYYMMDD -s source_dir -t target_dir\n: command not found cpafter.sh: line 26: usage+=\t\t-v verbose\n: command not found cpafter.sh: line 27: usage+=\t\t-f force target dir creation or copying to non-empty target dir\n: command not found copying from /source to /target/root/copy_it.sh: line 24: usage+=build a path from the given dir root if necessary. Meant to be used\n: command not found /root/copy_it.sh: line 25: usage+=with cpafter.sh.\n\n: command not found /root/copy_it.sh: line 26: usage+=\tusage: copy_it.sh [-v] -s source_file -t target_directory_root\n: command not found /root/copy_it.sh: line 27: usage+=\t\t-v verbose (just lists the source file)\n: command not found ./my_test_fileMy version: GNU bash, version 3.00.16(1)-release (i686-pc-linux-gnu)
Drew
21 November 2007 at 5:43 am
Hi, Andrew. I’m glad the scripts were helpful for you.
I put both scripts in my
~/bindir, and then have this in my.bash_profile:# set PATH so it includes user's private bin if it exists if [[ -d ~/bin && ! $PATH =~ ~/bin ]] ; then export PATH=~/bin:"${PATH}" fiIf you use something like that, you won’t have to hard code the path to
copy_it.sh, and you can have all your scripts readily available.(It might be helpful also to rewrite it with the advice from Mario above so that it is only a single script, but since it’s working this way I haven’t had that much motivation to do so.)
My bash version is 3.2.13(1)-release. I just searched and found http://tldp.org/LDP/abs/html/bashver3.html: “The version 3.1 update of Bash introduces a number of bugfixes and a few minor changes. The += operator is now permitted in places where previously only the = assignment operator was recognized.” So that might explain this situation.
21 November 2007 at 7:22 am
Hi Scott:
I need a KSH script which does the following:
1. CD to Directory – “/home/RAOB/TOC/” and list the files present in that directory
2. Generate both Local time and GM time and compare the file’s time with GM time.
3. If the file’s timestamp is lower than the GM time (meaning 3 days older), then we move it to a new directory from the list and pick another file. Else, process it as an command line argument to program (/root/home/source/programs/abc.c)
4. Parallelly, append that file, which is processed from the directory and store it in a log file
I wrote the following script:
#!/bin/sh -x checkduration=259200 # 3 days in seconds cur_timestamp=`date +%s` #current time in seconds cd /mnt/ldm/data/public/RAOB/200801/ # change dir for i in /mnt/ldm/data/public/RAOB/200801/*; do if [ -f $i ]; then # if the file is there filename=${i#/mnt/ldm/data/public/RAOB/200801/};# get file name last_mod=$(stat -c "%Y" ${i#/mnt/ldm/data/public/RAOB/200801/}); # get last mod time of file in seconds last_mod=$(stat -c "%Y" filename) #above line gathers file modified time in seconds from epoch if [ $last_mod ] then time_diff=`expr $cur_timestamp - $last_mod`; #cal time difference 3 days or more if [ $time_diff -lt $checkduration] # file modified three days or less back then mv ${i#/mnt/ldm/data/public/RAOB/200801/} /mnt/ldm/data/public/RAOB/old_data #if more then move to a new folder cat $filename>>log #append this file name to log sheet fi fi fi doneI do not get any errors, but there seem to be a problem with the comparison of times and to move the file read to another directory.
Could you help me please?
rgds,
Kalyan
31 January 2008 at 2:46 pm
Hi, Kalyan. Sorry, can’t help you.
31 January 2008 at 4:13 pm
Hi,
Just wanted to say many thanks. Nice program, works fine, saves me a lot of time!
12 April 2008 at 7:55 am
Hi, Laurent — you’re welcome — I’m glad it was useful for you.
14 April 2008 at 7:45 pm
I’m new to bash. I cd in a bash file and during the scripts its ok but after returning to command line prompt I’m in the first Directory. How can I do scripts in the global environment?
21 June 2008 at 7:04 am
Sorry, MrM, I don’t know the answer to what I think you’re asking.
22 June 2008 at 9:17 pm
Hello,
can anybody help how and what script shall i make that can show me the updated/modified files in windows.
27 August 2008 at 9:08 am
Hi,
I used your copy_it.sh, but I ran into a slight problem,
I’m not sure that this would be a problem for others,
but I just figured I should give something back.
The src file directory gets changed to the curdir,
but that didn’t work for me. Here are the changes i made:
# copy_it.sh # ... curdir=$PWD #from_dir #regex -- does string start with dot slash? src_file=${from_file} if [[ ! "$from_file" =~ ^\./ ]]; then from_file="./$from_file" #in case only a filename was given fi # ... #cp -pdf "$curdir/$from_file" "$to_dir/$from_file" cp -pdf "$src_file" "$to_dir/$from_file"Thanks,
timr
21 October 2008 at 10:17 pm
Thanks for the feedback, timr — I’m glad you were able to work it out.
22 October 2008 at 4:30 am
For MrM, the short answer is that you will need to include the script in your current environment like this:
. ./myscript
The script doesn’t have to be executable.
The reason you need to do this is because of the parent-child relationship in Unix processes. The environment of the child can’t be seen by the parent, so when you execute a script, you are creating a new process with a copy of the parent’s environment. When the child dies, the child’s environment dies as well leaving you back to where you started.
Using an include, as shown above, you are simply saying to the shell, execute these commands as though you had typed them in your current environment. The script, when included, doesn’t need to be executable, doesn’t need any shell magic declaration at the top, but does need to be written in the same shell language as the one you’re in when calling it.
Cheers,
Mario
10 November 2008 at 3:44 pm
Just a quick “thanks for this”. Worked as advertised and real useful!
29 January 2010 at 3:51 pm
Super! Thanks for the feedback.
29 January 2010 at 6:41 pm
can this also be used on a mac?
if so, has anybody used it and do i have to do anything different than listed above?
thank you!
29 April 2010 at 8:53 am
i just tried it on my mac, and it did not work :(
this is what i got
—
./cpafter.sh -v -a 20100426 -s test-dir/ -t test-target
date: settimeofday (timezone): Operation not permitted
date: settimeofday (timezone): Operation not permitted
./cpafter.sh: line 91: (( – ) / 60 / 60 / 24) – 1: syntax error: operand expected (error token is “) / 60 / 60 / 24) – 1″)
copying from /Users/mani/Downloads/cpafter/test-dir
to /Users/mani/Downloads/cpafter/test-target
find: -daystart: unknown option
find: -daystart: unknown option
29 April 2010 at 9:11 am