#!/bin/bash # Copyright 2013 Norman Carver # # cp viewer -- Bash shell script to use pv (pipe viewer) to copy files, # so see progress and rate info, but accepts cp's argument syntax. # # Syntax: cpv [OPTION] SOURCE DESTINATION # cpv [OPTION] SOURCE... DIRECTORY # cpv [OPTION] -t DIRECTORY SOURCE... # Options: # -i for interactive (overrides previous -n)" # -n for no clobber (overrides previous -i)" # # Copies only regular files (so does not behave exactly like cp)! # # Requires: pv (pipe viewer) # # Version history: # 1.0 (07/28/2013) Initial public release # 1.1 (03/08/2014) Minor cleanup/improvements # Copyright 2013-2014 Norman Carver # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or (at # your option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Change default options used by pv if desired: # E.g., to show only progress bar: pvoptions="-p" # See "man pv" for options, default is like -pterb. pvoptions= # Make certain pv program is installed: if ! which pv &> /dev/null; then echo "Program pv (pipe viewer) required, please install first!" exit 1 fi function print_usage() { echo "Usage: cpv [OPTION] SOURCE DESTINATION" echo " cpv [OPTION] SOURCE... DIRECTORY" echo " cpv [OPTION] -t DIRECTORY SOURCE... " echo " Options:" echo " -i for interactive (overrides previous -n)" echo " -n for no clobber (overrides previous -i)" } # Function to determine if copy action should be done: # Takes two arguments, (1) source path, (2) target/copy path. function do_copy() { source=$1 target=$2 # Check that source is a regular file: if [[ ! -f "${source}" ]]; then type=$(stat --format="%F" "${source}") echo "$0: omitting ${type} \`${source}'" return 1 fi # Check whether will overwrite file: if ( $interactive || $noclobber ) && [[ -e "${target}" ]]; then if $interactive; then echo -n "$0: overwrite \`$target'?" if read && [[ ! "$REPLY" =~ ^[yY].*$ ]]; then return 1 fi else return 1 fi fi return 0 } # Check that number of arguments was valid: if [[ $# -lt 2 ]]; then print_usage exit 1 fi # Decode options: reverse=false interactive=false noclobber=false while getopts ":int" opt; do case $opt in i) interactive=true noclobber=false ;; n) noclobber=true interactive=false ;; t) reverse=true ;; \?) print_usage exit 1 ;; esac done shift $((OPTIND-1)) # Check that number of file arguments is valid: if [[ $# -lt 2 ]]; then print_usage exit 1 fi # Determine which syntax case we have and do copying: lastarg=${!#} if $reverse || [[ -d "${lastarg}" ]]; then # File(s) are to be copied to a directory, so # first determine the directory: if $reverse; then directory="${1}" first=2 last=$# else directory=$lastarg first=1 last=$(($# - 1)) fi for (( i=$first ; i <= $last ; i++ )); do source=${!i} target=${directory}/$(basename "${source}") if do_copy "${source}" "${target}"; then if [[ $last -gt $first ]]; then echo "${source}:"; fi pv $pvoptions "${source}" > "${target}" fi done else # A single file is to be copied: if [[ $# != 2 ]]; then print_usage exit 1 fi source=$1 target=$2 if do_copy "${source}" "${target}"; then pv $pvoptions "${source}" > "${target}" fi fi # Normal completion: exit # EOF