Je cherche la méthode la plus simple pour imprimer la ligne la plus longue d'un fichier. J'ai fait des googles et étonnamment ne pouvais pas sembler trouver une réponse. J'imprimais fréquemment la longueur de la ligne la plus longue d'un fichier, mais je ne sais pas comment imprimer réellement la ligne la plus longue. Quelqu'un peut-il fournir une solution pour imprimer la ligne la plus longue d'un fichier? Merci d'avance.
cat ./text | awk ' { if ( length > x ) { x = length; y = $0 } }END{ print y }'
UPD : résumer tous les conseils dans les commentaires
awk 'length > max_length { max_length = length; longest_line = $0 } END { print longest_line }' ./text
cat filename | awk '{ print length }' | sort -n | tail -1
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
La commande est inhabituellement difficile à lire sans pratique car elle mélange la syntaxe de la coquille et de la réégycle.
[.____] Pour une explication, j'utiliserai d'abord un pseudocode simplifié. Les lignes commençant par ##
ne fonctionnent pas dans le Shell.
Ce code simplifié utilise le nom de fichier F, et quitte la citation et des parties de Regexps pour la lisibilité.
La commande comporte deux parties, une grep
- et une invocation wc
:
## grep "^.{$( wc -L F )}$" F
Le wc
est utilisé dans une extension du procédé, $( ... )
, de sorte qu'il est exécuté avant grep
. Il calcule la longueur de la ligne la plus longue. La syntaxe de dilatation de coquille est mélangée à la syntaxe de modèle d'expression régulière de manière déroutante, alors je vais décomposer l'expansion du processus:
## wc -L F
42
## grep "^.{42}$" F
Ici, l'expansion du processus a été remplacée par la valeur qu'il reviendrait, en créant la ligne de commande grep
qui est utilisé. Nous pouvons maintenant lire l'expression régulière plus facilement: Il correspond exactement du début (^
) à la fin ($
) de la ligne. L'expression entre eux correspond à n'importe quel caractère sauf nouvelle ligne, répétée de 42 fois. Combiné, c'est-à-dire des lignes comportant exactement 42 caractères.
Maintenant, retour à de vraies commandes Shell: L'option grep
-E
(--extended-regexp
) permet de ne pas échapper à la {}
pour une meilleure lisibilité. Option -m 1
(--max-count=1
) fait arrêter après la première ligne se trouve. La <
dans la commande wc
écrit le fichier à son stdin, pour empêcher wc
d'imprimer le nom du fichier ainsi que la longueur.
Pour rendre les exemples plus lisible avec le nom de fichier se produit deux fois, je vais utiliser une f
variable pour le nom du fichier; Chaque $f
dans l'exemple pourrait être remplacé par le nom du fichier.
f="file.txt"
Montrer la première ligne la plus longue - la première ligne qui est aussi longue que la ligne la plus longue:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Show toutes les lignes les plus longues - Toutes les lignes qui sont aussi longues que la ligne la plus longue:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Afficher la dernière ligne la plus longue - La dernière ligne qui est aussi longue que la ligne la plus longue:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Afficher la (ligne la plus longue - la ligne la plus longue plus longue que toutes les autres lignes ou échouer:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
(La dernière commande est encore plus inefficace que les autres, car il répète la commande complète grep. Il doit évidemment être décomposé de telle sorte que la sortie de wc
et les lignes écrites par grep
sont enregistrées dans les variables.
[.____] Notez que toutes les lignes les plus longues peuvent en réalité être toutes lignes. Pour économiser dans une variable, seules les deux premières lignes doivent être conservées.)
sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file
Ceci lit d'abord le fichier à l'intérieur de la substitution de commande et génère la longueur de la ligne la plus longue, (précédemment, expand
convertit les onglets en espaces, pour surmonter la sémantique de wc -L
- Chaque onglet dans la ligne ajoutera 8 au lieu de 1 à la longueur de la ligne). Cette longueur est ensuite utilisée dans une signification d'expression sed
"Trouvez une ligne de ce nombre de caractères longtemps, d'imprimer, puis de quitter". Cela peut donc être aussi optimal que la ligne la plus longue à proximité du sommet du fichier, heheh (merci pour les commentaires géniaux et constructifs).
Un autre, j'avais pensé plus tôt que le SED (en bash):
#!/bin/bash
while read -r line; do
(( ${#line} > max )) && max=${#line} && longest="$line"
done
echo "$longest"
Voici une solution PERL:
Perl -e 'while(<>){
$l=length;
$l>$m && do {$c=$_; $m=$l}
} print $c' file.txt
Ou, si vous voulez imprimer tous les lignes les plus longues
Perl -e 'while(<>){
$l=length;
Push @{$k{$l}},$_;
$m=$l if $l>$m;
} print @{$k{$m}}' file.txt
Depuis que je n'avais rien de mieux à faire, j'ai couru des points de repère sur un fichier texte de 625 m. Étonnamment, ma solution Perl était toujours plus rapide que les autres. Certes, la différence avec la solution acceptée awk
est minuscule, mais elle est là. De toute évidence, des solutions qui impriment plusieurs lignes sont plus lentes, donc j'ai trié par type, le plus rapide au plus lent.
Imprimez une seule des lignes les plus longues:
$ time Perl -e 'while(<>){
$l=length;
$l>$m && do {$c=$_; $m=$l}
} print $c' file.txt
real 0m3.837s
user 0m3.724s
sys 0m0.096s
$ time awk 'length > max_length { max_length = length; longest_line = $0 }
END { print longest_line }' file.txt
real 0m5.835s
user 0m5.604s
sys 0m0.204s
$ time sed -rn "/.{$(<file.txt expand -t1 |wc -L)}/{p;q}" file.txt
real 2m37.348s
user 2m39.990s
sys 0m1.868s
Imprimer toutes les lignes les plus longues:
$ time Perl -e 'while(<>){
$l=length;
Push @{$k{$l}},$_;
$m=$l if $l>$m;
} print @{$k{$m}}' file.txt
real 0m9.263s
user 0m8.417s
sys 0m0.760s
$ time awk 'length >x { delete y; x=length }
length==x { y[NR]=$0 } END{ for (z in y) print y[z] }' file.txt
real 0m10.220s
user 0m9.925s
sys 0m0.252s
## This is Chris Down's bash solution
$ time ./a.sh < file.txt
Max line length: 254
Lines matched with that length: 2
real 8m36.975s
user 8m17.495s
sys 0m17.153s
L'exemple suivant allait être, et aurait dû être un commentaire à Dmitry.malikov's Réponse, mais à cause de la tilisation inutile de l'espace de commentaire visible là-bas, j'ai Choisi pour le présenter ici, où il sera au moins vu ...
Ceci est une simple variation de la méthode Dmitry's Single Pass Awk.
[.____] Il imprime toutes les lignes "égales plus longues". (Noter. delete array
est une extension GAWK).
awk 'length >x { delete y; x=length }
length==x { y[NR]=$0 } END{ for (z in y) print y[z] }' file
Pure Bash:
#!/bin/bash
_max_length=0
while IFS= read -r _line; do
_length="${#_line}"
if (( _length > _max_length )); then
_max_length=${_length}
_max_line=( "${_line}" )
Elif (( _length == _max_length )); then
_max_line+=( "${_line}" )
fi
done
printf 'Max line length: %d\n' "${_max_length}"
printf 'Lines matched with that length: %d\n' "${#_max_line[@]}"
(( ${#_max_line[@]} )) && printf '%s\n' '----------------' "${_max_line[@]}"
J'ai développé un petit script shell pour cela. Il affiche la longueur, la ligne de ligne et la ligne elle-même de la longueur dépasse une taille particulière comme 80 caractères:
#!/bin/sh
# Author: Surinder
if test $# -lt 2
then
echo "usage: $0 length file1 file2 ..."
echo "usage: $0 80 hello.c"
exit 1
fi
length=$1
shift
LONGLINE=/tmp/longest-line-$$.awk
cat << EOF > $LONGLINE
BEGIN {
}
/.*/ {
current_length=length(\$0);
if (current_length >= expected_length) {
printf("%d at line # %d %s\n", current_length, NR, \$0);
}
}
END {
}
EOF
for file in $*
do
echo "$file"
cat $file | awk -v expected_length=$length -f $LONGLINE |sort -nr
done
rm $LONGLINE
https://github.com/lordofrain/tools/blob/master/longest-line/longest-line.sh