![]() |
|
|
|
|
|||||||
| Forums | Portal | Register | Forum Rules | FAQ | Contribute | Members List | Arcade | Search | Today's Posts | Mark Forums Read |
| Shell Programming and Scripting Post questions about KSH, CSH, SH, BASH, PERL, PHP, SED, AWK and OTHER shell scripts here. |
|
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Recursive pid script | jbarnhar | Shell Programming and Scripting | 3 | 05-02-2007 12:14 PM |
| recursive wc on a directory? | bimba17 | UNIX for Dummies Questions & Answers | 1 | 11-29-2006 01:05 PM |
| recursive sorting | fermisoft | UNIX for Advanced & Expert Users | 1 | 08-16-2005 05:46 AM |
| recursive rcp | Nicol | Shell Programming and Scripting | 6 | 11-06-2003 07:52 AM |
| Recursive FTP | aslamg | UNIX for Dummies Questions & Answers | 1 | 03-08-2001 12:27 AM |
|
|
Submit Tools | LinkBack | Thread Tools | Display Modes |
|
||||
|
Recursive FTP -- here at last.
Over the past few weeks, I saw a couple of threads requesting recursive ftp:
Copying files between 2 Unix server ftp from NT to UNIX I decided to try to write a script to accommodate these requests. The result is HardFeed. Here are a few examples of what it can do. HardFeed ftpserver joeblow somedir This will connect to "ftpserver" and the user "joeblow". It will cd to "somedir". It will look at all of the files (and only the files) there. Each remote file that does not exist in the current directory will be copied to the current directory. HardFeed -ds ftpserver joeblow somedir This will work as the above example did. Except now we try to create local copies of any symbolic links or directories that we found in "somedir". Again, though, we will not overwrite any pre-existing object. HardFeed -rds ftpserver joeblow somedir Now we will create copies of any remote directories and desend into them. This will copy an entire directory tree. (except that it continues to ignore special files, pipes, etc.) HardFeed -rs ftpserver joeblow somedir This is similiar, except we only desend into pre-existing directories. You can use this to copy part of a directory structure. Just pre-create the few directories that you want to copy. HardFeed -rdsm ftpserver joeblow somedir This will copy a directory tree, but this time it will try to duplicate the mode (permissions) on each remote object that is duplicated. HardFeed -rdsf ftpserver joeblow somdir The -f is "freshen". Again it copies a directory tree. But if we have a local file and a remote file, the timestamps are compared. The remote file will overwrite the the local file if the remote file was newer. There is more, including support for microsoft ftp servers that has been lightly tested. See the script itself for more info. Last edited by Perderabo; 11-23-2002 at 12:01 PM. |
| Forum Sponsor | ||
|
|
|
||||
|
HardFeed Part 2
Code:
#
# Function to decode an "ls -l" line.
lsdcode() {
typeset -Z2 nmonth day
typeset -i8 octal
#
# get the line, get the first character, split line into words
line="$1"
char1=${line%%${line#?}}
IFS=" "
set -A things -- $line
IFS=""
#
# We may have a "total" line which needs to be ignored
if [[ ${things[0]} = total ]] ; then
set -A lsdc -- skip 000 000000000000 x x
return 0
fi
#
#
parser=1
month=${things[5]}
xmonth=$(conv_month $month)
if conv_month $month > /dev/null ; then
parser=1
else
parser=0
fi
if ((parser)); then
#
# Strict Left to Right Parse Routine
#
# Break out the fields that we want. This technique requires
# that the user, group, and size fields never run together and
# so they must have at least one space between them. But it
# allows some limited support of filenames with embedded spaces.
echo "$line" | IFS=" " read permstring junk junk junk junk \
month day swing rawname
if [[ $char1 = l ]] ; then
link=${rawname#*-\> }
name=${rawname% -\>*}
else
name="$rawname"
link=""
fi
else
#
# Outside to Inside Parse Routine
#
# Break out the fields that we want. This technique requires
# that no white space exist in the filename. But the user,
# group, and size fields may sometimes run together without
# causing a problem.
echo "WARNING:" badly formatted line in directory listing for: >&2
echo " " "${line}" >&2
echo " " attempting outside-to-inside scan >&2
echo >&2
((pname=${#things[*]}-1))
if [[ $char1 = l ]] ; then
link=${things[pname]}
((pname=pname-2))
else
link=
fi
permstring=${things[0]}
name=${things[pname]}
month=${things[pname-3]}
day=${things[pname-2]}
swing=${things[pname-1]}
if conv_month $month > /dev/null ; then
:
else
echo "ERROR: " outside-to-inside scan has also failed >&2
echo " " giving up on: >&2
echo " " "$line" >&2
echo >&2
set -A lsdc -- skip 000 000000000000 x x
return 0
fi
fi
#
# Ignore . and ..
if [[ $name = . || $name = .. ]] ; then
set -A lsdc -- skip 000 000000000000 x x
return 0
fi
#
# decode permissions (the permission string is first word
set -A perms -- $(print -- ${permstring#?} | sed 's/./& /g')
extras=0
[[ ${perms[2]} = S ]] && { ((extras=extras+4000)); perms[2]=- ; }
[[ ${perms[2]} = s ]] && { ((extras=extras+4000)); perms[2]=x ; }
[[ ${perms[5]} = S ]] && { ((extras=extras+2000)); perms[5]=- ; }
[[ ${perms[5]} = s ]] && { ((extras=extras+2000)); perms[5]=x ; }
[[ ${perms[8]} = T ]] && { ((extras=extras+1000)); perms[8]=- ; }
[[ ${perms[8]} = t ]] && { ((extras=extras+1000)); perms[8]=x ; }
binary=2#$(print -- ${perms[@]} | sed 's/ //g;s/-/0/g;s/[^0]/1/g')
((octal=binary))
result=$(echo $octal)
result=${result#??}
((result=result+extras))
#
# Decode date and time and convert it to yyyymmddhhmm
nmonth=$(conv_month $month)
if [[ $swing = *:* ]] ; then
if [[ $nmonth > $THISMONTH ]] ; then
((year=LASTYEAR))
else
((year=THISYEAR))
time1=${swing%???}
time2=${swing#???}
time="${time1}${time2}"
fi
else
year=$swing
time="0000"
fi
#
# Output the final record
set -A lsdc -- ${char1} ${result} ${year}${nmonth}${day}${time} ${name} ${link}
return
}
#
# Function to process a remote file
# We will not overwrite and existing file unless we in "freshen" mode.
# And unless we are in "freshen" mode, it is an error for a file to
# pre-exist.
process_remote_file() {
VMESS="${VMESS} is a remote file that"
do_get=0
if [[ -f $name ]] ; then
VMESS="${VMESS} already exists"
if ((OPT_FRESHEN)) ; then
line2=$(ls -ld "$name")
lsdcode "$line2"
char12=${lsdc[0]}
mode2=${lsdc[1]}
datestamp2=${lsdc[2]}
name2=${lsdc[3]}
link2=${lsdc[4]}
if [[ $datestamp > $datestamp2 ]] ; then
VMESS="${VMESS} but is out-of-date and"
do_get=1
else
VMESS="${VMESS} and is current"
fi
else
VMESS="${VMESS} and cannot be retrieved"
echo WARNING: no get since $name exists in ${localpath} >&2
fi
else
do_get=1
fi
if ((do_get)) ; then
print -p get \""$name"\"
waitfor $name
VMESS="${VMESS} has been retrieved"
if ((OPT_MODE)) ; then
chmod $mode "$name"
fi
fi
if (($OPT_VERBOSE)) ; then
echo "$VMESS"
fi
return 0
}
# Function to process a remote directory
# To this function, a remote directory is just an object that
# may need to be duplicated in the current directory
process_remote_directory() {
VMESS="${VMESS} is a remote directory that"
if ((OPT_DIRECTORIES)) ; then
if exists $name ; then
if [[ ! -d $name ]] ; then
VMESS="${VMESS} cannot be created due to pre-existing object"
echo WARNING: no mkdir since $name exists in ${localpath} >&2
else
VMESS="${VMESS} already exists"
fi
else
mkdir "$name"
VMESS="${VMESS} has been created locally"
if ((OPT_MODE)) ; then
chmod $mode "$name"
fi
fi
else
VMESS="${VMESS} has been ignored"
fi
if (($OPT_VERBOSE)) ; then
echo "$VMESS"
fi
if ((OPT_RECURS)) ; then
if [[ -d "$name" ]] ; then
cd "$name"
print -p lcd \""$name"\"
exec 4<&-
obtain_and_process_remote_ls "$name"
print -p cd ..
print -p lcd ..
cd ..
exec 4< ${DIR_FILE_NAME[LEV]}
lineno=0
while (( lineno != ${DIR_LINE_NUM[LEV]})) ; do
read -u4 junk
((lineno=lineno+1))
done
fi
fi
return 0
}
#
# Function to process a remote symlink
# Note that we deal with th symlink only -- not
# the object (if any) that the link points to.
process_remote_symlink() {
VMESS="${VMESS} is a remote symlink that"
if ((OPT_SYMLINKS)) ; then
if exists "$name" ; then
if [[ ! -L $name ]] ; then
VMESS="${VMESS} cannot be created due to pre-existing object"
echo WARNING: no symlink since $name exists in ${localpath} >&2
else
VMESS="${VMESS} already exists"
fi
else
ln -s "$link" "$name"
VMESS="${VMESS} has been duplicated locally"
fi
else
VMESS="${VMESS} has been ignored"
fi
if (($OPT_VERBOSE)) ; then
echo "$VMESS"
fi
}
#
# If a remote object is not a file, directory, or
# symlink, we come here.
process_remote_weirdo() {
VMESS="${VMESS} is a remote unknown object that has been ignored"
return 0
}
#
# This function obtains an "ls" listing from the remote ftp system. Then it
# scans the listing line by line to figure out what to do. It will completely
# process the current directory.
obtain_and_process_remote_ls() {
typeset rdir tmpfile okfile ## local scope variables ##
rdir=$1
#
# Set up variables or modify them if we have recursed
((LEV=LEV+1))
tmpfile=/tmp/HardFeed.tp.$$.${LEV}
okfile=/tmp/HardFeed.ok.$$.${LEV}
if ((LEV == 1)) ; then
localpath=$STARTPATH
remotepath=$rdir
else
localpath=${localpath}/$rdir
remotepath=${remotepath}/$rdir
fi
#
# Get a copy of the remote dir output in a local file
# called $tmpfile
print -p cd \""$rdir"\"
print -p $OPT_DIRCMD $tmpfile
print -p $OPT_DIRCMD $okfile
waitfor $okfile
DIR_FILE_NAME[LEV]=$tmpfile
DIR_LINE_NUM[LEV]=0
exec 4< $tmpfile
#
# process each line
#
while read -u4 line ; do
((DIR_LINE_NUM[LEV]=${DIR_LINE_NUM[LEV]}+1))
lsdcode "$line"
char1=${lsdc[0]}
mode=${lsdc[1]}
datestamp=${lsdc[2]}
name=${lsdc[3]}
link=${lsdc[4]}
VMESS="${remotepath}/${name}"
case $char1 in
skip) ;;
-) process_remote_file
;;
d) process_remote_directory
;;
l) process_remote_symlink
;;
*) process_remote_weirdo
;;
esac
done
#
# We may have recursed...so we must put everything back the way
# we found it
localpath=${localpath%$rdir}
localpath=${localpath%/}
remotepath=${remotepath%$rdir}
remotepath=${remotepath%/}
rm $tmpfile
rm $okfile
((LEV=LEV-1))
return 0
}
#
# Main Program
#
ftp -inv >&3 2>&1 |&
print -p open $SYSTEM
print -p user $USER $PASSWORD
print -p binary
i=0
while ((OPT_CMDS>i)) ; do
print -p ${OPT_CMDS_LIST[i]}
((i=i+1))
done
obtain_and_process_remote_ls $DIRECTORY
print -p bye
wait
exit 0
Last edited by Perderabo; 03-16-2004 at 12:30 PM. |
|
|||
|
perderabo,
that is a great script you wrote! im very impressed. your effort to do this for every one just to help some people out is just another example of why unix.com has got to be the best and most helpful website one could find on all things related to unix and the internet. im running a server in my basment and have a desktop in my room, and im gonna have a mirror of everything on the site on my desktop, so i can work on the site from my room, and im gonna use your script to keep everything up to date. thanks for your hard work! im sure it will be appreciated by everyone who sees it. |
|
|||
|
That was really a very useful script, I will test it on my system and try to make use of it and keep it in bin path and advertise!
That was a great work esp. hiding all the complexity behind and giving a simple user interface. Thanks again! Vishnu. |
|
||||
|
Folks, I really appreciate the kudos. Thanks!
But if everyone who finds this script useful was to post a thank-you note, we will get a lengthy thread with little content. So let's keep the thread useful. If you have a question, suggestion, bug report, etc, go ahead and post. But no more thank-you's. I know it's a cool script. But I will add a personal note: No one will benefit from this effort as much as I did. I learned a lot as I solved the problems that I encountered writing this script. What's more, I too wanted a recursive ftp script. And not too surprisingly, this one meets my needs perfectly. |
||||
| Google The UNIX and Linux Forums |