289 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
		
		
			
		
	
	
			289 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
|   | #! /bin/bash | ||
|  | # | ||
|  | # original from: | ||
|  | # | ||
|  | # @(#) frcp.ksh 2.2 93/11/14 | ||
|  | # 92/06/29 john h. dubois iii (john@armory.com) | ||
|  | # 92/10/14 Cleaned up, improved, added -d and -r options | ||
|  | # 92/11/11 Made work with a dest of '.' | ||
|  | # 93/07/09 Added -l and -n options, & login as anonymous if no .netrc entry | ||
|  | # 93/11/14 Use either passwd or password in .netrc, since ftp does. | ||
|  | # | ||
|  | # conversion to bash v2 syntax by Chet Ramey | ||
|  | # | ||
|  | # frcp: ftp front end with rcp-like syntax. | ||
|  | # Note: requires any machine names given to be listed with | ||
|  | #       user and password in .netrc.  If not, anonymous FTP is | ||
|  | #	done. | ||
|  | # | ||
|  | # full path to ftp binary | ||
|  | if [ -x /usr/bin/ftp ]; then | ||
|  | 	FTP=/usr/bin/ftp; | ||
|  | elif [ -x /usr/ucb/ftp ]; then | ||
|  | 	FTP=/usr/ucb/ftp | ||
|  | else | ||
|  | 	FTP=ftp | ||
|  | fi | ||
|  | 
 | ||
|  | istrue() | ||
|  | { | ||
|  | 	test 0 -ne "$1" | ||
|  | } | ||
|  | isfalse() | ||
|  | { | ||
|  | 	test 0 -eq "$1" | ||
|  | } | ||
|  | 
 | ||
|  | # For each filename given, put the filename in filename[n] | ||
|  | # and the machine it is on in machine[n]. | ||
|  | function SplitNames { | ||
|  |     typeset file | ||
|  |     typeset -i i=1 | ||
|  | 
 | ||
|  |     unset filename[*] machine[*] | ||
|  |     for file; do | ||
|  | 	case "$file" in | ||
|  | 	*:*) machine[i]=${file%%:*} ;; | ||
|  | 	*)   machine[i]=$LocalMach ;; | ||
|  | 	esac | ||
|  | 	filename[i]=${file#*:} | ||
|  | 	let i+=1 | ||
|  |     done | ||
|  | } | ||
|  | 
 | ||
|  | function verboseprint { | ||
|  |     echo "$@" | ||
|  |     echo "$@" 1>&2 | ||
|  | } | ||
|  | 
 | ||
|  | function MakeDir { | ||
|  |     OFS=$IFS | ||
|  |     local IFS=/ dir component | ||
|  | 
 | ||
|  |     case "$1" in | ||
|  |     /*)	;; | ||
|  |      *) dir=. | ||
|  |     esac | ||
|  |     set -- $1 | ||
|  |     IFS=$OFS | ||
|  |     for component; do | ||
|  | 	dir=$dir/$component | ||
|  | 	if [ ! -d "$dir" ]; then | ||
|  | 	    if mkdir "$dir"; then :; else | ||
|  | 		echo "Could not make directory $dir." >&2 | ||
|  | 		return 1 | ||
|  | 	    fi | ||
|  | 	fi | ||
|  |     done | ||
|  |     return 0 | ||
|  | } | ||
|  | 
 | ||
|  | lastisdot () | ||
|  | { | ||
|  | 	case "$1" in | ||
|  | 	*/.|*/..)	return 0;; | ||
|  | 	*)	return 1;; | ||
|  | 	esac | ||
|  | } | ||
|  | 
 | ||
