Grep a primeira linha mais longa
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
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 uma wc
invocação:
## grep "^.{$( wc -L F )}$" F
O wc
é usado em uma expansão de processo e $( ... )
, portanto, é executado antes 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 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 <
no wc
comando grava o arquivo para seu stdin, para evitar que wc
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.
f="file.txt"
Mostre a primeira linha mais longa - a primeira linha que contenha a linha mais longa:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Mostrar todas as linhas mais longas - todas as linhas que contenham a linha mais longa:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Mostrar a última linha mais longa - a última linha que é tão longa quanto a linha mais longa:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Mostre a 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, ele deve ser decomposto para que a saída wc
e as linhas escritas por grep
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.)