Estou tentando usar find para retornar todos os nomes de arquivos que tenham um diretório específico em seu caminho, mas não tenham outro diretório específico em nenhum lugar no caminho do arquivo. Algo como:
myRegex= <regex>
targetDir= <source directory>
find $targetDir -regex $myRegex -print
Eu sei que também posso fazer isso canalizando um comando find para outro, mas gostaria de saber como fazer isso com uma única expressão regular.
Por exemplo, eu quero todo arquivo que tenha o diretório "good" em seu caminho, mas não tenha o diretório "bad" em nenhum lugar em seu caminho, não importa a combinação. Alguns exemplos:
/good/file_I_want.txt #Captured
/good/bad/file_I_dont_want.txt #Not captured
/dir1/good/file_I_want.txt #Captured
/dir2/good/bad/file_I_dont_want.txt #Not captured
/dir1/good/dir2/file_I_want.txt #Captured
/dir1/good/dir2/bad/file_I_want.txt #Not captured
/bad/dir1/good/file_I_dont_want.txt #Not captured
Tenha em mente que alguns nomes de arquivos podem conter "bom" ou "ruim", mas eu só quero considerar nomes de diretórios.
/good/bad.txt #Captured
/bad/good.txt #Not captured
Minha pesquisa sugere que eu deveria usar um Negative Lookahead e um Negative Lookbehind. No entanto, nada que tentei funcionou até agora. Alguma ajuda seria apreciada. Obrigado.
Como Inian disse, você não precisa
-regex
(o que não é padrão, e a sintaxe varia muito entre as implementações que suportam-regex
¹).Você pode usar
-path
para isso, mas também pode dizerfind
para não inserir diretórios chamadosbad
, o que seria mais eficiente do que descobrir todos os arquivos neles para depois filtrá-los com-path
:(
LC_ALL=C
então o curingafind
de 's*
não engasga com nomes de arquivos com sequência de bytes não formando caracteres válidos na localidade).Ou para mais de um nome de pasta:
Com
zsh
, você também pode fazer:Ou para as listas em arrays:
Para não descer em dirs chamados
bad
, ou (menos eficiente como com-path '*/good/*' ! -path '*/bad/*'
):Em
zsh -o extendedglob
,~
é o operador de globbing exceto (e não) enquanto^
é o operador de negação e#
é 0-ou-mais-da-coisa-anterior como regexp*
.${(~j[|])array}
une os elementos da matriz com|
,|
sendo tratado como um operador glob em vez de um literal|
com~
.Em
zsh
, você poderá usar a correspondência PCRE depois deset -o rematchpcre
:Mas essa avaliação do código shell para cada arquivo (incluindo aqueles em
bad
diretórios) provavelmente o tornará muito mais lento do que outras soluções.Também tome cuidado para que o PCRE (ao contrário do zsh globs) engasgue com sequências de bytes que não formam caracteres válidos na localidade e não suporta conjuntos de caracteres de vários bytes diferentes do UTF-8. Corrigir a localidade para
C
gostarfind
acima resolveria ambos para esse padrão específico.Se você preferir
[[ =~ ]]
apenas fazer a correspondência regexp estendida como embash
, você também pode carregar o módulo pcre (zmodload zsh/pcre
) e usar[[ -pcre-match ]]
em vez de[[ =~ ]]
fazer a correspondência PCRE.Ou você pode fazer a filtragem com
grep -zP
(assumindo GNUgrep
ou compatível):(embora
find
ainda descubra todos os arquivos em todos osbad
diretórios).Substitua
tr '\0' '\n'
porxargs -r0 cmd
se precisar fazer algo com esses arquivos (além de imprimi-los um por linha).¹ De qualquer forma, não conheço nenhuma
find
implementação que suporte expressões regulares do tipo perl ou do tipo vim que você precisaria para operadores de pesquisa.Você não precisa de um regex para isso, você pode usar o
-path
predicado para excluir diretórios com um nome específico em qualquer nívelEmbora seja provavelmente menos eficiente (embora eu não tenha certeza!) e menos "correto" do que
find
a filtragem poderosa (por exemplo, ingênuogrep
aqui não funcionará para nomes contendo caracteres de nova linha, embora sejam extremamente raros e normalmente representem um erro) , geralmente é muito mais fácil empilhar algumas instânciasgrep
que filtram sucessivamente os resultados usando correspondências mais simples e correspondências inversas-v
Isso exige mais cuidado com as substrings para garantir que você realmente encontre um nome de diretório, mas geralmente fornecerá uma sintaxe muito mais fácil de entender e poderá fazer tudo o que você precisa!