Contribution:
1
hgh
h2b
h4h
2
ok
koko
lkopk
3
uh
ju
nfjvn
4
Production attendue:
1
2
3
4
Donc, je dois avoir seulement la 1ère, 5ème, 9ème, 13ème valeur du fichier dans le fichier de sortie. Comment faire ça?
Contribution:
1
hgh
h2b
h4h
2
ok
koko
lkopk
3
uh
ju
nfjvn
4
Production attendue:
1
2
3
4
Donc, je dois avoir seulement la 1ère, 5ème, 9ème, 13ème valeur du fichier dans le fichier de sortie. Comment faire ça?
Réponses:
Utilisation d'AWK:
awk '!((NR - 1) % 4)' input > output
Comprendre comment cela fonctionne est laissé comme un exercice pour le lecteur.
NR % 4 == 1
serait l'OMI plus lisible.
Utilisation de split
(GNU coreutils):
split -nr/1/4 input > output
-n
générer CHUNKS
des fichiers de sortieet CHUNKS
comme
r/K/N
utiliser la distribution à tour de rôle et ne sortir que Kth de N vers sortie standard sans séparer les lignes / enregistrementsAvec GNU sed
:
sed '1~4!d' < input > output
Avec standard sed
:
sed -n 'p;n;n;n' < input > output
Avec 1
et 4
dans $n
et $i
variables:
sed "$n~$i!d" # GNU only
awk -v n="$n" -v i="$i" 'NR >= n && (NR % i) == (n % i)'
Version Python, juste pour le plaisir:
with open('input.txt') as f:
for i, line in enumerate(f.readlines()):
if i%4 == 0:
print(line.strip())
enumerate(f)
devrait être en mesure de faire le travail tout en consommant moins de mémoire
readlines
(d'où la fusion du fichier entier en mémoire), vous pouvez utiliser f.readlines()[::4]
pour obtenir toutes les quatre lignes. Vous pouvez donc utiliser print(''.join(f.readlines()[::4]))
.
POSIX sed
: cette méthode utilise le posixly sed et peut donc être exécutée partout, ou au moins les seds qui respectent le posix.
$ sed -ne '
/\n/!{
H;s/.*//;x
}
:loop
$bdone
N;s/\n/&/4
tdone
bloop
:done
s/.//;P
' input.file
Un autre est une génération de code sed programmatique à des fins d'évolutivité:
$ code=$(yes n | head -n 4 | paste -sd\; | sed s/n/p/)
$ sed -ne "$code" input.file
Perl
: nous remplissons le tableau A jusqu'à ce qu'il ait une taille de 4. Ensuite, nous imprimons son premier élément et effaçons également le tableau.
$ perl -pe '
$A[@A] = @A ? <> : $_ while @A < 4;
$_ = (splice @A)[0];
' input.file
Appelez avec scriptname filename skip
(4 dans votre cas) Cela fonctionne en tirant des iter
lignes du haut du fichier et en ne sortant que le dernier. Il augmente ensuite iter
de skips
et se répète tant que la valeur de iter
n'a pas dépassé le lines
in file
.
#!/bin/bash
file="$1"
lines=`wc -l < "$file"`
skips="$2" || "4"
iter=1
while [ "$iter" -le "$lines" ]; do
head "$file" -n $iter | tail -n 1
iter=$(( $iter + $skips ))
done
Pure Bash:
mapfile -t lines < input
for (( i=0; i < ${#lines[@]}; i+=4 ))
do printf "%s\n" "${lines[$i]}"
done
mapfile est un module intégré ajouté dans Bash 4 qui lit l'entrée standard dans un tableau, ici nommé lines
, avec une ligne par entrée. L' -t
option supprime les nouvelles lignes finales.
Si vous souhaitez imprimer toutes les quatre lignes à partir de la ligne 4, vous pouvez le faire dans une seule commande en utilisant mapfile
l'option de rappel de -C
, qui exécute le code fourni toutes les lignes, avec l'intervalle donné par -c
. L'index du tableau actuel et la ligne suivante à affecter sont donnés au code comme arguments.
mapfile -t -c4 -C 'printf "%.0s%s\n"' < input
Cela utilise la fonction printf
intégrée; le code de format %.0s
supprime le premier argument (l'index), donc seule la ligne est imprimée.
Vous pouvez utiliser la même commande pour imprimer toutes les quatre lignes à partir de la ligne 1, 2 ou 3, mais vous devez ajouter 3, 2 ou 1 lignes input
avant de l'alimenter mapfile
, ce qui, à mon avis, est plus problématique que cela ne vaut la peine .
Cela fonctionne également:
mapfile -t lines < input
printf "%s%.0s%.0s%.0s\n" "${lines[@]}"
Ici, printf
consomme quatre entrées du tableau lines
à la fois, imprimant uniquement la première et ignorant les trois autres avec %.0s
. Je n'aime pas cela, car vous devez manipuler manuellement la chaîne de format pour différents intervalles ou points de départ.
sed -n '1~4p'