Monday, February 16, 2009

Fancy move/copy commands

Upadte- 2/23/2009 4:25 PM
Updated the action detection to work for the mv variant as well.



Ok, here is a nice wrapper script I wrote in bash. It adds a nice progress bar tot he cp and mv commands Linux.

To install just save this file someplace and give it execute rights. Then create symbolic links for cp and mv in your $PATH.

$> mkdir ~/bin
Save as ~/bin/nice.ops
$> ln -s ~/bin/nice.ops ~/bin/cp
$> ln -s ~/bin/nice.ops ~/bin/mv
Added ~/bin to $PATH in ~/.bashrc


Code:
nice.ops
#!/bin/bash

# This is a custom wrapper for the cp and mv commands in *nix. It adds a nice progress bar to the file operation.
# Jeremy Pyne

# Config, Set command mode here if auto-detect doesn't work.
action= # cp|mv
message= # Copying|Moving

# Auto-detect command type.
if [ -z $action ] ; then
case `expr "$0" : '.*\(/cp\|/mv\)'` in
/cp)
action=cp
message=Copying
;;
/mv)
action=mv
message=Moving
;;
esac
fi

# Default Variables
dest=
quiet=0
detail=0
dest_dir=0
dest_size=0
pct=0

# Throw a usage message if there are to few parameters.
if [ $# -lt 2 ] ; then
/bin/$action $@
exit
fi

# Loop through each argument.
for arg ; do
case $arg in
# Show extra details.
--detail)
detail=1
continue ;;
# Show less details.
--quiet)
quiet=1
continue ;;
esac

# If there was a destination, change it to a source file.
if [ "$dest" ] ; then
files[${#files[@]}]="$dest"
fi

# Set the current item as the destination.
dest="$arg"
done

# Calculate the source file cound and size.
orig_size=`du -s "${files[@]}" | awk 'BEGIN{total=0}{total+=$1}END{print total}'`
orig_count=`find "${files[@]}" | awk 'BEGIN{total=0}{total++}END{print total}'`

# Show a info message.
if [ $quiet -eq 0 ] ; then
echo $message $orig_count files $orig_size bytes to $dest.
fi

# If a single source directory is being used, it will be renamed so we need to gets it's contents.
if [ ${#files[@]} -eq 1 -a -d "${files[0]}" ] ; then
# Flag the rename bit se we can properly look for files.
dest_dir=1
IFS=$'\n'
# Store each direct child of the source directory.
for file in `cd "${files[@]}" && ls ` ; do
ofiles[${#ofiles[@]}]="$file"
done
IFS=$' '
fi

# Preform the acctual copy or move command.
/bin/$action -f $params "${files[@]}" "$dest" 2>/tmp/.error &

# Start with a empty progress bar.
echo -en "[> 0%]\b\b\b\b\b"
sleep 1

# If there was an error echo it out and exit.
if [ -s /tmp/.error ] ; then
cat /tmp/.error
rm /tmp/.error
exit 1
fi

# If the source files were empty, just skip to 100% and exit.
if [ $orig_size -eq 0 ] ; then
echo -e "#>100%]\b\b\b\b\b\b"
exit 0
fi

# While still copying, update the progress bar.
while [ $orig_size -gt $dest_size ] ; do
if [ $dest_dir -eq 1 ] ; then
# If this was a single directory operation, check the new directories contents.
dest_size=`cd "$dest" && du -s "${ofiles[@]}" 2>/dev/null | awk 'BEGIN{total=0}{total+=$1}END{print total+4}'`
dest_count=`cd "$dest" && find "${ofiles[@]}" 2>/dev/null | awk 'BEGIN{total=0}{total++}END{print total}'`
elif [ -f "$dest" ] ; then
# If this was a single file operation, check the new file.
dest_size=`du -s "$dest" | awk 'BEGIN{total=0}{total+=$1}END{print total}'`
dest_count=`find "$dest" | awk 'BEGIN{total=0}{total++}END{print total}'`
elif [ -d "$dest" ] ; then
# If this was a many to one directory operation, check for the source items in the new directory.
dest_size=`cd "$dest" && du -s "${files[@]}" 2>/dev/null | awk 'BEGIN{total=0}{total+=$1}END{print total}'`
dest_count=`cd "$dest" && find "${files[@]}" 2>/dev/null | awk 'BEGIN{total=0}{total++}END{print total}'`
fi

# Calculate the operation percentage.
pct=$((( 100 * $dest_size ) / $orig_size ))

# Move the the start of the line and clear it.
echo -en "\033[120D\033[K["
# For 0 to 100
for count in `seq -s " " 0 50`; do
if [ $count -eq $(($pct / 2)) ] ; then
# Print a '>' at the current percent.
echo -ne "\033[s>"
elif [ $count -lt $(($pct / 2)) ] ; then
# Print a '#' for compleated area.
echo -n "#"
else
# Print a ' ' for space not done.
echo -n " "
fi
done
# Print the percentage and restore the cursor to the '>' icon.
echo -en "$pct%]\033[u"

# If detail was set, show extra info.
if [ $detail -eq 1 -a $quiet -eq 0 ] ; then
echo -en "\033[s"
echo -en "\033[1A\033[120D\033[K"
echo -en $message $dest_count/$orig_count files $dest_size/$orig_size bytes to $dest.
echo -en "\033[u"
fi
# Wait 1 second.
sleep 1
done
echo

exit 0

No comments: