#!/bin/bash export COPY_MODULE_PATH="$(dirname $(realpath "${BASH_SOURCE:-$0}"))" module_load debug module_load confirm module_load helpers 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 Mirror local SPATH; local DPATH; local exec; local list; local verbose local usesudo;local cmd;local noconfirm;local insert; local sargs 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 -i, insert 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 --force -M, copy as "mirror" above -m plus '--delete-excluded' added. A perfect mirror -f, rsync --exclude-from , can have multiple -F, copy a filesystem, uses -M and -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 ssh arguments may be added at the end after --. any option with multiple arguments must be enclosed in literal double quotes, (.e.g) -o \"ProxyCommand nohup ssh firewall nc -w1 %h %p\" 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:shnFi' OPTION; do # echo OPTION $OPTION ARG $OPTARG INDX $OPTIND case "$OPTION" in # TODO add D and S for destion and source path 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") args+=("--exclude-from=$COPY_MODULE_PATH/cache-trash-log.exc") Mirror=true mirror=true usesudo=sudo ;; p) args+=("--mkpath") ;; i) insert=true ;; m) mirror=true ;; M) Mirror=true 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 Error: both a source and destination need to be passed; help; ) && return 1 # 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 # echo remote copy, loading ssh 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 # else # echo local rsync copy fi [[ ! $SHOST ]] && SPATH=$(realpath $SPATH) [[ ! $DHOST ]] && DPATH=$(realpath $DPATH) # BASH_DEBUG="stdout" debug $( ( IFS=$','; echo all remaining arguments: "$*" ) ) for ((d=1; d<$#+1; ++d)); do echo in loop $d, ${!d} [[ ${!d} == "--" ]] && sargs=true && break done if [[ $sargs ]]; then # if there are extra ssh arguments sshargs=("${@:$d+1:$#}") debug $( ( IFS=$','; echo "ssh arguments: ${sshargs[*]}" ) ) [[ $DHOST || $SHOST ]] && args+=( "$(remove_end_spaces "-e '$(ssh -l "${sshargs[*]}")'")") fi # remove -- # args=+("${@:1:$d-1}") # debug $( ( IFS=$','; echo remaining arguments to parse: "$*" ) ) # else # echo again: ${args[*]} # args=("${@:1}") # assemble arguments from options [[ ! $exec ]] && args+=(--dry-run -v) [[ ! $quiet ]] && args+=(--info=progress2 $verbose) [[ $mirror ]] && args+=(-a --numeric-ids --delete --force) [[ $Mirror ]] && args+=(--delete-excluded) [[ ! -v PS1 ]] && noconfirm=true if [[ ! $noconfirm && ! $list ]]; then if [[ $insert ]]; then # todo mirror option confirm The contents within $([[ $SHOST ]] && echo $SHOST:)$SPATH will be \ $([[ $mirror ]] && echo mirrored || echo placed ) inside $([[ $DHOST ]] && echo $DHOST:)$DPATH || return 0 else confirm the directory $(basename $SPATH) of $([[ $SHOST ]] && echo $SHOST:)$SPATH will be \ $([[ $mirror ]] && echo mirrored || echo put ) at destination $([[ $DHOST ]] && echo $DHOST:)$DPATH/$(basename $SPATH)? || return 0 fi fi cmd="$usesudo $(which rsync) ${args[*]} $SRC$([[ $insert ]] && 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 fcpy="copy -r -q -i -n -a " # alias mirror="copy -i -a -M" mirror_shell () { local dir; local dest #TODO don't overwrite hostname [ $# -lt 2 ] && echo "both a directory and remote host need to be passed" && return 2 dir=$1 [[ ! -d $dir ]] && echo no directory $dir to mirror && return 1 dest=$2 shift 2 copy $@ -i -a -c -M "$dir" "$dest:$dir" --exclude=archive* } rpush () { local dir; local dest #TODO don't overwrite hostname [ $# -lt 2 ] && echo "both a directory and remote host need to be passed" && return 2 dir=$1 [[ ! -d $dir ]] && echo no directory $dir to mirror && return 1 dest=$2 shift 2 copy "$@" -i -a "$dir" "$dest:$dir" } rpull () { local dir; local src; local dest #TODO don't overwrite hostname [ $# -lt 2 ] && echo "remote pull, both a directory and remote host need to be passed" && return 2 dir=$1 src=$2 shift 2 if [[ ! $1 == "-"* ]]; then dest=$1 shift echo pulling to alternate directory $dest fi copy "$@" -l -i "$src:$dir" "${dest:-dir}" copy "$@" -i "$src:$dir" "${dest:-dir}" } rpushmirror () { rpush "$@" -M -c } rpullmirror () { rpull "$@" -M -c } rbrowser_copy () { local browser; local dest [ $# -lt 2 ] && echo "both a browser directory (within /opt/chromium) and remote host need to be passed" && return 2 browser=$1 [[ ! -d /opt/chromium/$browser ]] && echo no browser directory /opt/chromium/$browser && return 1 dest=$2 shift 2 copy $@ -a -c -M "/opt/chromium/$browser" "$dest:/opt/chromium" --exclude=Singleton* }