|  | # CopyFiles: issue ftp(TC) commands to copy files. | ||
|  | # Usage: CopyFiles [sourcemachine:]sourcepath ... [destmachine:]destpath | ||
|  | # Global vars: | ||
|  | # Uses LocalMach (should be name of local machine) | ||
|  | # Sets global arrs machine[]/filename[] | ||
|  | function CopyFiles { | ||
|  |     unset machine[*] filename[*] | ||
|  | 
 | ||
|  |     SplitNames "$@"	# split names into filename[1..n] and machine[1..n] | ||
|  | 
 | ||
|  |     local DestMach=${machine[$#]}	# Machine to copy files to | ||
|  |     local DestPath=${filename[$#]} 	# Destination file/dir | ||
|  | 
 | ||
|  |     unset machine[$#] filename[$#] | ||
|  | 
 | ||
|  |     [ -z "$DestPath" ] && DestPath=.	# dest was given as machine: | ||
|  | 
 | ||
|  |     # Try to determine if destination should be a directory | ||
|  |     # so that it can be forced to be a directory. | ||
|  | 
 | ||
|  |     case "$DestPath" in | ||
|  |     */)	;;	# don't add / if trailing / already present | ||
|  |     *)  if [ $# -gt 2 ] || # if more than two args given, last must be a dir | ||
|  | 	    # If dest in on local machine, check whether it is a directory | ||
|  |     	   [ $DestMach = $LocalMach -a -d $DestPath ] ||  | ||
|  | 	    # If dest ends with . or .., it is a directory | ||
|  | 	   lastisdot "$DestPath" | ||
|  | 	then | ||
|  | 		DestPath=$DestPath/ | ||
|  | 	fi ;; | ||
|  |     esac | ||
|  | 
 | ||
|  |     # If one of the above tests made us think dest is a directory, | ||
|  |     # but it isn't, complain | ||
|  |     case "$DestPath" in | ||
|  |     */)	if [ "$DestMach" = "$LocalMach" ] && [ ! -d "$DestPath" ]; then | ||
|  | 		echo "Destination is not a directory." 1>&2 | ||
|  | 		exit 1 | ||
|  |         fi ;; | ||
|  |     esac | ||
|  | 
 | ||
|  |     DoCopy "$DestMach" "$DestPath" | ||
|  | } | ||
|  | 
 | ||
|  | # Usage: OpenMachine machine-name | ||
|  | # Emits login sequence or doesn't, depending on .netrc file and global | ||
|  | # variables anon and noanon | ||
|  | OpenMachine () | ||
|  | { | ||
|  |     local machine=$1 netrc=$HOME/.netrc user= password= | ||
|  | 
 | ||
|  |     if isfalse $anon && [ -r $netrc ]; then | ||
|  | 	set -- $(gawk ' | ||
|  | 	/machine (.* )?'"$machine"'($| )/,/^ *$/ { | ||
|  | 	    Fields[$1] = $2 | ||
|  | 	    if ("passwd" in Fields) | ||
|  | 		Fields["password"] = Fields["passwd"] | ||
|  | 	    if ("login" in Fields && "password" in Fields) { | ||
|  | 		print Fields["login"] " " Fields["password"] | ||
|  | 		exit | ||
|  | 	    } | ||
|  | 	} | ||
|  | 	' $netrc ) | ||
|  | 	user=$1 | ||
|  | 	password=$2 | ||
|  |     fi | ||
|  |     if [ -z "$password" ]; then | ||
|  | 	if istrue $noanon; then | ||
|  | 	    echo "No .netrc entry for machine $machine" 1>&2 | ||
|  | 	    exit 1 | ||
|  | 	fi | ||
|  | 	user=anonymous | ||
|  | 	password=$USER@$LocalMach | ||
|  |     fi | ||
|  |     verboseprint open $machine | ||
|  |     echo user $user "*******" 1>&2 | ||
|  |     echo user $user $password | ||
|  | } | ||
|  | 
 | ||
|  | # Usage: DoCopy destination-machine destination-path | ||
|  | # Copies the files in global arrs machine[]/filename[] to the given dest | ||
|  | # Global vars: | ||
|  | # Uses machine[], filename[], LocalMach, check | ||
|  | DoCopy () | ||
|  | { | ||
|  |     local DestMach=$1 | ||
|  |     local DestPath=$2 | ||
|  |     local OpenMach	# Machine that connection is currently open to | ||
|  |     local OWD=$PWD SourceMach SourceFile | ||
|  |     local FileName | ||
|  |     typeset -i i=1 | ||
|  | 
 | ||
|  |     while [ $i -le ${#machine[*]} ]; do | ||
|  | 	istrue $check && verboseprint "runique" | ||
|  | 
 | ||
|  | 	SourceMach=${machine[i]} | ||
|  | 	SourceFile=${filename[i]} | ||
|  | 
 | ||
|  | 	DestFile=$DestPath | ||
|  | 	# if DestPath is a dir, | ||
|  | 	# add source filename to it without source path | ||
|  | 	case "$DestFile" in | ||
|  | 	*/)	DestFile=$DestFile${SourceFile##*/} ;; | ||
|  | 	esac | ||
|  | 
 | ||
|  | 	if [ $SourceMach = $LocalMach ]; then | ||
|  | 	    if [ $DestMach != "$OpenMach" ]; then | ||
|  | 		OpenMachine $DestMach | ||
|  | 		OpenMach=$DestMach | ||
|  | 	    fi | ||
|  | 	    verboseprint put $SourceFile $DestFile | ||
|  | 	elif [ $DestMach = $LocalMach ]; then | ||
|  | 	    if istrue $check && [ -f "$DestFile" ]; then | ||
|  | 		echo "$DestFile already exists." 1>&2 | ||
|  | 		continue | ||
|  | 	    fi | ||
|  | 	    # If destination is on local machine, | ||
|  | 	    # the dest will be a full dir/filename | ||
|  | 	    if istrue $createdirs; then | ||
|  | 		MakeDir "${DestFile%/*}" || continue | ||
|  | 	    fi | ||
|  | 	    if [ $SourceMach != "$OpenMach" ]; then | ||
|  | 		OpenMachine $SourceMach | ||
|  | 		OpenMach=$SourceMach | ||
|  | 	    fi | ||
|  | 	    # If source filename has wildcards ([, ], *, ?) do an mget | ||
|  | 	    case "$SourceFile" in | ||
|  | 	    \[*\]|*\**|*\?*) | ||
|  | 		verboseprint lcd "$DestFile" | ||
|  | 		verboseprint mget "$SourceFile" | ||
|  | 		verboseprint lcd $OWD ;; | ||
|  | 	    *)  verboseprint get "$SourceFile" "$DestFile" ;; | ||
|  | 	    esac | ||
|  | 	else | ||
|  | 	    echo "Neither source machine \"$SourceMach\" "\ | ||
|  | "nor destination machine \"$DestMach\" is local." 1>&2 | ||
|  | 	fi | ||
|  | 	let i+=1 | ||
|  |     done | ||
|  | } | ||
|  | 
 | ||
|  | # Start of main program | ||
|  | name=${0##*/} | ||
|  | 
 | ||
|  | if [ "$1" = -h ]; then | ||
|  |     echo \ | ||
|  | "$name: do ftp transfers using rcp-style parameters. | ||
|  | Usage: $name <source> <destpath>   or   $name <source> [<source> ...] <destdir> | ||
|  | At least one of <source> and <destpath> must be the local system. | ||
|  | A remote filename is given as machinename:filename | ||
|  | If remote filenames contain wildcards, they will be globbed on the remote | ||
|  | machine.  Make sure they are quoted when $name is invoked. | ||
|  | If the invoking user's .netrc file (see ftp(TC)) contains an entry for the | ||
|  | remote system with a login and password supplied, $name will log in using | ||
|  | the given login and password.  If not, $name will login in as user | ||
|  | anonymous and with the user@localsystem as the password. | ||
|  | Options: | ||
|  | -c: check: do not overwrite files. | ||
|  | -d: create directories as needed. | ||
|  | -f: force: overwrite files (default). | ||
|  | -h: print this help. | ||
|  | -l: fail if there is no entry with login and password for the remote system, | ||
|  |     instead of logging in as anonymous. | ||
|  | -n: log in as anonymous even if there is an entry for the remote system in | ||
|  |     the user's .netrc file. | ||
|  | -r: read source/dest filename pairs from the standard input, | ||
|  |     one pair per line, and copy files accordingly." | ||
|  |     exit 0 | ||
|  | fi | ||
|  | 
 | ||
|  | typeset -i check=0 createdirs=0 readinput=0 anon=0 noanon=0 | ||
|  | 
 | ||
|  | while getopts :cdflnr Option | ||
|  | do | ||
|  |     case "$Option" in | ||
|  |     c) check=1;; | ||
|  |     d) createdirs=1;; | ||
|  |     f) check=0;; | ||
|  |     l) noanon=1;; | ||
|  |     n) anon=1;; | ||
|  |     r) readinput=1;; | ||
|  |     \?) echo "$OPTARG: invalid option."; exit 1;; | ||
|  |     esac | ||
|  | done | ||
|  | 
 | ||
|  | shift $((OPTIND-1)) | ||
|  | 
 | ||
|  | LocalMach=`hostname`  | ||
|  | 
 | ||
|  | if istrue $readinput; then | ||
|  |     while read line; do | ||
|  | 	CopyFiles $line | ||
|  |     done | $FTP -nv | ||
|  | else | ||
|  |     if [ $# -lt 2 ]; then | ||
|  | 	echo "$name: Not enough arguments.  Use -h for help." 1>&2 | ||
|  | 	exit | ||
|  |     fi | ||
|  |     CopyFiles "$@" | $FTP -nv | ||
|  | fi |