Por que a âncora $ no final da linha não está funcionando com o comando grep, mesmo que a âncora ^ na linha de frente esteja?

19

Muito novo no UNIX, mas não novo na programação. Usando o Terminal no MacBook. Para fins de gerenciamento e pesquisa de listas de palavras para a construção de palavras cruzadas, estou tentando me familiarizar com o comando Grep e suas variações. Parece bem direto, mas ficar desligado desde o início com o que pensei que deveria ser um caso simples.

Quando eu entro

grep "^COW" masternospaces.txt

Consigo o que quero: uma lista de todas as palavras que começam com COW.

Mas quando eu entro

grep "COW$" masternospaces.txt

Espero obter uma lista de palavras que terminam com COW (existem muitas dessas palavras) e nada é retornado.

O arquivo é um arquivo de texto sem formatação, com cada linha apenas uma palavra (ou uma frase da palavra sem espaços) em maiúsculas.

Alguma idéia do que poderia estar acontecendo aqui?

DTalvacchio
fonte
3
Qual é a origem do arquivo masternospaces.txt? é possível que tenha terminações de linha no estilo Windows (CR-LF) em vez de LFs no estilo Unix?
steeldriver
2
Não tenho certeza, mas você está procurando uma lista de palavras ou uma lista de linhas ... ?
mikeserv
chave de aço ... Algo assim foi o meu primeiro pensamento. Não sabia ao certo como inspecionar o que estava acontecendo ali ou quais eram as possibilidades. Supondo que um retorno final fosse um retorno final. Esse arquivo é um compêndio enorme de algumas fontes. Eu nem tenho certeza de qual deles seria considerado o arquivo original. E já passou por pelo menos três processadores de texto em máquinas para PC e Mac. Qual pode ser a melhor maneira de ver que tipo de terminações está usando?
DTalvacchio
mikeserv - Neste arquivo .txt, cada linha é apenas uma palavra (ou uma frase sem espaços entre as palavras, então novamente uma "palavra"). Então, estou procurando linhas, suponho. . . apenas que cada linha tem apenas uma daquilo que considero uma palavra para fins de palavras cruzadas.
DTalvacchio
1
Você pode usar hexdumppara verificar exatamente como as terminações de sua linha estão formatadas. Eu sugiro que você use o meu formato favorito: hexdump -e '"%08_ad (0x%08_ax) "8/1 "%02x "" "8/1 "%02x "' -e '" "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt. Com a saída, verifique as terminações da linha: 0a-> LF, 0d-> CR.
user43791

Respostas:

23

Como o @steeldriver mencionou, é provável que o problema seja causado por um estilo de final de linha diferente do que o grepesperado.

Para verificar as terminações de linha

Você pode usar hexdumppara verificar exatamente como as terminações de sua linha estão formatadas. Sugiro que você use meu formato favorito:

hexdump -e '"%08_ad (0x%08_ax)    "8/1 "%02x ""   "8/1 "%02x "' -e '"    "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt

Com a saída, verifique as terminações da linha: 0a-> LF, 0d-> CR. Um exemplo muito rápido daria algo como isto:

$ hexdump -e '"%08_ad (0x%08_ax)    "8/1 "%02x ""   "8/1 "%02x "' -e '"    "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt
00000000 (0x00000000)    4e 6f 20 43 4f 57 20 65   6e 64 69 6e 67 0d 0a 45    No COW e|nding..E
00000016 (0x00000010)    6e 64 69 6e 67 20 69 6e   20 43 4f 57 0d 0a          nding in| COW..

Nota os fins de linha no formato dos: 0d 0a.

Para alterar as terminações de linha

Você pode ver aqui ou aqui vários métodos para alterar as terminações de linha usando várias ferramentas, mas, como algo único, você sempre pode usar o vi / vim:

vim masternospaces.txt
:set fileformat=unix
:wq

Para grep sem alterar nada

Se você quiser apenas grepcorresponder, não importa o final da linha, sempre poderá especificar finais de linha como este:

grep 'COW[[:cntrl:]]*$' masternospaces.txt

