Padrão `find -name` que corresponde a vários padrões

335

Eu estava tentando obter uma lista de todos os arquivos Python e HTML em um diretório com o comando find Documents -name "*.{py,html}".

Então veio a página de manual:

As chaves dentro do padrão ('{}') não são consideradas especiais (ou seja, localize. -Name 'foo {1,2}' corresponde a um arquivo chamado foo {1,2}, não aos arquivos foo1 e foo2.

Como isso faz parte de uma cadeia de tubulação, eu gostaria de poder especificar quais extensões ela corresponde no tempo de execução (sem codificação). Se o find não puder fazê-lo, um liner perl (ou similar) seria bom.

Edit: A resposta que acabei encontrando inclui todos os tipos de porcaria, e é um pouco longa também, então eu a publiquei como resposta à coceira original que estava tentando arranhar. Sinta-se livre para hackear isso se você tiver melhores soluções.

Xiong Chiamiov
fonte
Um utilitário muitas vezes esquecido e subutilizado também é locate, embora com a ressalva de que a atualização internab pode não estar atualizada. Mas é rápido.
michael
Estou votando para encerrar esta questão como off-topic porque ela pertence ao Unix e Linux
Dan Dascalescu

Respostas:

481

Use -o, que significa "ou":

find Documents \( -name "*.py" -o -name "*.html" \)

Você precisaria criar essa linha de comando programaticamente, o que não é tão fácil.

Você está usando o bash (ou Cygwin no Windows)? Se você é, deve poder fazer o seguinte:

ls **/*.py **/*.html

o que pode ser mais fácil de construir programaticamente.

RichieHindle
fonte
3
Estou usando o zsh, que, como regra geral, suporta todos os basismos, além de mais.
Xiong Chiamiov 15/07/2009
12
O Zsh suporta **pesquisa recursiva; O Bash suporta apenas nas versões 4.0 e posteriores, e somente com shopt -s globstar.
ephemient
2
Quantos -o args você pode ter? Eu tenho um potencialmente grande lista de .gcda (dados de cobertura) arquivos para construir
Jasper azuis
40
Você precisa cercar os dois -names entre colchetes, se estiver usando -exec. Por exemplofind Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
artbristol
2
O comentário @artbristol é muito relevante se, por exemplo, você estiver adicionando um -print0para lidar com nomes de arquivos com espaços.
Nimrodm
63

Algumas edições do find, principalmente nos sistemas linux, possivelmente em outros, também suportam as opções -regex e -regextype, que encontram arquivos com nomes correspondentes ao regex.

por exemplo

find . -regextype posix-egrep -regex ".*\.(py|html)$" 

deve fazer o truque no exemplo acima. No entanto, essa não é uma função de localização POSIX padrão e depende da implementação.

intelekt
fonte
1
intersting mas mais complexo do que as outras respostas
m1k3y3
12
Mais simples: find . -regex ".*\.\(py\|html\)$"isso funciona porque encontra padrões para expressões regulares no estilo Emacs, que são ligeiramente diferentes, para que você não precise especificar o regextype.
robru
2
Se você tem muitas expressões, -regextype posix-egrepé útil (caso contrário, você precisará escapar de muitos caracteres). Este é o comando find eu usei para um dist-hook construção de um zip distribuição do Windows (encontra os arquivos para a mudança e em arquivo muda-los para dos-EOL): find -regextype posix-egrep -regex ".*(\.([chyl]|def|cpy|cob|conf|cfg)|(README|ChangeLog|AUTHORS|ABOUT-NLS|NEWS|THANKS|TODO|COPYING.*))$" -exec sed -i -e 's/\r*$/\r/' {} \;
Simon Sobisch
32

Você pode adicionar programaticamente mais -namecláusulas, separadas por -or:

find Documents \( -name "*.py" -or -name "*.html" \)

Ou escolha um loop simples:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done
Stephan202
fonte
@ user2284570: então não há *.pyarquivos ou você tem uma versão estranha do find. O comando listado acima funciona muito bem.
Stephan202
Não, estou usando -iname. Ele retorna os *.pyarquivos apenas se gravá-los na última posição (assim iname *.htmlcomo a primeira expressão) . Eu uso o comando no Debian.
user2284570
Você está usando aspas? Isso é muito importante.
Stephan202
1
É um -ou ou -o?
Stephane
1
@ StephaneEybert: está bom, mas apenas o último é compatível com POSIX (de acordo com a página de manual).
Stephan202
16

Isso encontrará todos os arquivos .c ou .cpp no ​​linux

$ find . -name "*.c" -o -name "*.cpp"

Você não precisa dos parênteses escapados, a menos que esteja fazendo alguns mods adicionais. Aqui, na página de manual, eles estão dizendo se o padrão corresponde, imprima-o. Talvez eles estejam tentando controlar a impressão. Nesse caso, a impressão-atua como uma condicional e se torna uma condição "AND'd". Isso impedirá a impressão de qualquer arquivo .c.

$ find .  -name "*.c" -o -name "*.cpp"  -print

Mas se você gostar da resposta original, poderá controlar a impressão. Isso encontrará todos os arquivos .c também.

$ find . \( -name "*.c" -o -name "*.cpp" \) -print

Um último exemplo para todos os arquivos de origem c / c ++

$ find . \( -name "*.c" -o -name "*.cpp"  -o -name "*.h" -o -name "*.hpp" \) -print
netskink
fonte
11

Eu tive uma necessidade semelhante. Isso funcionou para mim:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print
bkidd
fonte
3
Perfeito. Mas acho que é um pouco estranho que ele não funciona sem a()
pedrofurla
Eu queria encontrar arquivos que correspondessem a * .c * .cpp ou * .cc Com apenas dois padrões de nome, eu não precisava de parênteses, mas com três padrões de nome associados a dois padrões -o, find -name "*.cpp" -o -name "*.c" -o -name "*.cc" -print0tive que usar um par de parênteses para agrupe o segundo ou operador. find -name "*.cpp" -o \( -name "*.c" -o -name "*.cc" \) -print0Pode ser que o -print0, que é sempre "verdadeiro", tenha afetado a lógica.
cardiff space man
5

Meu padrão foi:

find -type f | egrep -i "*.java|*.css|*.cs|*.sql"

Como a findexecução menos intencional do processo por Brendan Long e Stephan202 et al .:

find Documents \( -name "*.py" -or -name "*.html" \)

PaSe
fonte
3
esse não é um uso correto do egrepregexp. Em vez disso, você tem um shell glob onde um regexp deve ser usado. (Além disso, o finduso típico é find {directory} [options...] [action]:, onde, dependendo de impl, directorypode usar .como actionpadrão -print, mas serei explícito.) Portanto, use algo como: find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' Mas também, como uma alternativa muito rápida find, pode-se também tente locatede forma semelhante (embora não necessariamente até à data, uma vez que consulta um db interno para uma lista de arquivos)
michael
2
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

simples, mas funciona :)

mnrl
fonte
1

Eu precisava remover todos os arquivos em diretórios filhos, exceto alguns arquivos. O seguinte funcionou para mim (três padrões especificados):

find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +
Adobe
fonte
1

As chaves dentro do padrão \(\)são necessárias para o padrão de nome comor

find Documents -type f \( -name "*.py" -or -name "*.html" \)

Embora para o padrão de nome com o andoperador não seja necessário

find Documents -type f ! -name "*.py" -and ! -name "*.html" 
Chetabahana
fonte
0

Isso funciona no AIX Korn Shell.

find *.cbl *.dms -prune -type f -mtime -1

Ele está procurando *.cblou *.dmscom 1 dia de idade, apenas no diretório atual, pulando os subdiretórios.

Abdul M Gill
fonte
0
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"
user7531934
fonte
2
Observe que o último corresponderá a foo.jmg, mas nenhum dos dois primeiros corresponderá.
copper.hat
0

A respeito

ls {*.py,*.html}

Ele lista todos os arquivos que terminam com .py ou .html nos nomes de arquivos

Dr_Hope
fonte