Se eu entendi sua pergunta corretamente, você quer extrair um arquivo enviado de uma solicitação que consiste em:
- uma linha que consiste em traços seguidos de dígitos hexadecimais;
- um monte de linhas não vazias (cabeçalhos);
- uma linha vazia;
- o conteúdo a extrair;
- quebra de linha;
- uma repetição da primeira linha;
em que as quebras de linha são uma sequência CRLF e o conteúdo pode conter bytes arbitrários, mas os cabeçalhos não contêm bytes nulos.
Em vez de confiar em head
e tail
para analisar linhas, você pode fazer isso em duas etapas:
- Determine o intervalo de posições de bytes que você deseja extrair.
- Extraia esses bytes.
Na primeira etapa, para evitar problemas com bytes nulos, use tr
para traduzi-los para outra coisa. Então você pode usar uma ferramenta baseada em linha para detectar a primeira linha vazia e para detectar o início da última linha. Eu uso o awk abaixo e aproveito a oportunidade para também extrair o nome do arquivo. Se você não tiver o awk, poderá usar head
, tail
, sed
,…
Para a segunda etapa, você pode usar dd
com um tamanho de bloco de 1. Isso é lento, mas confiável.
upload=24593.tmp
filename=$(<"$upload" tr 'upload=24593.tmp
filename=$(<"$upload" tr '%pre%' _ | awk '
{line_start = line_end; line_end += length($0)+1}
!content_start && /^Content-Disposition:.*filename="/ {
sub(/.*filename="/, ""); sub(/".*/, "");
filename = $0
}
!content_start && $0=="\r" {content_start=line_end}
END {print content_start, line_start-2-content_start, filename}
')
skip=${filename%% *}; filename=${filename#* }
count=${filename%% *}; filename=${filename#* }
if [ -z "$filename" ]; then filename=$(mktemp); fi
<$upload dd bs=1 skip="$skip" count="$count" >"$filename"
' _ | awk '
{line_start = line_end; line_end += length($0)+1}
!content_start && /^Content-Disposition:.*filename="/ {
sub(/.*filename="/, ""); sub(/".*/, "");
filename = $0
}
!content_start && $0=="\r" {content_start=line_end}
END {print content_start, line_start-2-content_start, filename}
')
skip=${filename%% *}; filename=${filename#* }
count=${filename%% *}; filename=${filename#* }
if [ -z "$filename" ]; then filename=$(mktemp); fi
<$upload dd bs=1 skip="$skip" count="$count" >"$filename"