635 votes

Comment extraire une plage prédéterminée de lignes d'un fichier texte sous Unix ?

J'ai un dump SQL de ~23000 lignes contenant des données de plusieurs bases de données. Je dois extraire une certaine section de ce fichier (c'est-à-dire les données d'une seule base de données) et la placer dans un nouveau fichier. Je connais les numéros de ligne de début et de fin des données que je veux.

Est-ce que quelqu'un connaît une commande Unix (ou une série de commandes) pour extraire toutes les lignes d'un fichier entre disons les lignes 16224 et 16482 et les rediriger ensuite dans un nouveau fichier ?

0 votes

Puisque vous mentionnez les gros fichiers, je suggère de vérifier le commentaire stackoverflow.com/questions/83329/

922voto

boxxar Points 2051
sed -n '16224,16482p;16483q' filename > newfile

De la manuel de sed :

p - Imprimer l'espace du motif (sur la sortie standard). Cette commande n'est généralement utilisée qu'en conjonction avec l'option de ligne de commande -n.

n - Si l'impression automatique n'est pas désactivée, elle imprime l'espace du motif, puis, indépendamment de cela, remplace l'espace du motif par la ligne d'entrée suivante. Si s'il n'y a plus d'entrée, sed quitte sans traiter d'autres commandes. commandes.

q - Exit sed sans traiter d'autres commandes ou entrées. Notez que l'espace du motif courant est imprimé si l'impression automatique n'est pas désactivée avec l'option -n.

y

Les adresses dans un script sed peuvent être sous l'une des formes suivantes :

numéro La spécification d'un numéro de ligne ne correspondra qu'à cette ligne dans l'entrée.

Une plage d'adresses peut être spécifiée en indiquant deux adresses séparées par une virgule (,). Une plage d'adresses correspond aux lignes commençant par où la première adresse correspond, et continue jusqu'à ce que la deuxième adresse correspond (inclusivement).

3 votes

J'étais curieux de savoir si cela modifiait le fichier original. Je l'ai sauvegardé juste au cas où et il semble que cela n'ait PAS modifié l'original, comme prévu.

1 votes

@AndyGroff. Pour modifier le fichier en place, utilisez le paramètre "-i". Sinon, il ne modifiera pas le fichier.

206 votes

Si, comme moi, vous devez effectuer cette opération sur un fichier TRES volumineux, il est utile d'ajouter une commande quit sur la ligne suivante. Ensuite, c'est sed -n '16224,16482p;16483q' filename . Sinon, sed continuera à scanner jusqu'à la fin (ou du moins ma version le fait).

223voto

JXG Points 3877
sed -n '16224,16482 p' orig-data-file > new-file

Où 16224,16482 sont le numéro de ligne de début et le numéro de ligne de fin, inclusivement. Il s'agit d'une indexation de type 1. -n supprime l'écho de l'entrée en tant que sortie, ce que vous ne voulez clairement pas ; les chiffres indiquent la plage de lignes sur laquelle la commande suivante doit opérer ; la commande p imprime les lignes concernées.

9 votes

Pour les fichiers volumineux, la commande ci-dessus continuera à parcourir l'ensemble du fichier après avoir trouvé la plage souhaitée. Existe-t-il un moyen de faire en sorte que sed arrête de traiter le fichier une fois la plage trouvée ?

45 votes

Eh bien, de la réponse ici il semble que l'arrêt à la fin de la gamme pourrait être accompli avec : sed -n '16224,16482p;16482q' orig-data-file > new-file .

7 votes

Pourquoi mettre un espace inutile, et ensuite devoir citer ? (Bien sûr, créer des problèmes inutiles et les résoudre est l'essence de la moitié de l'informatique, mais je veux dire à côté de cette raison ...)

126voto

manveru Points 1474

Assez simple en utilisant la tête/queue :

head -16482 in.sql | tail -258 > out.sql

en utilisant sed :

sed -n '16224,16482p' in.sql > out.sql

en utilisant l'awk :

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

2 votes

Les deuxième et troisième options sont correctes, mais la première est plus lente que de nombreuses autres car elle utilise deux commandes là où une seule suffit. Elle nécessite également un calcul pour obtenir le bon argument à la commande tail .

3 votes

Il est intéressant de noter que pour garder les mêmes numéros de ligne que la question, la commande sed devrait être sed -n 16224,16482p' in.sql >out.sql et la commande awk devrait être awk 'NR>=16224&&NR<=16482' in.sql > out.sql

3 votes

Il faut également savoir que dans le cas du premier exemple head -16482 in.sql | tail -$((16482-16224)) >out.sql laisse le calcul à bash

42voto

Mark Janssen Points 6155

Vous pouvez utiliser 'vi' et ensuite la commande suivante :

:16224,16482w!/tmp/some-file

Alternativement :

cat file | head -n 16482 | tail -n 258

EDIT:- Juste pour ajouter une explication, vous utilisez head -n 16482 pour afficher les 16482 premières lignes puis utiliser tail -n 258 pour obtenir les 258 dernières lignes de la première sortie.

2 votes

Et au lieu de vi, vous pouvez utiliser ex, c'est-à-dire vi moins les trucs de la console interactive.

1 votes

Vous n'avez pas besoin de la cat commandement ; head peut lire un fichier directement. Cette méthode est plus lente que beaucoup d'autres car elle utilise 2 (3 comme indiqué) commandes là où une seule est suffisante.

3 votes

@JonathanLeffler Vous avez tout à fait tort. C'est incroyablement rapide. J'extrais 200k lignes, soit environ 1G, d'un fichier de 2G contenant 500k lignes, en quelques secondes (sans l'option cat ). Les autres solutions nécessitent au moins quelques minutes. De même, la variante la plus rapide de GNU semble être tail -n +XXX filename | head XXX .

34voto

fedorqui Points 42938

Il existe une autre approche avec awk :

awk 'NR==16224, NR==16482' file

Si le fichier est énorme, il peut être bon de exit après avoir lu la dernière ligne souhaitée. De cette façon, il ne lira pas les lignes suivantes inutilement :

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

awk 'NR==16224, NR==16482; NR==16482 {exit}' file

2 votes

1+ pour l'économie du temps d'exécution et des ressources en utilisant print; exit . Merci !

0 votes

Légère simplification du 2ème exemple : awk 'NR==16224, NR==16482; NR==16482 {exit}' file

0 votes

C'est lumineux, merci @RobinA.Meade ! J'ai édité votre idée dans le post

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X