Якщо чітко взяти " просто Баш і нічого іншого ", ось одна адаптація попередніх відповідей ( @ Chris's , @ 131's ), яка не викликає жодних зовнішніх утиліт (навіть стандартних), але також працює з бінарними файлами:
#!/bin/bash
download() {
read proto server path <<< "${1//"/"/ }"
DOC=/${path// //}
HOST=${server//:*}
PORT=${server//*:}
[[ x"${HOST}" == x"${PORT}" ]] && PORT=80
exec 3<>/dev/tcp/${HOST}/$PORT
# send request
echo -en "GET ${DOC} HTTP/1.0\r\nHost: ${HOST}\r\n\r\n" >&3
# read the header, it ends in a empty line (just CRLF)
while IFS= read -r line ; do
[[ "$line" == $'\r' ]] && break
done <&3
# read the data
nul='\0'
while IFS= read -d '' -r x || { nul=""; [ -n "$x" ]; }; do
printf "%s$nul" "$x"
done <&3
exec 3>&-
}
Використовуйте с download http://path/to/file > file
.
Ми маємо справу з байтами NUL read -d ''
. Він читає, поки не буде байт NUL, і повертає true, якщо він знайшов його, false, якщо не. Bash не може обробляти байтів NUL у рядках, тому, коли read
повертається з true, ми додаємо байт NUL вручну під час друку, а коли він повертає помилкове значення, ми знаємо, що більше немає байтів NUL, і це має бути останній фрагмент даних .
Тестується з Bash 4.4 на файлах з NUL в середині, і закінчуючи нулем, однією або двома NUL, а також з wget
і бінарними файлами curl
від Debian. Для завантаження wget
двійкового файлу 373 кБ було потрібно близько 5,7 секунди. Швидкість близько 65 кБ / с або трохи більше 512 кб / с.
Для порівняння, розчин кішки @ 131 закінчується менш ніж за 0,1 с, або майже в сто разів швидше. Не дуже дивно, насправді.
Це, очевидно, нерозумно, оскільки без використання зовнішніх утиліт ми не можемо багато зробити із завантаженим файлом, навіть не зробити його виконуваним.
gawk