Como imprimir a linha mais longa em um arquivo?

29

Estou procurando o método mais simples para imprimir a linha mais longa em um arquivo. Eu fiz algumas pesquisas e surpreendentemente não consegui encontrar uma resposta. Costumo imprimir o comprimento da linha mais longa em um arquivo, mas não sei como imprimir realmente a linha mais longa. Alguém pode fornecer uma solução para imprimir a linha mais longa em um arquivo? Desde já, obrigado.

    
por dr.bunsen 13.11.2011 / 01:58

9 respostas

32
cat ./text | awk ' { if ( length > x ) { x = length; y = $0 } }END{ print y }'

UPD : resumindo todos os conselhos nos comentários

awk 'length > max_length { max_length = length; longest_line = $0 } END { print longest_line }' ./text 
    
por 13.11.2011 / 02:02
5
sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file

Primeiro, lê o arquivo dentro da substituição do comando e produz o comprimento da linha mais longa, (anteriormente, expand converte as tabulações em espaços, para superar a semântica de wc -L - cada tab na linha adicionará < em> 8 em vez de 1 para o comprimento da linha). Esse comprimento é então usado em uma expressão sed que significa "encontre uma linha com esse número de caracteres, imprima e feche". Então, isso pode ser o ideal, já que a linha mais longa está próxima do topo do arquivo, heheh (obrigado pelos comentários impressionantes e construtivos).

Outra, eu pensei antes do sed (em bash):

#!/bin/bash
while read -r line; do
    (( ${#line} > max )) && max=${#line} && longest="$line"
done
echo "$longest"
    
por 13.11.2011 / 03:22
4

Aqui está uma solução Perl:

perl -e 'while(<>){
           $l=length;  
           $l>$m && do {$c=$_; $m=$l}  
         } print $c' file.txt 

Ou, se você quiser imprimir todas as linhas mais longas

perl -e 'while(<>){
           $l=length;
           push @{$k{$l}},$_;
           $m=$l if $l>$m;
         } print @{$k{$m}}' file.txt 

Como não tinha nada melhor para fazer, fiz alguns benchmarks em um arquivo de texto de 625M. Surpreendentemente, minha solução Perl foi consistentemente mais rápida que as outras. Concedido, a diferença com a solução awk aceita é pequena, mas está lá. Obviamente, as soluções que imprimem várias linhas são mais lentas, então classifico por tipo, e mais rápido a mais lento.

Imprima apenas uma das linhas mais longas:

$ 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

Imprimir todas as linhas mais longas:

$ 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
    
por 01.05.2013 / 21:28
3

Grep a primeira linha mais longa

grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt 

O comando é excepcionalmente difícil de ler sem prática porque mistura sintaxe shell e regexp.
Para explicação, vou usar o pseudocódigo simplificado primeiro. As linhas que começam com ## não são executadas no shell.
Este código simplificado usa o nome de arquivo F e deixa de fora citando e partes de regexps para legibilidade.

Como funciona

O comando tem duas partes, uma invocação grep - e uma wc :

## grep "^.{$( wc -L F )}$" F

O wc é usado em uma expansão de processo, $( ... ) , portanto é executado antes de grep . Calcula o comprimento da linha mais longa. A sintaxe de expansão do shell é misturada com a sintaxe do padrão de expressão regular de maneira confusa, então eu decomponho a expansão do processo:

## wc -L F e 42 e ## grep "^.{42}$" F

Aqui, a expansão do processo foi substituída pelo valor que retornaria, criando a linha de comando grep que é usada. Agora podemos ler a expressão regular com mais facilidade: ela corresponde exatamente do início ( ^ ) ao final ( $ ) da linha. A expressão entre eles corresponde a qualquer caractere, exceto newline, repetido por 42 vezes. Combinado, isto é, linhas que consistem em exatamente 42 caracteres.


Agora, voltando aos comandos reais do shell: O grep option -E ( --extended-regexp ) permite não escapar do {} para legibilidade. A opção -m 1 ( --max-count=1 ) faz com que pare depois que a primeira linha é encontrada. O < no comando wc grava o arquivo em seu stdin, para evitar que wc imprima o nome do arquivo junto com o tamanho.

Quais são as linhas mais longas?

Para tornar os exemplos mais legíveis com o nome do arquivo ocorrendo duas vezes, usarei uma variável f para o nome do arquivo; Cada $f no exemplo pode ser substituído pelo nome do arquivo.

f="file.txt"

Mostre a primeira linha mais longa - a primeira linha com a maior linha:

grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"

Mostre todas as linhas mais longas - todas as linhas que são tão longas quanto a linha mais longa:

grep -E "^.{$(wc -L <"$f")}\$" "$f" 

Mostre a última linha mais longa - a última linha que é longa como a linha mais longa:

tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"

Mostre a única linha mais longa - a linha mais longa que todas as outras linhas ou falhe:

[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f" 

(O último comando é ainda mais ineficiente que os outros, pois repete o comando grep completo. Obviamente deve ser decomposto para que a saída de wc e as linhas gravadas por grep sejam salvas em variáveis. < br> Note que todas as linhas mais longas podem ser todas as linhas. Para salvar em uma variável, apenas as duas primeiras linhas precisam ser mantidas.

    
por 10.11.2014 / 00:37
2

O seguinte exemplo seria, e deveria ter sido, um comentário para a resposta dmitry.malikov , mas por causa do uso inútil de espaço visível para comentários , Eu escolhi para apresentá-lo aqui, onde pelo menos será visto ...

Esta é uma variação simples do dmitry's método awk single-pass.
Imprime todas as linhas "iguais". (Nota: delete array é uma extensão do gawk).

awk 'length >x { delete y; x=length }
     length==x { y[NR]=$0 } END{ for (z in y) print y[z] }' file
    
por 14.11.2011 / 05:16
2
cat filename | awk '{ print length }' | sort -n | tail -1
    
por 24.09.2013 / 12:30
1

Em puro 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[@]}"
    
por 13.11.2011 / 21:09
0

Eu desenvolvi um pequeno script de shell para isso. Ele exibe comprimento, linha # e linha por tamanho que excede um tamanho específico, como 80 caracteres:

#!/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(\
#!/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(\%pre%);
    if (current_length >= expected_length) {
       printf("%d at line # %d %s\n", current_length, NR, \%pre%);
    }
  }

  END {
  }
EOF

for file in $*
do
  echo "$file"
  cat $file | awk -v expected_length=$length -f $LONGLINE |sort -nr
done

rm $LONGLINE
); if (current_length >= expected_length) { printf("%d at line # %d %s\n", current_length, NR, \%pre%); } } END { } EOF for file in $* do echo "$file" cat $file | awk -v expected_length=$length -f $LONGLINE |sort -nr done rm $LONGLINE

link

    
por 19.10.2016 / 08:53
-3

Você pode usar wc :

wc -L fileName
    
por 01.05.2013 / 13:37

Tags