427
社区成员
发帖
与我相关
我的任务
分享
#!/bin/bash
#This Script utilizes curls ability to download files in parts
#
#Project: http://code.google.com/p/splitcurl
#License: http://directory.fsf.org/wiki/License:BSD_3Clause
#Check parameters
if [[ -z "$1" ]]
then
echo "Where's the URL?"
echo -e "Usage:\n\t`basename $0` URL [SPLITNUM(4)]"
exit 1
fi
SPLITNUM=${2:-4}
URL=$1
if [[ ! -z "$3" ]]
then
FILENAME="$3"
else
FILENAME="`basename $URL`"
FILENAME="${FILENAME%%\?*}"
fi
PART_DIR=."$FILENAME".part
mkdir -pv "$PART_DIR"
SIZE="`curl -sqI "$URL" 2> /dev/null | tr -d '\015' | awk '/^$/{exit} /Length/ {print $2}' | grep -o '[0-9]*'`"
SIZE=${SIZE:-1}
#SIZE=2798594411
if [[ ! -z $4 ]]
then
SIZE=$4
fi
[ $SIZE -gt 0 ] || SPLITNUM=1
START=0
CHUNK=$((${SIZE:-0}/$SPLITNUM))
END=$CHUNK
#Cleanup on kill
function clean {
echo "cleaning..."
# kill 0
#rm /tmp/$FILENAME.* 2> /dev/null
#rm -r "$PART_DIR"> /dev/null
echo "Download failed!"
exit 1
}
#Trap ctrl-c
trap 'clean' SIGINT SIGTERM
#Test splitness
OUT=`curl -m 10 --range 0-0 "$URL" 2> /dev/null | while read -n 1 C
do
OUT="${OUT}½"
echo ${OUT}
[ ${#OUT} -gt 1 ] && break
done`
#Check out
case ${#OUT} in
0) clean;; #Curl error
1) ;; #Got a byte
*) echo Server does not spit...;SPLITNUM=1;; #Got more than asked for
esac
function curl_part {
PART_NUM=$1
PART_START=$2
PART_END=$3
CRANGE_START=$PART_START
CRANGE_END=$PART_END
# curl --ftp-pasv -o /tmp/$FILENAME.$PART --range $START-$END $URL 2> /dev/null &
try=0
while true
do
if [[ -e "$PART_DIR/$FILENAME.$PART_NUM" ]]
then
PART_SKIP=`ls -l "$PART_DIR/$FILENAME.$PART_NUM" | awk '{print $5}'`
CRANGE_START=$(($PART_START+$PART_SKIP))
fi
if [[ $CRANGE_START -gt $CRANGE_END ]]
then
# echo "downloaded $FILENAME, part ($PART_NUM, $PART_START, $PART_END, $(($PART_END - $PART_START + 1)))"
break
fi
#echo "downloading $FILENAME, part ($PART_NUM, $PART_START, $PART_END, $CRANGE_START, $CRANGE_END), try = $try"
curl --ftp-pasv --range $CRANGE_START-$CRANGE_END "$URL" $PART_NUM >> "$PART_DIR/$FILENAME.$PART_NUM" 2>/dev/null
try=$(($try + 1))
done
}
#Invoke curls
for PART in $(seq 1 $SPLITNUM)
do
# curl --ftp-pasv -o /tmp/$FILENAME.$PART --range $START-$END $URL 2> /dev/null &
if [[ $PART -eq $SPLITNUM ]]
then
END=$(($SIZE - 1))
fi
curl_part $PART $START $END &
START=$(($START+$CHUNK+1))
END=$(($START+$CHUNK))
done
TIME=$((`date +%s`-1))
ORIGSIZE=$((`eval ls -l "$PART_DIR/$FILENAME".{1..$SPLITNUM} 2> /dev/null|awk 'BEGIN{SUM=0}{SUM=SUM+$5}END{print SUM}'`))
function calc {
GOTSIZE=$((`eval ls -l "$PART_DIR/$FILENAME".{1..$SPLITNUM} 2> /dev/null|awk 'BEGIN{SUM=0}{SUM=SUM+$5}END{print SUM}'`))
SIZEDIFF=$(($GOTSIZE - $ORIGSIZE))
if [[ $SIZEDIFF -eq 0 ]]
then
return
fi
TIMEDIFF=$(( `date +%s` - $TIME ))
RATE=$(( ($SIZEDIFF / $TIMEDIFF)/1024 ))
PCT=$(( ($GOTSIZE * 100) / $SIZE ))
if [[ $RATE -eq 0 ]]
then
return
fi
ETA=$((($SIZE-$GOTSIZE) / 1024 / $RATE))
ETA_STR="$ETA"s
if [[ $ETA -gt 60 ]]
then
ETA_STR="$(($ETA / 60))m$(($ETA % 60))s"
ETA=$(($ETA / 60))
fi
if [[ $ETA -gt 60 ]]
then
ETA_STR="$(($ETA / 60))h$(($ETA % 60))m"
ETA=$(($ETA / 60))
fi
if [[ $ETA -gt 24 ]]
then
ETA_STR="$(($ETA / 24))d$(($ETA % 24))h"
fi
}
function b2h {
F_SIZE=$1
F_SIZE_STR="$F_SIZE "b
if [[ $F_SIZE -ge 1024 ]]
then
F_SIZE_STR=$(echo "scale=2;$1/1024" | bc )KB
F_SIZE=$(($F_SIZE / 1024 ))
fi
if [[ $F_SIZE -ge 1024 ]]
then
F_SIZE_STR=$(echo "scale=2;$1/1024/1024" | bc )MB
F_SIZE=$(($F_SIZE / 1024 ))
fi
if [[ $F_SIZE -ge 1024 ]]
then
F_SIZE_STR=$(echo "scale=2;$1/1024/1024/1024" | bc )GB
fi
echo "$F_SIZE_STR"
}
#Wait for all parts to complete while spewing progress
echo "Downloading $FILENAME ($SIZE, $(b2h $SIZE)) at `date`"
SECS=1
while jobs | grep -q Running
do
if [[ $(($SECS % 3 )) -eq 0 ]]
then
TIME=$((`date +%s`-1))
ORIGSIZE=$((`eval ls -l "$PART_DIR/$FILENAME".{1..$SPLITNUM} 2> /dev/null|awk 'BEGIN{SUM=0}{SUM=SUM+$5}END{print SUM}'`))
fi
PART_LEFT=$(jobs | grep Running | wc -l)
calc
echo -n "$SPLITNUM parts, $PART_LEFT jobs, $(b2h $(($SIZE - $GOTSIZE))) left @ $RATE kb/s ($PCT%), ETA($ETA_STR). "
tput ech ${#SIZE}
tput cub 1000
sleep 1
SECS=$(($SECS + 1))
done
calc
echo "Downloading $FILENAME in $SPLITNUM parts: $GOTSIZE / $SIZE bytes @ $RATE kb/s ($PCT%). "
#Join all the parts
eval cat "$PART_DIR/$FILENAME".{1..$SPLITNUM} > "$FILENAME"
echo "Files done!"
rm -r "$PART_DIR" 2> /dev/null