#!/bin/bash export COPY_MODULE_PATH="$(dirname $(realpath "${BASH_SOURCE:-$0}"))" module_load debug module_load confirm copy () { if ! which rsync &> /dev/null; then echo rsync must be installed to use this function; return 6; fi local SHOST; local DHOST; local sshargs; local args local SRC; local DEST; local mirror; local quiet local SPATH; local DPATH; local exec; local list; local verbose local usesudo;local cmd;local noconfirm;local merge args=() help() { cat < source destination --- Available Script Options -r, run the command by this script uses --dry-run. When ready pass this flag. -s, run command as sudo -l, list the rsync command that will be run instead of running it. removes --dry-run. great for generating a rsync command to be used elsewhere -p, make path at destination if need be. careful will creating missing subdirectories -e, rsync --exclude , as many of these as desired -m, merge source inside destination instead of making folder at destination, good for changing destination folder name -M, copy as "mirror" uses options. -a --numeric-ids --delete --delete-excluded --force -f, rsync --exclude-from , can have multiple -F, copy a filesystem, uses -M mirror plus -xHAXS, and uses sudo (i.e. -s script option) -n, no confirm, will always confirm command unless this is set -q, quiet, suppress progress -v, verbose, same as -v for rsync option, unset if -q is set -a, archive, same as -a for rsync option, basic identical copy with recursion -c, clean tranfer meaning will not transfer folder with trash, cache, log, nodemodules -C, show excludes for clean transfer -h, this help text source or destination may include a : prefix but not both use 'fcopy ' for fast copy uses -r -q -m -n -a EOF } # parse sshcp options local OPTION local OPTARG local OPTIND while getopts 'avMqpf:le:rcCmd:s:hnF' OPTION; do # echo OPTION $OPTION ARG $OPTARG INDX $OPTIND case "$OPTION" in s) usesudo=sudo ;; c) # clean out unneeded folders like cache, trash, log args+=("--exclude-from=$COPY_MODULE_PATH/cache-trash-log.exc") ;; C) echo "## clean transfer exclusions found in $COPY_MODULE_PATH/cache-trash-log.exc ##" cat "$COPY_MODULE_PATH/cache-trash-log.exc" echo -e "\n##############################################" return 0 ;; q) quiet=true ;; n) noconfirm=true ;; e) args+=("--exclude=$OPTARG") ;; f) args+=("--exclude-from=$OPTARG") ;; F) args+=("-xHAXS") mirror=true usesudo=sudo ;; p) args+=("--mkpath") ;; m) merge=true ;; M) mirror=true ;; l) list=true ;; v) verbose="-v" ;; r) exec=true ;; a) args+=("-a") ;; h) help return 0 ;; *) >&2 echo fatal: unknown remote script option $OPTION, aborting help return 1 ;; esac done shift $((OPTIND - 1)) [ $# -lt 2 ] && echo both a source and destination need to be passed && return 2 # source parse SRC=$1; shift if [[ $SRC =~ ":" ]]; then echo source is remote SHOST=${SHOST:-$(sed 's/\(.*\):.*/\1/' <<< "$SRC")} SPATH=$(sed 's/.*:\(.*\)/\1/' <<< "$SRC") else # echo source is local SPATH=$SRC fi # destination parse DEST=$1;shift if [[ $DEST =~ ":" ]]; then # echo destination is remote DHOST=${DHOST:-$(sed 's/\(.*\):.*/\1/' <<< "$DEST")} DPATH=$(sed 's/.*:\(.*\)/\1/' <<< "$DEST") else # echo destination is local DPATH=$DEST fi [[ $DHOST && $SHOST ]] && echo this script can not process remote host to remote host transfer && return 5 # is source or destination is remote, create -e ssh sync option if [[ $DHOST || $SHOST ]]; then if ! module_load ssh &>/dev/null; then echo unable to load ssh module echo likely the uci network repo has not been installed echo to do a remote copy this repo which contains the ssh module echo "must be installed. Try \"module_load uci-shell-install; install_shell_network\"" return 6 fi if [[ ! $(get_user_host ${DHOST:-$SHOST}) ]]; then >&2 echo fatal: the host ${DHOST:-$SHOST} is not valid, aborting remote copy return 1 fi # parse ssh arguments from the rest debug $( ( IFS=$','; echo all arguments: "$*" ) ) for ((d=1; d<$#; ++d)); do [[ ${!d} == "---" ]] && break done if [[ $d -lt $# ]]; then # if there are extra ssh arguments debug found --- at $d sshargs=("${@:$d+1:$#}") debug $( ( IFS=$','; echo "ssh arguments: ${sshargs[*]}" ) ) args+=("${@:1:$d-1}") debug $( ( IFS=$','; echo remaining arguments to parse: "$*" ) ) else args+=("${@:1}") fi args+=( "$(remove_end_spaces "-e '$(ssh -l "${sshargs[*]}")'")") fi # assemble options [[ ! $exec ]] && args+=(--dry-run -v) [[ ! $quiet ]] && args+=(--info=progress2 $verbose) [[ $mirror ]] && args+=(-a --numeric-ids --delete --delete-excluded --force) [[ ! -v PS1 ]] && noconfirm=true if [[ ! $noconfirm && ! $list ]]; then if [[ $merge ]]; then # todo mirror option confirm The contents within $SPATH will be $([[ $mirror ]] && echo mirrored || echo placed ) inside $DPATH || return 0 else confirm the directory $(basename $SPATH) of $SPATH will be $([[ $mirror ]] && echo mirrored || echo put ) at destination $DPATH/$(basename $SPATH)? || return 0 fi fi cmd="$usesudo $(which rsync) ${args[*]} $SRC$([[ $merge ]] && echo "/") $DEST" [[ $list ]] && echo "$cmd" && return 0 if [[ ! $quiet ]]; then [[ $exec ]] && echo executing the copy command || echo dry run of command, use -r to execute; fi if eval $cmd; then [[ ! $quiet ]] && echo copy success! debug $cmd else >&2 echo remote copy failed >&2 echo $cmd return 1 fi } alias fcopy="copy -r -q -m -n -a " # for copying chromium profile use # --exclude=Singleton*