Se uma linha em branco for mostrada, você pode verificar se realmente correspondeu a algo usando a -vopção de cat:

grep 'COW[[:cntrl:]]*$' masternospaces.txt | cat -v

Meu favorito pessoal

Você também pode grep e padronizar a saída usando sed:

sed -n '/COW^M*$/{;s/^M//g;p;};' masternospaces.txt

onde ^Mé obtido digitando Ctrl-V Ctrl-Mno teclado.

Espero que isto ajude!

user43791
fonte
Tudo isso é extremamente útil. Hoje estou sem tempo, mas amanhã vou analisar tudo isso de perto e ver o que é o quê. Enquanto isso, algum de vocês tem um link para o seu guia de referência de comando favorito do Unix, para que eu possa aprender um pouco sobre como as coisas estão funcionando, eu agradeceria. Venho pegando peças aqui e ali, mas ainda não encontrei uma fonte que seja a minha fonte de explicações. Obrigado a todos e faremos o check-in amanhã com uma atualização bem-sucedida. --D
DTalvacchio
É uma pena que este post não tenha encerramento, pelo menos para mim. Pela minha vida, não consigo descobrir como combinar o final da linha. Se eu fizer um dump hexadecimal, não consigo encontrar uma boa linha que termine como o seu exemplo acima. Não estou familiarizado com o trabalho com hexadecimal, por isso talvez não esteja lendo direito. Eu também tentei o [[:cntrl:]]@ user43791 sugerido e ainda não está combinando nada para mim. Isso não faz sentido. Estou usando GNU grep 2.20 e analisar a saída de nDPI que foi gravado em um arquivo de texto
harperville
@harperville Se você cat -v yourfile.ext, o que vê?
User43791 de
Bem, nada de emocionante ou inesperado. Apenas o conteúdo como eu esperaria vê-los. Alguma coisa específica que você está procurando? Não consigo colar a saída aqui, mas apenas vejo o conteúdo. Texto normal em inglês ASCII, de acordo com file.
harperville
@harperville Não há "^ M" extra no final de cada linha? Você pode colar as primeiras linhas de hexadecimal?
precisa saber é o seguinte
1

Embora você possa usar a sintaxe RegEx 'padrão' com grep (como na resposta de @ user43791 ), o grep também tem outros identificadores para indicar os limites de entrada.

Os marcadores para o início e o fim de toda a linha são \`(backtick) (em vez de ^) e \'(apóstrofo) (em vez de $).

Portanto, para o seu comando original, você usaria: grep "COW\'" masternospaces.txt

Nota lateral: também é importante observar isso ?e +será tratado literalmente, a menos que você os escape usando \?e \+para torná-los equivalentes do seletor no estilo RegEx.

Fonte: grepsintaxe da expressão regular

samthecodingman
fonte
grep está tomando ^ (acento circunflexo) para início e \'(apóstrofo) para o final
GypsyCosmonaut
1

Outra maneira de remover o \rantes do grep:

... | dos2unix | egrep 'COW$' | ...

Gosto que está muito claro, já que não me lembro de coisas assim [[:cntrl:]]por muito tempo.

Javier
fonte
-2

"COW $" quando o bash define o parâmetro para grep, foi interpretado como 'COW' onde trata "$" como "", pois $ é um símbolo de escape. quando nada foi associado a $, ele é interpretado como uma string vazia pelo shell bash; portanto, você deve usar grep 'COW $' masternospaces.txt.

yangyang
fonte
3
Como não há expansão válida $, ele seria deixado sozinho pelo bash e usado pelo grep. Veja você mesmo: echo "COW$"- o $ainda estará lá.
Jeff Schaller
-3

No BSD grep, você precisa escapar de "$" e colocar sua string entre aspas duplas:

"COW\$"
user297403
fonte
1
Hum ... não. O $item não será especial para o shell, porque o item a seguir não é um nome de variável de shell válido. Usar aspas simples em seqüências de caracteres estáticas é uma idéia melhor, mas não fará diferença aqui.
Kusalananda