288 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
| #! /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
 | 
