Com sed
você pode fazer:
sed '24q;1,5d;12,18d' <infile >outfile
... Possivelmente uma solução mais eficiente poderia ser obtida head
. Don já demonstrou como isso pode funcionar muito bem, mas eu também tenho brincado com isso. Algo que você pode fazer para lidar com este caso específico:
for n in 5 6 7 6
do head -n"$n" >&"$((1+n%2))"
done <infile >outfile 2>/dev/null
... que chamaria head
quatro vezes escrevendo para outfile
ou para, /dev/null
dependendo se o valor dessa iteração $n
é um número par ou ímpar.
Para casos mais gerais, juntei isso de outras coisas que já tinha:
somehead()(
### call it like:
### somehead -[repeat] [-][numlines]* <infile >outfile
set -e -- "${1#-}" "$@" #-e for arg validation
r=; cd -- "${TMP:-/tmp}" #go to tmp
dd bs=4096 of="$$$$" <&4 2>&3 & #dd <in >tmpfile &bg
until [ -s "$$$$" ]; do :; done #wait while tmpfile empty
exec <"$$$$" 4<&-; rm "$$$$" #<tmpfile; rm tmpfile
[ "$3${1}0" -ne "$3${2#?}0" ] || #validate args - chk $1
shift "$(((r=-${1:--1})||1))"; shift #shift 1||2
while [ "$(((r+=(_n=1))-1))" -ne 0 ] && #while ! $rptmax &&
IFS= read -r l && # ! EOF &&
printf "%.$(($1>0?${#l}+1:0))s" "$l # ? printf do
"; do for n do [ "${n#-}" -gt 0 ] || exit #args all -[nums>0]
head "-n$((${n#-}-_n))" >&"$((n>(_n=0)?1:3))" #head -n?$1 >?[+-]
done; done #done and done
) 4<&0 3>/dev/null #4<for dd 3>for head
Isso pode ser feito da seguinte maneira:
seq 100 | somehead -1 -5 6 -7 6
... que imprime ...
6
7
8
9
10
11
19
20
21
22
23
24
Ele espera que seu primeiro argumento seja uma contagem de repetição prefixada com a -
ou, na sua falta, apenas a -
. Se uma contagem for fornecida, ela repetirá o padrão de linha fornecido nos argumentos a seguir tantas vezes quanto especificado e parará assim que isso for feito.
Para cada argumento a seguir, ele interpretará um número inteiro negativo para indicar uma contagem de linhas que deve ser gravada /dev/null
e um número inteiro positivo para indicar uma contagem de linhas que deve ser gravada stdout
.
Portanto, no exemplo acima, ele imprime as primeiras 5 linhas para /dev/null
, as próximas 6 para stdout
, as próximas 7 para /dev/null
novamente e as próximas 6 novamente para stdout
. Depois de atingir o último de seus argumentos e alternar completamente a -1
contagem de repetições, ele sai. Se o primeiro argumento tivesse sido, -2
ele repetiria o processo mais uma vez, ou -
pelo maior tempo possível.
Para cada ciclo de arg, o while
loop é processado uma vez. No topo de cada loop, a primeira linha de stdin
é lida na variável shell $l
. Isso é necessário porque while head </dev/null; do :; done
se repetirá indefinidamente - head
indica em seu retorno quando ele atinge o final do arquivo. Portanto, a verificação no EOF é dedicada read
e printf
escreverá $l
mais uma nova linha stdout
apenas se o segundo argumento for um número inteiro positivo.
A read
verificação complica um pouco o loop, porque imediatamente após outro loop ser chamado - um for
loop que itera sobre args, 2-$#
conforme representado em $n
cada iteração do while
loop pai . Isso significa que, para cada iteração, o primeiro argumento deve ser decrementado em um do valor especificado na linha de comando, mas todos os outros devem manter seus valores originais e, portanto, o valor do $_n
marcador var é subtraído de cada um, mas apenas mantém um valor valor maior que 0 para o primeiro argumento.
Isso constitui o loop principal da função, mas a maior parte do código está na parte superior e destina-se a permitir que a função armazene de maneira limpa até mesmo um pipe como entrada. Isso funciona chamando primeiro um background dd
para copiar seu arquivo tmpfile na saída em tamanhos de bloco de 4k por peça. A função então configura um loop de espera - que quase nunca deve completar nem um único ciclo completo - apenas para garantir que dd
tenha feito pelo menos uma única gravação no arquivo antes que a função substitua seu stdin por um descritor de arquivo vinculado ao tmpfile e depois, desconecta imediatamente o arquivo comrm
. Isso permite que a função processe o fluxo de maneira confiável, sem a necessidade de interrupções ou limpeza - assim que a função liberar sua reivindicação no arquivo fd, o tmpfile deixará de existir porque seu único link do sistema de arquivos nomeado já foi removido.
head
etail
? Nesse caso, sua solução é praticamente o melhor que você pode fazer. Se você tem permissão para usar outros programassed
ouawk
pode oferecer soluções melhores (ou seja, com menos invocações de processos).