
Eu queria usar o grep em todos os arquivos .txt usando o caractere curinga '*'.
Tentei este comando (e também sem as aspas " "), mas falhei.
ls | grep "*.txt"
O interessante é que se eu colocar outro caractere no comando grep correspondente a um arquivo .txt do diretório, funciona
>>ls | grep s*.txt
sample.txt
Eu sei que ls *.txt
vai funcionar, mas fiquei um pouco surpreso com a natureza do comando grep. Alguém poderia me ajudar por que isso está acontecendo?
É porque o grep usa expressões regulares, por favor ajude.
Responder1
Em regexes, *
significa "qualquer número do item anterior", e não "qualquer número de caracteres", como acontece nos padrões de shell. E .
significa "qualquer caractere único". Então, para procurar por "qualquer coisa, seguida de literal .txt
", você usaria .*\.txt
. Ou apenas \.txt
, já que normalmente as correspondências de regex procuram a correspondência em qualquer lugar da linha. Então, novamente, \.txt
também corresponderia a um nome de arquivo como foo.txtgz
, já que .txt
não precisaria estar no final. Você precisaria \.txt$
bloquear o padrão até o final da linha.
A regex *.txt
não tem sentido, é um erro ou procura um asterisco literal, dependendo da implementação e se você estiver usando regexes básicas ( grep
) ou regexes estendidas ( grep -E
). Melhor não usar.
Por outro lado, s*.txt
procuraria "qualquer número de letras s
, depois qualquer caractere único e depois literal txt
". Essa é uma regex mais válida, mas... ainda não corresponde sample.txt
.
Em vez disso, o que acontece no seu segundo comando é que, como s*.txt
não está entre aspas, o shell expande o s*.txt
antes grep
de vê-lo. Se o único arquivo correspondente for sample.txt
, grep
procure-o na saída de ls
. (Se houvesse vários nomes de arquivos correspondentes, o primeiro seria considerado o padrão e o restante como nomes de arquivos para grep
leitura. Nesse caso, a entrada do canal seria ignorada.)
Mas ls
também pode levar uma lista de arquivos, então, embora você possa usar
ls | grep '\.txt'
para obter qualquer .txt
arquivo, provavelmente seria mais fácil usar
ls *.txt
em vez de.
Responder2
É em parte porque grep
usa expressões regulares (na verdade, é isso que re
o nome significa - é a abreviação deglobalRnormaleexpressãoprinte).
O *
curinga em expressões regulares é diferente do *
curinga no shell globbing.
Em expressões regulares, *
significa "zero ou mais do objeto definido anteriormente". No entanto, .
étambémum curinga, que significa 'um caractere'.
Em shell globs, *
significa "zero ou mais caracteres". .
não é um curinga.
Quando você grep
procura o padrão "*.txt"
, procura zero ou mais de qualquer coisa, seguido por exatamente mais um caractere, seguido pela string literal txt
.
Quando você grep
usa o padrão "s*.txt"m you are looking for a literal
s , followed by zero or more
txt` s, followed by any character, followed by the literal string
.
É por isso que uma coisa comum que você encontrará em expressões regulares é .*
, que significa "um de qualquer caractere seguido por zero ou mais de qualquer caractere". Regexese para "literalmente qualquer combinação de caracteres diferente de zero caracteres".
Quando você ls *.txt
estiver dizendo ao shell "Encontre quaisquer nomes de arquivos que correspondam ao padrão glob *.txt
, liste-os aqui e forneça-os como argumentos para o ls
comando.
Responder3
observe que grep está pesquisando arquivocontenteenquanto o primeiro argumento é search PATTERN e outros argumentos interpretados como FILES para examinar
fica mais claro para você ao usar grep -H -o
sinalizadores ou colocá-lo grep
dentro de um script e executá-lo bash -x script
para ver como os globs do shell se expandiram antes de serem passados como argumentos