web-dev-qa-db-fra.com

Commande rapide unix pour afficher des lignes spécifiques au milieu d'un fichier?

Essayer de déboguer un problème avec un serveur et mon seul fichier journal est un fichier journal de 20 Go (même sans horodatage! Pourquoi les utilisateurs utilisent-ils System.out.println() pour la journalisation? En production?!)

En utilisant grep, j'ai trouvé une zone du fichier sur laquelle j'aimerais jeter un coup d'œil, ligne 347340107.

Autre que de faire quelque chose comme

head -<$LINENUM + 10> filename | tail -20 

... qui nécessiterait head pour lire les 347 millions de lignes du fichier journal, existe-t-il une commande simple et rapide permettant de transférer les lignes 347340100 - 347340200 (par exemple) sur la console?

update J'ai totalement oublié que grep peut imprimer le contexte d'une correspondance ... cela fonctionne bien. Merci!

165
matt b

avec GNU-grep, vous pouvez simplement dire 

grep --context = 10 ...
66
Mathias Weidner

J'ai trouvé deux autres solutions si vous connaissez le numéro de ligne mais rien d'autre (pas de grep possible):

En supposant que vous ayez besoin des lignes 20 à 40,

sed -n '20,40p;41q' file_name

ou 

awk 'FNR>=20 && FNR<=40' file_name
344
Sklivvz
# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3,  efficient on large files 

méthode 3 efficace sur les gros fichiers

moyen le plus rapide d'afficher des lignes spécifiques

99
WCC

Non, les fichiers ne sont pas adressables en ligne.

Il n'y a pas de moyen à temps constant pour trouver le début de la ligne n dans un fichier texte. Vous devez diffuser dans le fichier et compter les nouvelles lignes.

Utilisez l’outil le plus simple et le plus rapide pour faire le travail. Pour moi, utiliser head est beaucoup plus logique que grep, car ce dernier est bien plus compliqué. Je ne dis pas que "grep est lent", ce n'est vraiment pas le cas, mais je serais surpris que ce soit plus rapide que head dans ce cas. Ce serait un bug dans head, fondamentalement.

23
unwind

Qu'en est-il de:

tail -n +347340107 filename | head -n 100

Je ne l'ai pas testé, mais je pense que cela fonctionnerait.

19
itsmatt

J'avais d'abord divisé le fichier en plusieurs fichiers plus petits comme celui-ci

$ split --lines=50000 /path/to/large/file /path/to/output/file/prefix

puis grep sur les fichiers résultants.

12
Luka Marinko

Je préfère aller dans less et

  • dactylographie 5% aller à mi-chemin du fichier,
  • 43210G aller à la ligne 43210
  • :43210 faire la même chose

et des trucs comme ça.

Encore mieux: hit v pour commencer à éditer (dans vim, bien sûr!), à cet endroit. Maintenant, notez que vim a les mêmes raccourcis clavier!

11
sehe

Vous pouvez utiliser la commande ex , un éditeur Unix standard (faisant partie de Vim maintenant), par exemple.

  • afficher une seule ligne (par exemple la 2e):

    ex +2p -scq file.txt
    

    syntaxe sed correspondante: sed -n '2p' file.txt

  • gamme de lignes (par exemple, 2-5 lignes):

    ex +2,5p -scq file.txt
    

    syntaxe sed: sed -n '2,5p' file.txt

  • à partir de la ligne donnée jusqu'à la fin (par exemple, du 5ème à la fin du fichier):

    ex +5,p -scq file.txt
    

    syntaxe sed: sed -n '2,$p' file.txt

  • plusieurs gammes de lignes (par exemple, 2-4 et 6-8 lignes):

    ex +2,4p +6,8p -scq file.txt
    

    syntaxe sed: sed -n '2,4p;6,8p' file.txt

Les commandes ci-dessus peuvent être testées avec le fichier de test suivant:

seq 1 20 > file.txt

Explication:

  • + ou -c suivi de la commande - exécute la commande (vi/vim) après la lecture du fichier,
  • -s - mode silencieux, utilise également le terminal actuel comme sortie par défaut,
  • q suivi de -c est la commande pour quitter l'éditeur (ajoutez ! pour forcer la fermeture, par exemple -scq!).
