${string:offset:length} é um operador de expansão de parâmetro que se expande para o intervalo de caracteres na variável $string .
Para obter um intervalo de bytes da entrada (e que também se aplica a caracteres de byte único), você pode usar:
func | tail -c +12 | head -c 5
para obter 5 bytes começando com o 12º (offsets baseados em 1). A opção -c para head não é padrão, mas é bastante comum.
Observe que func pode ser eliminado algum tempo depois de ter emitido seu 16º byte, pois head sairá depois de ter esses 5 bytes, e tail será eliminado se tentar gravar mais dados depois disso, que iria ondular para func .
Você também pode fazer:
func | dd bs=1 skip=11 count=5 2> /dev/null
2> /dev/null é para evitar a mensagem de status no final. Isso suprime todos os erros. Com o GNU dd , você pode substituí-lo por status=none para apenas suprimir o status.
Para valores grandes de length , isso seria menos eficiente ao ler um byte de cada vez. Com o GNU dd novamente, você pode evitar isso fazendo:
func | dd iflag=count_bytes,skip_bytes,fullblock skip=11 bs=64k count=5M status=none
Que faria tantas leituras de até 64 KiB cada para obter 5 MiB de bytes de dados.
Agora, para aqueles offset e length a serem expressos em caracteres (single ou multi-byte) ao invés de byte, isso se torna mais complicado.
Uma opção é armazenar toda a saída em uma variável e usar o operador ${var:offset:length} como outras pessoas mostraram . Embora isso signifique armazenar toda a saída na memória. Usar var=$(func) também significa que os caracteres da nova linha são descartados.
Outra opção é usar bash de read -N , que lê um determinado número de caracteres :
func | {
IFS= read -rN 11 discarded
IFS= read -rN 5 data
printf '%s\n' "$data"
}
Ou com perl (um pouco mais eficiente para dados grandes):
func | perl -Mopen=locale -sne '
BEGIN{$total = $o + $n; $/ = \$total}
print substr($_, $o); exit' -- -o=10000 -n=5000000