Estou procurando o método mais simples para imprimir a linha mais longa em um arquivo. Eu pesquisei no Google e surpreendentemente não consegui encontrar uma resposta. Frequentemente, imprimo o comprimento da linha mais longa em um arquivo, mas não sei como realmente imprimir a linha mais longa. Alguém pode fornecer uma solução para imprimir a linha mais longa em um arquivo? Desde já, obrigado.
35
Respostas:
UPD : resumindo todos os conselhos nos comentários
fonte
cat
) e usar um canal são operações caras, sem mencionar que é mais eficiente para o awk ler apenas o arquivo. As implicações de desempenho são definitivamente perceptíveis se isso for feito com freqüência e, mesmo assim, você estiver usando mal o usocat
.cat
não é inútil aqui. Pode ser inútil para um computador, mas para um leitor humano pode fornecer valor. A primeira variante mostra claramente a entrada. O fluxo é mais natural (da esquerda para a direita). No segundo caso, você não sabe qual é a entrada, a menos que você role a janela.cat
.< file command
funciona muito bem.< filename command
é equivalente afilename < command
em todos os shell que eu tentei. Mas uma vez que você está ciente disso, você pode tirar vantagem disso ao escrever longos canos que mostram claramente a direção do fluxo de dados (sem invocar um comando extra):< input-file command1 | command2 | command3 > output-file
fonte
Isso primeiro lê o arquivo dentro da substituição de comando e gera o comprimento da linha mais longa (anteriormente,
expand
converte guias em espaços, para superar a semântica dewc -L
- cada guia na linha adicionará 8 em vez de 1 ao comprimento da linha). Esse comprimento é usado em umased
expressão que significa "encontre uma linha com esse número de caracteres, imprima-a e saia". Então, na verdade, isso pode ser o ideal, pois a linha mais longa fica perto do topo do arquivo, heheh (obrigado pelos comentários impressionantes e construtivos).Outro, pensei antes do sed (no bash):
fonte
-L, --max-line-length
imprime o comprimento da linha mais longa, de acordo com a página do manual, mas se você for mais fundo (como quando obtém resultados errados / inesperados ), verá que essa opção aumenta o comprimento em 8 para cada caractere de 1 guia\x09
veja este Q / A em Unix e Linuxsed -rn "/.{$(<file expand -t1 |wc -L)}/p" file
read line
irá interpretar caracteres escapou-barra invertida como o caractere literal, por exemplo\A
resloves paraA
, o que naturalmente efetivamente relata um mais curto do que real byte-uso ... Para evitar que isso escapou interpretação, use:read -r line
. . . . Além disso, para tornar o + wc sed versão parar após a primeira "linha mais longa", a mudançap
para{p;q}
..sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file
Aqui está uma solução Perl:
Ou, se você quiser imprimir todas as linhas mais longas
Como não tinha nada melhor para fazer, executei alguns benchmarks em um arquivo de texto de 625M. Surpreendentemente, minha solução Perl foi consistentemente mais rápida que as outras. É verdade que a diferença com a
awk
solução aceita é pequena, mas existe. Obviamente, as soluções que imprimem várias linhas são mais lentas, por isso classifiquei por tipo, da mais rápida para a mais lenta.Imprima apenas uma das linhas mais longas:
Imprimir todas as linhas mais longas:
fonte
Grep a primeira linha mais longa
O comando é extraordinariamente difícil de ler sem prática, porque combina sintaxe shell e regexp.
Para explicação, usarei primeiro o pseudocódigo simplificado. As linhas que começam com
##
não são executadas no shell.Esse código simplificado usa o nome do arquivo F e deixa de fora citações e partes de regexps para facilitar a leitura.
Como funciona
O comando possui duas partes, a
grep
- e umawc
invocação:## grep "^.{$( wc -L F )}$" F
O
wc
é usado em uma expansão de processo e$( ... )
, portanto, é executado antesgrep
. 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 uma maneira confusa; portanto, decompomos a expansão do processo:## wc -L F
42
## grep "^.{42}$" F
Aqui, a expansão do processo foi substituída pelo valor que retornaria, criando a
grep
linha de comando 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 nova linha, repetida por 42 vezes. Combinadas, ou seja, linhas que consistem em exatamente 42 caracteres.Agora, voltando aos comandos reais do shell: A
grep
opção-E
(--extended-regexp
) permite não escapar da{}
legibilidade. Option-m 1
(--max-count=1
) faz com que pare depois que a primeira linha for encontrada. O<
nowc
comando grava o arquivo para seu stdin, para evitar quewc
imprimam o nome do arquivo junto com o comprimento.Quais 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 um$f
no exemplo pode ser substituído pelo nome do arquivo.Mostre a primeira linha mais longa - a primeira linha que contenha a linha mais longa:
Mostrar todas as linhas mais longas - todas as linhas que contenham a linha mais longa:
Mostrar a última linha mais longa - a última linha que é tão longa quanto a linha mais longa:
Mostre a linha mais longa - a linha mais longa que todas as outras linhas ou falhe:
(O último comando é ainda mais ineficiente que os outros, pois repete o comando grep completo. Obviamente, ele deve ser decomposto para que a saída
wc
e as linhas escritas porgrep
sejam salvas nas variáveis.Observe que todas as linhas mais longas podem na verdade ser todas as linhas Para salvar em uma variável, apenas as duas primeiras linhas precisam ser mantidas.)
fonte
O exemplo a seguir seria e deveria ter sido um comentário para a resposta de dmitry.malikov , mas por causa do Uso inútil do espaço de comentários visível lá, eu escolhi apresentá-lo aqui, onde pelo menos será visto. ..
Esta é uma variação simples do de Dmitry método awk single-pass.
Imprime todas as linhas "iguais maiores". (Nota.
delete array
É uma extensão gawk).fonte
Na festança pura:
fonte
_max_line[0]=${_line}
não remove o resto de quaisquer mais curtos "mais longas linhas" previamente acumulados ...unset _max_line
vai limpar toda a matriz ...Eu desenvolvi um pequeno script de shell para isso. Ele exibe o comprimento, a linha # e a própria linha pelo comprimento que excede um tamanho específico, como 80 caracteres:
https://github.com/lordofrain/tools/blob/master/longest-line/longest-line.sh
fonte
$*
raramente é uma boa ideia, você quer"$@"
. O/.*/
no seuawk
não faz nada, pois também corresponde a linhas vazias. Você pode evitar escapar\$0
se citar o'EOF'
. Por que usar umBEGIN{}
bloco vazio ? Finalmente, você não precisacat
, apenasawk . . . "$file" | . . .
awk -vmax=15 '{len=length($0); if(len>=max){printf("%s, %d at line # %d %s\n", FILENAME, len, NR, $0);}}' file*
Você pode usar
wc
:fonte
wc -L
a desvantagem de.