Con sed
usted podría hacer:
sed '24q;1,5d;12,18d' <infile >outfile
... Posiblemente se podría tener una solución más eficiente head
. Don ya ha demostrado cómo eso podría funcionar muy bien, pero también he estado jugando con eso. Algo que puede hacer para manejar 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 llamar head
4 veces escrito, ya sea a outfile
o /dev/null
en función de si el valor de esa iteración de $n
un número par o impar.
Para casos más generales, combiné esto con otras cosas que ya tenía:
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
Esto puede hacer lo tuyo como:
seq 100 | somehead -1 -5 6 -7 6
... que imprime ...
6
7
8
9
10
11
19
20
21
22
23
24
Espera que su primer argumento sea un recuento repetido con el prefijo a -
, o, en su defecto, solo a -
. Si se proporciona un conteo, repetirá el patrón de línea dado en los siguientes argumentos tantas veces como se especifique y se detendrá tan pronto como lo haya hecho.
Para cada argumento que sigue, interpretará un entero negativo para indicar un recuento de líneas en el que se debe escribir /dev/null
y un entero positivo para indicar un recuento de líneas en el que se debe escribir stdout
.
Entonces, en el ejemplo anterior, imprime las primeras 5 líneas en /dev/null
, las siguientes 6 en stdout
, las siguientes 7 en /dev/null
otra vez y las siguientes 6 una vez más en stdout
. Después de haber alcanzado el último de sus argumentos y completar un ciclo completo a través del -1
recuento repetido, se cierra. Si el primer argumento hubiera sido -2
, habría repetido el proceso una vez más, o -
durante el mayor tiempo posible.
Para cada ciclo arg, el while
ciclo se procesa una vez. En la parte superior de cada bucle, la primera línea de stdin
se lee en la variable de shell $l
. Esto es necesario porque while head </dev/null; do :; done
se repetirá indefinidamente, head
indica en su devolución cuando ha llegado al final del archivo. Por lo tanto, la verificación contra EOF está dedicada read
y printf
escribirá $l
más una nueva línea stdout
solo si el segundo argumento es un entero positivo.
La read
verificación complica un poco el ciclo porque inmediatamente después de que se llama a otro ciclo, un for
ciclo que itera sobre args 2-$#
como se representa en $n
cada iteración de su while
ciclo principal . Esto significa que para cada iteración, el primer argumento debe reducirse en uno del valor especificado en la línea de comando, pero todos los demás deben conservar sus valores originales, por lo que el valor del $_n
marcador var se resta de cada uno, pero solo tiene un valor valor mayor que 0 para el primer argumento.
Eso constituye el bucle principal de la función, pero la mayor parte del código está en la parte superior y está destinado a permitir que la función almacene limpiamente incluso una tubería como entrada. Esto funciona llamando primero a un fondo dd
para copiarlo en un archivo tmp en la salida en bloques de 4k por pieza. Luego, la función configura un ciclo de retención, que casi nunca debería completar ni un solo ciclo completo, solo para asegurarse de que dd
haya realizado al menos una sola escritura en el archivo antes de que la función reemplace su stdin con un descriptor de archivo vinculado al archivo tmp y luego inmediatamente desvincula el archivo conrm
. Esto permite que la función procese de manera confiable la secuencia sin requerir trampas o de otro modo para la limpieza: tan pronto como la función lo libere en el fd, el archivo tmp dejará de existir porque su único enlace de sistema de archivos con nombre ya se ha eliminado.
head
ytail
? Si es así, su solución es prácticamente lo mejor que puede hacer. Si tiene permiso para usar otros programas,sed
oawk
podría permitir soluciones más agradables (es decir, con menos invocaciones de procesos).