encontre as buscas dentro do caminho fornecido, conforme indicado. Então, se você digitar ./, não correspondefoo
Costas
@ Costas: eu entendo isso. O que não entendo é por que fez diferença se eu der o caminho absoluto para find.
York
@York Em certas situações, não existe um comportamento sempre correto. Imagine um link simbólico com o nome barque aponta para um arquivo fooque está fora do caminho de pesquisa. Deve combinar ou não?
Hauke Laging
1
Os .e /tmp/foonão são os mesmos - são dois links físicos diferentes para o mesmo diretório; find /tmp/foo/. -name 'foo'também não encontra nada.
jimmij
@jimmij: quando corro find /tmp/foo -name 'foo', estava pedindo ao bash para encontrar no diretório /tmp/fooum arquivo cujo nome é "foo". Como o diretório /tmp/fooestá vazio, ele não deve ter retornado nada. Eu não entendo por que ele retorna /tmp/foo. Por outro lado, quando eu corro find . -name 'foo', estava perguntando ao bash a mesma coisa, ou seja, encontrando um arquivo no diretório atual (que passou a ser /tmp/foo), cujo nome é 'foo', e ele não retorna nada que faça sentido.
York
Respostas:
15
findpercorre as árvores de diretórios especificadas e avalia a expressão fornecida para cada arquivo que encontra. A travessia começa no caminho especificado. Aqui está um resumo de como find . -name foofunciona:
Primeiro caminho na linha de comando: .
O nome base ( .) corresponde ao padrão foo? Não, então não faça nada.
Acontece que /tmp/fooé outro nome para o mesmo diretório. Mas findnão sabe disso (e não deve tentar descobrir).
O caminho é um diretório? Sim, então atravesse-o. Enumere as entradas .e, para cada entrada, execute o processo de travessia.
O diretório está vazio: ele não contém nenhuma entrada além de .e .., que findnão percorre recursivamente. Então o trabalho está terminado.
E find /tmp/foo:
Primeiro caminho na linha de comando: /tmp/foo
O nome base ( foo) corresponde ao padrão foo? Sim, então a condição corresponde.
Não há ação associada a essa condição, portanto, execute a ação padrão, que é imprimir o caminho.
O caminho é um diretório? Sim, então atravesse-o. Enumere as entradas /tmp/fooe, para cada entrada, execute o processo de travessia.
O diretório está vazio: ele não contém nenhuma entrada além de .e .., que findnão percorre recursivamente. Então o trabalho está terminado.
Acontece que .e /tmp/foosão o mesmo diretório, mas isso não é suficiente para garantir que findtenha o mesmo comportamento em ambos. O findcomando tem maneiras de distinguir entre os caminhos para o mesmo arquivo; o -namepredicado é um deles. find /tmp/foo -name foocorresponde ao diretório inicial, bem como a qualquer arquivo abaixo chamado foo. find . -name .corresponde apenas ao diretório inicial ( .nunca pode ser encontrado durante uma travessia recursiva).
"ele não contém nenhuma entrada que não seja. e .., que encontrar não percorre recursivamente." Presumo que "não se recursivamente se recursivamente" se refira a "..". Se isso estiver correto, o que "transversalmente recursivamente" significaria no contexto de ".."?
Faheem Mitha
@FaheemMitha "não percorre recursivamente" se aplica a ambos .e ... (Se findpercorrido de forma .recursiva, acabaria percorrendo o diretório novamente e novamente e novamente e ...) .e ..não são apenas notações especiais, elas aparecerão como entradas de diretório.
Gilles 'SO- stop be evil' (
5
Não há normalização dos argumentos da linha de comandos antes da aplicação dos testes. Portanto, os resultados diferem dependendo do caminho usado (se links simbólicos estiverem envolvidos):
cd /tmp
mkdir foo
ln -s foo bar
find /tmp/foo -name foo
find /tmp/bar -name foo
No "seu caso", ambas as chamadas dariam o mesmo resultado que pode ser (mais) confuso. Você pode usar -mindepth 1se desejar que os pontos de partida sejam ignorados (podem não ser POSIX).
-mindepth 1trabalho. No entanto, ainda não entendo o porquê find . -name 'foo'e me find /tmp/foo -name 'foo'comporto de maneira diferente.
York
2
(gnu) find mostra todas as correspondências encontradas no caminho fornecido ao comando porque inicia sua comparação com os argumentos da linha de comando, descendo mais profundamente na estrutura de diretórios a partir daí (portanto, -maxdepth 0restringe os testes ao nível base ou apenas aos argumentos da linha de comando, enquanto -mindepth 1pula os argumentos da linha de comando, como man findexplica). Esta é a razão pela find /tmp/foo -name 'foo'qual produzirá uma correspondência, mesmo que o diretório em si esteja vazio.
find . -name 'foo'por outro lado, não produzirá nenhum resultado porque .(ponto) é um arquivo especial que age como um /tmp/foolink físico para o mesmo inode - é como um nome de arquivo separado (embora especial) e não como um link simbólico ou uma expressão sujeita a expansão do nome do caminho pelo shell. Portanto, o primeiro teste aplicado por find aos argumentos da linha de comando no exemplo fornecido não mostrará nenhuma correspondência, pois, na .verdade, não corresponde ao padrão de nome definido em -name 'foo'. Nem /tmp/foo/.uma vez que um teste para um -namepadrão é realizado apenas no nome da base do caminho (consulte man find), que aqui é novamente ..
Embora esse comportamento possa não ser esperado ou parecer intuitivo da perspectiva do usuário (e sim, também me confundiu a princípio), ele não constitui um bug, mas corresponde à lógica e à funcionalidade descritas nas páginas de manual e informações de ( gnu) encontrar.
Tentei comentar a resposta de Gilles, mas demorou muito para caber em um comentário. Por esse motivo, estou colocando isso como resposta à minha própria pergunta.
A explicação de Gilles (e a de Shevek também) é clara e faz sentido. O ponto principal aqui é que não apenas findtenta corresponder os nomes dos arquivos dentro dos caminhos especificados (recursivamente), mas também tenta combinar o nome base dos caminhos especificados.
Por outro lado, há alguma prova de que esse é o caminho findque deve funcionar, em vez de ser um bug? Na minha opinião, seria melhor se isso não tornasse os resultados inconsistentes find .e find ABSOLUTE-PATHporque a inconsistência é sempre confusa e poderia desperdiçar o desenvolvedor muito tempo tentando descobrir "o que estava errado". No meu caso, eu estava escrevendo um script e o caminho foi tomado a partir de uma variável. Portanto, para que meu script funcione corretamente, o que posso pensar em fazer é escrever find $path/. -name 'pattern'.
Finalmente, acho que é possível obter resultados consistentes findsempre substituindo-o .pelo diretório atual antes de prosseguir.
Não há nenhum objeto nomeado foono diretório em que você iniciou a pesquisa relativa.
Você está correto ao supor que gfindhá erros quando ele relata /tmp/fooao usar o nome absoluto como um diretório inicial.
Gfindtem vários desvios do padrão, parece que você encontrou outro. Quando você gosta de uma solução compatível mais padrão, recomendo sfindque faça parte do schilytools.
-nameaplica-se aos resultados da pesquisa de diretório. Nenhum dos dois casos mencionados retornará uma entrada de diretório foode uma readdir()operação.
Eu suspeito que isso seja um bug também. Aqui está a saída de find --version: find (GNU findutils) 4.4.2 Copyright (C) 2007 Free Software Foundation, Inc. Licença GPLv3 +: GNU GPL versão 3 ou posterior < gnu.org/licenses/gpl.html >
York
Bem, verifiquei seu exemplo de comando com find(certificado POSIX) gfinde sfind; o problema só existe quando você usa gfind. No Linux, gfindnão é instalado com o nome nativo, mas com o nome find.
schily
3
Está correto para find /tmp/foo -name fooa saída /tmp/foo. (Cc @York) Esse é o comportamento do OpenBSD find, GNU find, BusyBox find, Solaris finde qualquer outro compatível com POSIX find("O primário avaliará como verdadeiro se o nome da base do nome do arquivo que está sendo examinado corresponder ao padrão (...)" - quando o nome do arquivo é passado como um operando de caminho, nenhuma readdirchamada está envolvida).
./
, não correspondefoo
find
.bar
que aponta para um arquivofoo
que está fora do caminho de pesquisa. Deve combinar ou não?.
e/tmp/foo
não são os mesmos - são dois links físicos diferentes para o mesmo diretório;find /tmp/foo/. -name 'foo'
também não encontra nada.find /tmp/foo -name 'foo'
, estava pedindo ao bash para encontrar no diretório/tmp/foo
um arquivo cujo nome é "foo". Como o diretório/tmp/foo
está vazio, ele não deve ter retornado nada. Eu não entendo por que ele retorna/tmp/foo
. Por outro lado, quando eu corrofind . -name 'foo'
, estava perguntando ao bash a mesma coisa, ou seja, encontrando um arquivo no diretório atual (que passou a ser/tmp/foo
), cujo nome é 'foo', e ele não retorna nada que faça sentido.Respostas:
find
percorre as árvores de diretórios especificadas e avalia a expressão fornecida para cada arquivo que encontra. A travessia começa no caminho especificado. Aqui está um resumo de comofind . -name foo
funciona:.
.
) corresponde ao padrãofoo
? Não, então não faça nada.Acontece que
/tmp/foo
é outro nome para o mesmo diretório. Masfind
não sabe disso (e não deve tentar descobrir)..
e, para cada entrada, execute o processo de travessia..
e..
, quefind
não percorre recursivamente. Então o trabalho está terminado.E
find /tmp/foo
:/tmp/foo
foo
) corresponde ao padrãofoo
? Sim, então a condição corresponde./tmp/foo
e, para cada entrada, execute o processo de travessia..
e..
, quefind
não percorre recursivamente. Então o trabalho está terminado.Acontece que
.
e/tmp/foo
são o mesmo diretório, mas isso não é suficiente para garantir quefind
tenha o mesmo comportamento em ambos. Ofind
comando tem maneiras de distinguir entre os caminhos para o mesmo arquivo; o-name
predicado é um deles.find /tmp/foo -name foo
corresponde ao diretório inicial, bem como a qualquer arquivo abaixo chamadofoo
.find . -name .
corresponde apenas ao diretório inicial (.
nunca pode ser encontrado durante uma travessia recursiva).fonte
.
e..
. (Sefind
percorrido de forma.
recursiva, acabaria percorrendo o diretório novamente e novamente e novamente e ...).
e..
não são apenas notações especiais, elas aparecerão como entradas de diretório.Não há normalização dos argumentos da linha de comandos antes da aplicação dos testes. Portanto, os resultados diferem dependendo do caminho usado (se links simbólicos estiverem envolvidos):
No "seu caso", ambas as chamadas dariam o mesmo resultado que pode ser (mais) confuso. Você pode usar
-mindepth 1
se desejar que os pontos de partida sejam ignorados (podem não ser POSIX).fonte
-mindepth 1
trabalho. No entanto, ainda não entendo o porquêfind . -name 'foo'
e mefind /tmp/foo -name 'foo'
comporto de maneira diferente.(gnu) find mostra todas as correspondências encontradas no caminho fornecido ao comando porque inicia sua comparação com os argumentos da linha de comando, descendo mais profundamente na estrutura de diretórios a partir daí (portanto,
-maxdepth 0
restringe os testes ao nível base ou apenas aos argumentos da linha de comando, enquanto-mindepth 1
pula os argumentos da linha de comando, comoman find
explica). Esta é a razão pelafind /tmp/foo -name 'foo'
qual produzirá uma correspondência, mesmo que o diretório em si esteja vazio.find . -name 'foo'
por outro lado, não produzirá nenhum resultado porque.
(ponto) é um arquivo especial que age como um/tmp/foo
link físico para o mesmo inode - é como um nome de arquivo separado (embora especial) e não como um link simbólico ou uma expressão sujeita a expansão do nome do caminho pelo shell. Portanto, o primeiro teste aplicado por find aos argumentos da linha de comando no exemplo fornecido não mostrará nenhuma correspondência, pois, na.
verdade, não corresponde ao padrão de nome definido em-name 'foo'
. Nem/tmp/foo/.
uma vez que um teste para um-name
padrão é realizado apenas no nome da base do caminho (consulteman find
), que aqui é novamente.
.Embora esse comportamento possa não ser esperado ou parecer intuitivo da perspectiva do usuário (e sim, também me confundiu a princípio), ele não constitui um bug, mas corresponde à lógica e à funcionalidade descritas nas páginas de manual e informações de ( gnu) encontrar.
fonte
Tentei comentar a resposta de Gilles, mas demorou muito para caber em um comentário. Por esse motivo, estou colocando isso como resposta à minha própria pergunta.
A explicação de Gilles (e a de Shevek também) é clara e faz sentido. O ponto principal aqui é que não apenas
find
tenta corresponder os nomes dos arquivos dentro dos caminhos especificados (recursivamente), mas também tenta combinar o nome base dos caminhos especificados.Por outro lado, há alguma prova de que esse é o caminho
find
que deve funcionar, em vez de ser um bug? Na minha opinião, seria melhor se isso não tornasse os resultados inconsistentesfind .
efind ABSOLUTE-PATH
porque a inconsistência é sempre confusa e poderia desperdiçar o desenvolvedor muito tempo tentando descobrir "o que estava errado". No meu caso, eu estava escrevendo um script e o caminho foi tomado a partir de uma variável. Portanto, para que meu script funcione corretamente, o que posso pensar em fazer é escreverfind $path/. -name 'pattern'
.Finalmente, acho que é possível obter resultados consistentes
find
sempre substituindo-o.
pelo diretório atual antes de prosseguir.fonte
Não há nenhum objeto nomeado
foo
no diretório em que você iniciou a pesquisa relativa.Você está correto ao supor que
gfind
há erros quando ele relata/tmp/foo
ao usar o nome absoluto como um diretório inicial.Gfind
tem vários desvios do padrão, parece que você encontrou outro. Quando você gosta de uma solução compatível mais padrão, recomendosfind
que faça parte doschilytools
.-name
aplica-se aos resultados da pesquisa de diretório. Nenhum dos dois casos mencionados retornará uma entrada de diretóriofoo
de umareaddir()
operação.fonte
find --version
: find (GNU findutils) 4.4.2 Copyright (C) 2007 Free Software Foundation, Inc. Licença GPLv3 +: GNU GPL versão 3 ou posterior < gnu.org/licenses/gpl.html >find
(certificado POSIX)gfind
esfind
; o problema só existe quando você usagfind
. No Linux,gfind
não é instalado com o nome nativo, mas com o nomefind
.find /tmp/foo -name foo
a saída/tmp/foo
. (Cc @York) Esse é o comportamento do OpenBSDfind
, GNUfind
, BusyBoxfind
, Solarisfind
e qualquer outro compatível com POSIXfind
("O primário avaliará como verdadeiro se o nome da base do nome do arquivo que está sendo examinado corresponder ao padrão (...)" - quando o nome do arquivo é passado como um operando de caminho, nenhumareaddir
chamada está envolvida).