8
kenorb

sed devra également lire les données pour pouvoir compter les lignes ..__ La seule manière de créer un raccourci serait de créer un contexte/un ordre dans le fichier à utiliser. Par exemple, s'il existe des lignes de journal avec une largeur fixe heure/date, etc., vous pouvez utiliser l'utilitaire look unix pour effectuer une recherche binaire dans les fichiers à des dates/heures particulières.

4
pixelbeat

Obtenir ack

ack --lines = nom du fichier de début à la fin

3
Odeyin

Utilisation

x=`cat -n <file> | grep <match> | awk '{print $1}'`

Ici, vous obtiendrez le numéro de ligne où la correspondance a eu lieu.

Maintenant, vous pouvez utiliser la commande suivante pour imprimer 100 lignes

awk -v var="$x" 'NR>=var && NR<=var+100{print}' <file>

ou vous pouvez aussi utiliser "sed"

sed -n "${x},${x+100}p" <file>
3
Ramana Reddy

S'appuyant sur la réponse de Sklivvz, voici une fonction intéressante que l'on peut mettre dans un fichier .bash_aliases. Il est efficace sur les gros fichiers lors de l’impression depuis le début du fichier.

function middle()
{
    startidx=$1
    len=$2
    endidx=$(($startidx+$len))
    filename=$3

    awk "FNR>=${startidx} && FNR<=${endidx} { print NR\" \"\$0 }; FNR>${endidx} { print \"END HERE\"; exit }" $filename
}
2
Keithel

Avec sed -e '1,N d; M q', vous imprimerez les lignes N + 1 à M. C'est probablement un peu mieux que grep -C car il ne tente pas de faire correspondre les lignes à un motif.

2
mweerden

Si votre numéro de ligne est 100 à lire 

head -100 filename | tail -1
2
Roopa

Pour afficher une ligne à partir d'un <textfile> par son <line#>, procédez comme suit:

Perl -wne 'print if $. == <line#>' <textfile>

Si vous voulez un moyen plus puissant de montrer une série de lignes avec des expressions régulières - je ne dirai pas pourquoi grep est une mauvaise idée, cela devrait être assez évident - cette expression simple vous montrera votre gamme passe unique qui correspond à ce que vous voulez lorsque vous traitez avec des fichiers texte d'environ 20 Go:

Perl -wne 'print if m/<regex1>/ .. m/<regex2>/' <filename>

(conseil: si votre expression rationnelle contient /, utilisez plutôt quelque chose comme m!<regex>!)

Ceci afficherait <filename> en commençant par la ligne qui correspond à <regex1> jusqu'à (et y compris) la ligne qui correspond à <regex2>.

Il ne faut pas un assistant pour voir comment quelques ajustements peuvent le rendre encore plus puissant. 

Dernière chose: Perl, en tant que langage mature, dispose de nombreuses améliorations cachées pour favoriser la vitesse et les performances. En gardant cela à l’esprit, cela en fait le choix évident pour une telle opération puisqu’elle a été développée à l’origine pour la gestion de gros fichiers journaux, textes, bases de données, etc.

0
osirisgothra

Facile avec Perl! Si vous voulez obtenir les lignes 1, 3 et 5 d'un fichier, dites/etc/passwd:

Perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd
0
dagelf

Vous pouvez essayer cette commande: 

egrep -n "*" <filename> | egrep "<line number>"
0
Fritz Dodoo

Je suis surpris qu’une autre réponse (de Ramana Reddy) suggère d’ajouter des numéros de ligne à la sortie. Ce qui suit recherche le numéro de ligne requis et colore la sortie.

file=FILE
lineno=LINENO
wb="107"; bf="30;1"; rb="101"; yb="103"
cat -n ${file} | { GREP_COLORS="se=${wb};${bf}:cx=${wb};${bf}:ms=${rb};${bf}:sl=${yb};${bf}" grep --color -C 10 "^[[:space:]]\\+${lineno}[[:space:]]"; }
0
eel ghEEz