Quelle est la meilleure façon de retirer un segment d'un fichier texte?


Réponses:


12

tu pourrais essayer:

cat textfile | head -n 45 | tail -n 26

ou

cat textfile | awk "20 <= NR && NR <= 45" 

mise à jour:

Comme l'a souligné Mahomedalid, ce catn'est pas nécessaire et un peu redondant, mais cela permet une commande claire et lisible.

Si catcela vous dérange, une meilleure solution serait:

<textfile awk "20 <= NR && NR <= 45"

2
awk NR==20,NR==45 textfilefonctionne aussi et lit facilement.
éphémère

J'aime plus l'utilisation de stdin, il a une cohérence globale avec le reste de nix
Stefan

1
La lecture des arguments de la ligne de commande est également cohérente avec les autres utilitaires UNIX, et mon point principal était de démontrer l' ,opérateur de plage awk .
éphémère

lol, je voulais dire @adam. mais oui, j'aime votre suggestion
Stefan

Je pense que la réponse de @ ephemient est la meilleure ici. Sinon, les commandes sont plutôt cryptiques.
Léo Léopold Hertz 준영

13

Encore plus simple:

sed -n '20,45p;45q' < textfile

L'indicateur -n désactive la sortie par défaut. Le "20,45" concerne les lignes 20 à 45 inclusivement. La commande "p" imprime la ligne courante. Et le q se ferme après l'impression de la ligne.


1
+1 sympa, j'aime, mais sa ligne 20 à 45 :)
Stefan

1
ok ok, je l'ai édité pour dire 20,45 :-)
dkagedal

La suppression de la qcommande (tout à partir de ;) a amélioré les performances pour moi lors de l'extraction d'une seule ligne 26995107 d'un fichier de 27169334 lignes.
Ruslan

6

Ce n'est pas une réponse mais je ne peux pas la poster comme commentaire.

Une autre façon (très rapide) de le faire a été suggérée par mikeserv ici :

{ head -n 19 >/dev/null; head -n 26; } <infile

En utilisant le même fichier de test qu'ici et la même procédure, voici quelques benchmarks (extraction des lignes 1000020-1000045):

mikeserv :

{ head -n 1000019 >/dev/null; head -n 26; } <iplist

real    0m0.059s

Stefan :

head iplist -n 1000045 | tail -n 26

real    0m0.054s

Ce sont de loin les solutions les plus rapides et les différences sont négligeables (pour un seul passage) (j'ai essayé avec différentes gammes: quelques lignes, des millions de lignes etc).

Le faire sans le tuyau pourrait cependant offrir un avantage significatif à une application qui devait rechercher sur plusieurs gammes de lignes de manière similaire, comme:

for  pass in 0 1 2 3 4 5 6 7 8 9
do   printf "pass#$pass:\t"
     head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES

... qui imprime ...

pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000

... et ne lit le fichier qu'une seule fois.


Les autres solutions sed/ awk/ perllisent tout le fichier et comme il s'agit de fichiers énormes, elles ne sont pas très efficaces. J'ai ajouté quelques alternatives qui exitou qaprès la dernière ligne de la plage spécifiée:

Stefan :

awk "1000020 <= NR && NR <= 1000045" iplist

real    0m2.448s

contre.

awk "NR >= 1000020;NR==1000045{exit}" iplist

real    0m0.243s

dkagedal ( sed):

sed -n 1000020,1000045p iplist

real    0m0.947s

contre.

sed '1,1000019d;1000045q' iplist

real    0m0.143s

Steven D :

perl -ne 'print if 1000020..1000045' iplist

real    0m2.041s

contre.

perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist

real    0m0.369s

+1 Je pense que c'est la meilleure réponse ici! Ce serait bien de savoir combien de temps cela prend awk NR==1000020,NR==1000045 textfiledans votre système.
Léo Léopold Hertz 준영

3
ruby -ne 'print if 20 .. 45' file

1
un autre rubyist, vous obtenez mon vote monsieur
Stefan

1
Pendant que nous y sommes, pourquoi pas python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'aussi? :-P C'est quelque chose que Ruby, inspiré de Perl, inspiré de awk / sed, peut facilement faire.
éphémère

2

Puisque sed et awk ont ​​déjà été pris, voici une solution perl:

perl -nle "print if ($. > 19 && $. < 46)" < textfile

Ou, comme indiqué dans les commentaires:

perl -ne 'print if 20..45' textfile

2
Qu'y a-t-il avec tous ces personnages supplémentaires? Pas besoin de supprimer et de rajouter des nouvelles lignes, la bascule suppose une comparaison avec le numéro de ligne et l'opérateur de diamant passe en revue les arguments s'il est fourni. perl -ne'print if 20..45' textfile
éphémère du

1
Agréable. -nle est un peu un réflexe je suppose, comme pour le reste, je n'ai aucune excuse sauf l'ignorance.
Steven D
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.