Tomando estritamente o " just Bash e nada mais ", aqui está uma adaptação das respostas anteriores ( @ Chris , @ 131 ) que não chama nenhum utilitário externo (nem mesmo o padrão), mas também funciona com arquivos binários:
#!/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>&-
}
Use com download http://path/to/file > file
.
Lidamos com NUL bytes com read -d ''
. Ele lê até um byte NUL e retorna true se encontrou um, false se não encontrou. O Bash não pode manipular NUL bytes em cadeias de caracteres, portanto, quando read
retorna com true, adicionamos o byte NUL manualmente ao imprimir e, quando retorna false, sabemos que não há mais bytes NUL e esse deve ser o último dado .
Testado com o Bash 4.4 em arquivos com NULs no meio e terminando em zero, um ou dois NULs, e também com os binários wget
e curl
do Debian. O wget
binário de 373 kB levou cerca de 5,7 segundos para baixar. Uma velocidade de cerca de 65 kB / s ou um pouco mais que 512 kb / s.
Em comparação, a solução de gato do @ 131 termina em menos de 0,1 s, ou quase cem vezes mais rápido. Não é muito surpreendente, realmente.
Isso é obviamente tolo, já que sem o uso de utilitários externos, não há muito o que fazer com o arquivo baixado, nem torná-lo executável.
gawk