Avec sed
vous pourriez faire:
sed '24q;1,5d;12,18d' <infile >outfile
... Peut-être une solution plus efficace pourrait être trouvée avec head
. Don a déjà montré comment cela pouvait très bien fonctionner, mais j'ai aussi joué avec. Quelque chose que vous pourriez faire pour gérer ce cas spécifique:
for n in 5 6 7 6
do head -n"$n" >&"$((1+n%2))"
done <infile >outfile 2>/dev/null
... qui appellerait head
4 fois l'écriture vers outfile
ou vers /dev/null
selon que la valeur de cette itération $n
est un nombre pair ou impair.
Pour des cas plus généraux, j'ai bricolé cela à partir d'autres choses que j'avais déjà:
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
Cela peut faire votre chose comme:
seq 100 | somehead -1 -5 6 -7 6
... qui imprime ...
6
7
8
9
10
11
19
20
21
22
23
24
Il s'attend à ce que son premier argument soit un nombre de répétitions préfixé par un -
, ou, à défaut, juste un -
. Si un décompte est fourni, il répétera le modèle de ligne donné dans les arguments suivants autant de fois que spécifié et s'arrêtera dès qu'il l'aura fait.
Pour chaque argument qui suit, il interprétera un entier négatif pour indiquer un compte de lignes qui doit être écrit /dev/null
et un entier positif pour indiquer un compte de lignes qui doit être écrit stdout
.
Ainsi, dans l'exemple ci-dessus, il imprime les 5 premières lignes /dev/null
, les 6 suivantes stdout
, les 7 suivantes /dev/null
et les 6 suivantes à nouveau stdout
. Après avoir atteint le dernier de ses arguments et entièrement parcouru le -1
nombre de répétitions, il se ferme ensuite. Si le premier argument avait été, -2
il aurait répété le processus une fois de plus, ou si -
aussi longtemps qu'il le pouvait.
Pour chaque cycle d'arg, la while
boucle est traitée une fois. En haut de chaque boucle, la première ligne de stdin
est lue dans la variable shell $l
. Ceci est nécessaire car while head </dev/null; do :; done
se répétera indéfiniment - head
indique dans son retour quand il a atteint la fin du fichier. Ainsi, la vérification par rapport à EOF est dédiée read
et printf
n'écrira $l
plus une nouvelle ligne stdout
que si le deuxième argument est un entier positif.
La read
vérification complique un peu la boucle car immédiatement après l'appel d'une autre boucle - une for
boucle qui itère sur les arguments 2-$#
comme représenté dans $n
chaque itération de sa while
boucle parent . Cela signifie que pour chaque itération, le premier argument doit être décrémenté de un de la valeur spécifiée sur la ligne de commande, mais tous les autres doivent conserver leurs valeurs d'origine, et donc la valeur du $_n
marqueur var est soustraite de chacun, mais ne contient que valeur supérieure à 0 pour le premier argument.
Cela constitue la boucle principale de la fonction, mais la majeure partie du code est en haut et est destinée à permettre à la fonction de tamponner proprement même un tuyau en entrée. Cela fonctionne en appelant d'abord un arrière-plan dd
pour copier son entrée dans un fichier tmp en sortie à des blocs de 4k par morceau. La fonction établit ensuite une boucle d'attente - qui ne devrait presque jamais terminer même un seul cycle complet - juste pour s'assurer qu'elle dd
a effectué au moins une seule écriture dans le fichier avant que la fonction ne remplace ensuite son stdin par un descripteur de fichier lié au fichier tmp et dissocie ensuite immédiatement le fichier avecrm
. Cela permet à la fonction de traiter le flux de manière fiable sans nécessiter d'interruptions ou autrement pour le nettoyage - dès que la fonction libère sa revendication sur le fd, le fichier tmp cessera d'exister car son seul lien de système de fichiers nommé a déjà été supprimé.
head
ettail
? Si c'est le cas, votre solution est à peu près la meilleure que vous puissiez faire. Si vous êtes autorisé à utiliser d'autres programmes,sed
ouawk
si vous autorisez de meilleures solutions (c'est-à-dire avec moins d'appels de processus).