Comptez le nombre de lignes vides à la fin du fichier

11

J'ai un fichier avec des lignes vides à la fin du fichier. Puis-je utiliser greppour compter le nombre de lignes vides à la fin du fichier avec le nom de fichier transmis comme variable dans le script?

Raghunath Choudhary
la source
compter le nombre de lignes vierges consécutives ?
RomanPerekhrest
2
@RomanPerekhrest Je dirais que oui, sinon ils ne seraient pas "à la fin du fichier"?
Sparhawk
'grep -cv -P' \ S 'nom_fichier' comptera le nombre total de lignes vides dans le fichier. Le chiffre à la fin ne fait que taxer mon cerveau!
MichaelJohn
OP a demandé grep@MichaelJohn gagne pour la pureté dans mon livre.
bu5hman
2
@ bu5hman Mais (comme il l'admet) ne répond pas à la question. Le vôtre non plus, vraiment.
Sparhawk

Réponses:

11

Si les lignes vides ne sont qu'à la fin

grep  -c '^$' myFile

ou:

grep -cx '' myFile
bu5hman
la source
Battu au montage par secondes, bon sang
bu5hman
grep -cv . myFileest une autre façon de l'écrire (pour les golfeurs de code). Mais j'ai trouvé une solution avec greps'il y a des lignes vides n'importe où dans le fichier.
Philippos
2
@Philippos, grep -cv .compterait également les lignes qui ne contiennent que des octets qui ne forment pas de caractères valides.
Stéphane Chazelas
11

Juste pour le plaisir, un peu effrayant sed:

#!/bin/sh
sed '/./!H;//h;$!d;//d;x;s/\n//' "$1" | wc -l

Explication:

  • /./adresse les lignes avec n'importe quel caractère, donc /./!les lignes non vides; pour ceux-ci, la Hcommande les ajoute à l'espace d'attente. Ainsi, si pour chaque ligne vide nous avons ajouté une ligne à l'espace d'attente, il y a toujours une ligne de plus que le nombre de lignes vides. Nous nous en occuperons plus tard.
  • //hle modèle vide correspond à la dernière expression régulière, qui était n'importe quel caractère, donc toute ligne non vide est adressée et déplacée vers l'espace d'attente par la hcommande pour "réinitialiser" les lignes collectées à 1. Lorsque la prochaine ligne vide sera ajoutée, il y en aura encore deux, comme prévu.
  • $!darrête le script sans sortie pour toutes les lignes sauf la dernière, de sorte que d'autres commandes ne sont exécutées qu'après la dernière ligne. Donc, quelles que soient les lignes vides que nous avons collectées dans l'espace d'attente se trouvent à la fin du fichier. Bien.
  • //d: La dcommande est à nouveau exécutée uniquement pour les lignes non vides. Donc, si la dernière ligne n'était pas vide, sedelle quittera sans aucune sortie. Zéro lignes. Bien.
  • x les échanges contiennent de l'espace et de l'espace de motif, de sorte que les lignes collectées sont maintenant dans l'espace de motif à traiter.
  • Mais nous nous souvenons qu'il y a une ligne de trop, nous la réduisons donc en supprimant une nouvelle ligne avec s/\n//.
  • Voilà! Le nombre de lignes correspond au nombre de lignes vides à la fin (notez que la première ligne ne sera pas vide, mais peu importe), nous pouvons donc les compter avec wc -l.
Philippos
la source
8

Un peu plus GNU tac/ tail -roptions:

tac file | awk 'NF{exit};END{print NR?NR-1:0}'

Ou:

tac file | sed -n '/[^[:blank:]]/q;p' | wc -l

Notez que sur la sortie de:

printf 'x\n '

Autrement dit, là où il y a un espace supplémentaire après la dernière ligne complète (que certains pourraient considérer comme une ligne vierge supplémentaire, mais selon la définition POSIX du texte, n'est pas du texte valide), ceux-ci donneraient 0.

POSIX:

awk 'NF{n=NR};END{print NR-n}' < file

mais cela signifie lire le fichier en entier ( tail -r/ taclirait le fichier en arrière depuis la fin sur les fichiers recherchables). Cela donne 1sur la sortie de printf 'x\n '.

Stéphane Chazelas
la source
6

Comme vous demandez réellement une grepsolution, j'ajoute celle-ci en se basant uniquement sur GNU grep(d'accord, en utilisant également la syntaxe shell et echo...):

#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))

Qu'est ce que je fais ici? $(grep -c ".*" "$1")compte toutes les lignes du fichier, puis nous soustrayons le fichier sans les lignes vides de fin.

Et comment les obtenir? $(grep -B42 . "$1"grep toutes les lignes non vides et 42 lignes avant elles, donc il imprimerait tout jusqu'à la dernière ligne non vide, tant qu'il n'y a pas plus de 42 lignes vides consécutives avant une ligne non vide. Pour éviter cette limite, je prends $(grep -cv . "$1")comme paramètre de l' -Boption, qui est le nombre total de lignes vides, donc toujours assez grand. De cette façon, j'ai supprimé les lignes vides de fin et je peux utiliser |grep -c ".*"pour compter les lignes.

Brillant, n'est-ce pas? (-;

Philippos
la source
+1 parce que même si c'est un code horrible, il répond techniquement à la question posée et je ne peux pas supporter de vous noter ;-)
roaima
Grepmeister. Nous n'en sommes pas dignes.
bu5hman
+1 pour la perversité. Une autre option (peut-être plus rapide?) Serait de choisir tac | greple premier non vide avec -m -A 42, puis un moins. Je ne sais pas lequel est le plus efficace, mais vous pourriez aussi wc -l | cut -d' ' -f1au lieu de saluer les lignes blanches?
Sparhawk
Oui, bien sûr, vous pouvez faire beaucoup de choses avec tac, wcet cut, mais ici, j'ai essayé de me limiter grep. Vous pouvez appeler cela de la perversité, je l'appelle du sport. (-;
Philippos
5

Une autre awksolution. Cette variation réinitialise le compteur kchaque fois qu'il y a une ligne non vide. Ensuite, chaque ligne incrémente le compteur. (Donc, après la première ligne de longueur non vide,. k==0) À la fin, nous affichons le nombre de lignes que nous avons comptées.

Préparer le fichier de données

cat <<'X' >input.txt
aaa

bbb
ccc



X

Comptez les lignes vides de fin dans l'échantillon

awk 'NF {k=-1}; {k++}; END {print k+0}' input.txt
3

Dans cette définition, une ligne vierge peut contenir des espaces ou d'autres caractères vides; c'est encore vierge. Si vous voulez vraiment compter les lignes vides plutôt que les lignes vides, changez NFpour $0 != "".

roaima
la source
Pourquoi $0 > ""? Cette utilisation strcoll()serait moins efficace que celle $0 != ""qui est memcmp()utilisée dans de nombreuses implémentations (POSIX l'exigeait strcoll()cependant).
Stéphane Chazelas
@ StéphaneChazelas Je n'ai pas pensé que cela $0 > ""pourrait être différent de $0 != "". J'ai tendance à traiter awkcomme un opérateur "lent" de toute façon (de sorte que si je sais que j'ai un grand ensemble de données en entrée et que le traitement est critique en temps, je verrai ce que je peux faire pour réduire la quantité awkà traiter - je ont utilisé des grep | awkconstructions dans de telles situations). Cependant, après avoir jeté un coup d'œil à ce que je suppose être la définition POSIX, je ne vois aucune référence à l'un strcoll()ou à l'autre memcmp(). Qu'est-ce que je rate?
roaima
strcoll()== les chaînes doivent être comparées en utilisant la séquence de classement spécifique aux paramètres régionaux . Comparez avec l' édition précédente . C'est moi qui l'ai soulevé. Voir aussi austingroupbugs.net/view.php?id=963
Stéphane Chazelas
@ StéphaneChazelas une implémentation où a <= b && a >= bn'est pas forcément la même que a == b. Aie!
roaima
C'est le cas de GNU awkou bash(pour ses [[ a < b ]]opérateurs) en_US.UTF-8 sur les systèmes GNU locales par exemple pour vs par exemple (pour bash, aucune <, >, =retourne vrai pour ceux). On peut dire que c'est un bug dans la définition de ces paramètres régionaux plus que dans bash / awk
Stéphane Chazelas
2

compter le nombre de lignes vierges consécutives à la fin du fichier

Solide awk+ tacsolution:

Échantillon input.txt:

$ cat input.txt
aaa

bbb
ccc



$  # command line 

L'action:

awk '!NF{ if (NR==++c) { cnt++ } else exit }END{ print int(cnt) }' <(tac input.txt)
  • !NF- s'assure que la ligne actuelle est vide (sans champs)
  • NR==++c- assurer l'ordre consécutif des lignes vierges. ( NR- nombre record, ++c- compteur auxiliaire régulièrement incrémenté)
  • cnt++- compteur de lignes vierges

Le résultat:

3
RomanPerekhrest
la source
1

IIUC, le script suivant appelé count-blank-at-the-end.shferait l'affaire:

#!/usr/bin/env sh

count=$(tail -n +"$(grep . "$1" -n | tail -n 1 | cut -d: -f1)" "$1" | wc -l)
num_of_blank_lines=$((count - 1))

printf "%s\n" "$num_of_blank_lines"

Exemple d'utilisation:

$ ./count-blank-at-the-end.sh FILE
4

Je l' ai testé dans GNU bash, Android mkshet ksh.

Arkadiusz Drabczyk
la source