Entendendo -regex com o GNU find

3

Antecedentes

Eu tenho o que acho que deveria ser um caso simples. Eu quero encontrar todos os arquivos com "cisco" no nome e fazer algo com esses arquivos (via xargs ).

Localizando arquivos com ls

Antes de usar xargs , o primeiro passo é listar todos os arquivos relevantes. Listar arquivos é fácil com ls | grep cisco ...

[mpenning@Bucksnort post]$ ls | grep cisco
cisco-asa-double-nat.rst
cisco-asa-packet-capture.rst
cisco-eem-tcl.rst
cisco-ip-sla-tracking.rst
cisco_autonomous_to_lwap.rst
[mpenning@Bucksnort post]$

Localizando arquivos com find

Embora provavelmente não seja necessário neste caso específico, localizar é geralmente considerado mais seguro quando se está trabalhando em xargs . No entanto, toda a lógica parece sair da janela quando eu uso find -regex .

[mpenning@Bucksnort post]$ find -regextype grep -regex ".*/cisco*" -print
[mpenning@Bucksnort post]$

No entanto, sei que posso encontrar esses arquivos ...

[mpenning@Bucksnort post]$ find | grep cisco
./cisco-eem-tcl.rst
./parsing-cisco-output-w-textfsm.rst
./cisco_autonomous_to_lwap.rst
./cisco-ip-sla-tracking.rst
./cisco-asa-double-nat.rst
./cisco-asa-packet-capture.rst
[mpenning@Bucksnort post]$

Perguntas

Entendo que find -regex precisa corresponder ao caminho completo retornado, mas por que o find -regextype grep -regex ".*/cisco*" -print não está funcionando acima? Não deve .*/cisco* corresponder ao caminho?

NOTAS

Sei que posso usar apenas find -path "*cisco*" para resolver o problema, mas o ponto da questão é entender por que meu uso de -regex está errado.

    
por Mike Pennington 18.12.2013 / 09:53

2 respostas

6

Encontrar com ls : as primeiras coisas primeiro, ls | grep cisco é um pouco detalhado, pois cisco não é uma expressão regular. Experimente:

ls *cisco*

Usando find : seguindo as mesmas linhas, -regex é um exagero com um padrão simples e estático. Que tal:

find -name '*cisco*'

As aspas são necessárias para que o glob seja interpretado por find , não pelo shell. Além disso, -print é necessário para muitas versões de find , mas é opcional (e o predicado padrão) para outros (por exemplo, GNU find ). Sinta-se à vontade para adicioná-lo se precisar.

Se você precisar pesquisar "cisco" no nome completo do caminho, tente isso:

find -path '*cisco*'

que é equivalente a find | fgrep cisco .

Usando find com expressões regulares : vamos fazer isso de qualquer maneira, já que é isso que você quer. Copiando sem vergonha do GNU find manpage:

-regex pattern

          File  name  matches  regular  expression  pattern.  This is a match
          on the whole path, not a search.  For example, to match a file named
          './fubar3', you can use the regular expression '.*bar.' or '.*b.*3',
          but not 'f.*r3'.

O que isto significa é que a sua expressão regular é encapsulada em um ^...$ invisível, então deve corresponder a todos os caracteres no nome completo do caminho do arquivo. Então, como nwildner e otokan disseram nos comentários, você deveria usar algo como:

find -regex '.*cisco.*'

E você nem precisa do -regextype para algo tão simples.

    
por 18.12.2013 / 11:35
2

O motivo pelo qual find -regex ".*/cisco*" não corresponde a nenhum caminho como ./cisco-eem-tcl.rst ou ./cisco_autonomous_to_lwap.rst é o seguinte:

  • .* corresponde a qualquer coisa - qualquer caractere, zero ou mais vezes
  • / corresponde a uma única barra - até aqui tudo bem
  • cisco* corresponde a cisc , seguido por qualquer número de o .

Lembre-se de que o operador asterix * restringe a repetição de seu item anterior, que é o neste caso. Isso significa que não temos nada correspondente a esse último componente do padrão, porque seria algo como cisc , cisco , ciscoo , ciscooo ... ad infinitum.

Se você precisar expressar que qualquer coisa pode seguir a palavra cisco , use .* depois disso:

find -regex '.*/cisco.*'

Talvez você queira ser um pouco mais restritivo em seus resultados de pesquisa, correspondendo somente rst arquivos:

find -regex '.*/cisco.*\.rst'

No entanto, fazer uma correspondência simples no componente de nome de arquivo do caminho, como esse, não requer o poder expressivo de expressões regulares para que você possa se sair bem usando apenas -name com glob para obter a mesma correspondência:

find -name 'cisco*.rst'

e para processar essas correspondências com xargs você faria algo assim:

find -name 'cisco*.rst' -print0 | xargs -0 command

Você deve sempre lembrar que regexes e globs são coisas diferentes sintática e semanticamente. Veja man find e leia sobre as opções -name e -regex para saber mais.

    
por 18.12.2013 / 12:03