Eu tive repetidamente este problema: Eu tenho um glob, que corresponde exatamente aos arquivos corretos, mas causa Command line too long
. Toda vez que o converti em alguma combinação de find
e grep
isso funciona para uma situação específica, mas que não é 100% equivalente.
Por exemplo:
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
Existe uma ferramenta para converter globs em find
expressões que eu não conheço? Ou existe uma opção para find
corresponder ao globo sem corresponder ao mesmo globo em um subdiretório (por exemplo, foo/*.jpg
não é permitido corresponder bar/foo/*.jpg
)?
-path
ou-ipath
.find . -path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg'
deve funcionar - exceto que corresponderá/fooz/blah/bar/quuxA/pic1234d.jpg
. Isso será um problema?echo <glob> | cat
, assumindo o meu conhecimento do bash, eco é build-in, e, portanto, não tem o limite de comandos maxRespostas:
Se o problema é que você recebe um erro da lista de argumentos muito longo, use um loop ou um shell interno. Enquanto
command glob-that-matches-too-much
pode errar,for f in glob-that-matches-too-much
não, então você pode simplesmente fazer:O loop pode ser terrivelmente lento, mas deve funcionar.
Ou:
(
printf
sendo incorporado na maioria dos shells, o acima funciona em torno da limitação daexecve()
chamada do sistema)Também funciona com o bash. Não tenho certeza exatamente onde isso está documentado.
Tanto o Vim
glob2regpat()
quanto o Pythonfnmatch.translate()
podem converter globs em regexes, mas ambos também usam.*
para*
, correspondendo/
.fonte
something
porecho
deveria fazê-lo.printf
- será mais rápido do que ligarecho
milhares de vezes e oferece mais flexibilidade.exec
, que se aplica a comandos externos comocat
; mas esse limite não se aplica a comandos internos do shell, comoprintf
.printf
é um builtin, e os shells presumivelmente usam o mesmo método para fornecer argumentos a eles que eles usam para enumerar argumentos parafor
.cat
não é um builtin.mksh
ondeprintf
não está embutido e conchas comoksh93
ondecat
está (ou pode ser) embutido. Veja tambémzargs
emzsh
trabalhar em torno dele sem ter de recorrer axargs
.find
(para os predicados-name
/-path
padrão) usa padrões curinga como globs (observe que{a,b}
não é um operador glob; após a expansão, você obtém dois globs). A principal diferença é o tratamento de barras (e os arquivos e diretórios de ponto não são tratados especialmente emfind
).*
no globs não abrange vários diretórios.*/*/*
fará com que até 2 níveis de diretórios sejam listados. A adição de a-path './*/*/*'
corresponderá a qualquer arquivo com pelo menos três níveis de profundidade e não deixaráfind
de listar o conteúdo de qualquer diretório em qualquer profundidade.Para esse particular
par de globs, é fácil de traduzir, você quer diretórios na profundidade 3, para poder usar:
(ou
-depth 3
com algumasfind
implementações). Ou POSIXly:O que garantiria isso
*
e?
não poderia corresponder aos/
caracteres.(
find
, ao contrário dos globs, leria o conteúdo de diretórios diferentes dos do diretóriofoo*bar
atual¹ e não classificaria a lista de arquivos. Mas, se deixarmos de lado o problema de que o que corresponde[A-Z]
ou o comportamento de*
/?
com relação a caracteres inválidos é não especificado, você obterá a mesma lista de arquivos).Mas, em qualquer caso, como o @muru mostrou , não há necessidade de recorrer
find
se for apenas para dividir a lista de arquivos em várias execuções para contornar o limite daexecve()
chamada do sistema. Algumas conchas comozsh
(comzargs
) ouksh93
(comcommand -x
) têm suporte embutido para isso.With
zsh
(cujos globos também têm o equivalente-type f
e a maioria dos outrosfind
predicados), por exemplo:(
(|.bak)
É um operador glob contrário a{,.bak}
, o(.)
glob qualificador é o equivalente dofind
's-type f
, adicioneoN
lá para ignorar a classificação como comfind
,D
para incluir dot-files (não se aplica a este glob))To Para
find
rastrear a árvore de diretórios como os globs precisariam, seria necessário algo como:Isso remove todos os diretórios no nível 1, exceto
foo*bar
os e todos no nível 2, exceto osquux[A-Z]
ouquux[A-Z].bak
, e então selecionapic...
os no nível 3 (e remove todos os diretórios nesse nível).fonte
Você pode escrever um regex para encontrar os requisitos correspondentes:
fonte
.
, adicione o jogo opcional para.bak
e mudança*
para[^/]*
não coincidir com caminhos como / foo / foo / bar etc.[0-9][0-9][0-9][0-9]?
a[0-9]{3,4}
Generalizando a nota da minha outra resposta , como uma resposta mais direta à sua pergunta, você pode usar este
sh
script POSIX para converter o glob em umafind
expressão:Para ser usado com um
sh
glob padrão (não os dois globs do seu exemplo que usam expansão de chave ):(isso não ignora arquivos de ponto ou dirs de ponto, exceto
.
e..
não classifica a lista de arquivos).Esse funciona apenas com globs em relação ao diretório atual, sem componentes
.
ou..
. Com algum esforço, você pode estendê-lo a qualquer glob, mais do que um glob ... Isso também pode ser otimizado paraglob2find 'dir/*'
não parecerdir
o mesmo que seria para um padrão.fonte