$ find -exec cd => fornece erro: => find: 'cd': Esse arquivo ou diretório não existe

8

Quando executo este comando, ele funciona:

$ find . -inum 888696 -exec ls '{}' \;
Conversation.pst  Outlook Data File  Outlook Data File.sbd  Trash      Unsent Messages
Inbox.pst     Outlook Data File.msf  Sent.pst       Trash.msf  Unsent Messages.msf

No entanto, ao substituir lspor cdele não funciona:

$ find . -inum 888696 -exec cd '{}' \;
find: cd’: No such file or directory

Eu sei que cdé um bashbuilt-in, então eu tentei isso que também não funciona:

$ find . -inum 888696 -exec builtin cd '{}' \;
find: builtin’: No such file or directory

Como posso usar cdjunto com o find -execcomando?


ATUALIZAR

A razão que eu estou tentando usar cdcom find -execé que o nome do diretório é um estranho que aparece no meu terminal como algo parecido ????.

user3405291
fonte
1
BTW, você pode LC_ALL=C printf '%q\n' *imprimir nomes ASCII para todos os arquivos em seu diretório atual, um para uma linha (alterando novas linhas para $'\n'ou similares).
Charles Duffy

Respostas:

15

A -execopção de findexecutar um utilitário externo, possivelmente com alguma opção de linha de comando e outros argumentos.

Seu Unix não fornece cdcomo um utilitário externo, apenas como um shell embutido, portanto, findfalha ao executá-lo. Pelo menos MacOS e Solaris que fornecem cdcomo um utilitário externo.

Haveria pouco ou nenhum uso para executar cddessa maneira, exceto como uma maneira de testar se o nome do caminho encontrado por findé um diretório no qual você seria capaz cd. O diretório de trabalho no seu shell interativo (ou o que estiver chamando find) não mudaria de qualquer maneira.

Relacionado:


Se você está tendo problemas com o nome de um diretório que é estranho ou extremamente difícil de digitar e deseja mudar para esse diretório, considere criar um link simbólico para o diretório e, cdem seguida , usar esse link:

find . -inum 888696 -exec ln -s {} thedir ';'

Isso criaria um link simbólico chamado thedirque apontaria para o diretório problemático. Você pode alterar o diretório de trabalho com

cd thedir

(se o link existir no diretório atual). Isso evita modificar o diretório de qualquer maneira. Outra idéia seria renomear o diretório de maneira semelhante find, mas isso não seria aconselhável se outro programa esperasse que o diretório tivesse esse nome específico.

Kusalananda
fonte
A razão que eu intenção de usar cdcom find -execé que os nomes de diretório são, em alguns caracteres estranhos que não aparecem corretamente em meu terminal.
user3405291
@ user3405291 Não está claro na pergunta o que você espera que aconteça ao executar o comando. Você espera alterar o diretório no shell interativo?
Kusalananda
Sim, eu só quero cdentrar em um diretório que tem um nome ruim e não consigo cdnele normalmente.
user3405291
@ user3405291 Ver atualização.
Kusalananda
O engraçado é que isso /bin/cdé resultado do POSIX ( pubs.opengroup.org/onlinepubs/9699919799/utilities/… ), onde os componentes internos normais precisam estar acessíveis para exec (). Claro, /bin/cdprovavelmente não faz o que as pessoas querem :-)
Stephen Harris
7

findexecuta o -execpróprio comando, não envolve um shell. Mesmo que isso acontecesse, a alteração do diretório só persistiria até a saída do shell, imediatamente após o cd.

Você precisará colocar o nome do arquivo no shell atual cd. Dependendo de quão ruins são os seus nomes de arquivos, você pode usar a substituição de comandos:

cd "$(find . -inum 888696)"

Isso não funcionará se o nome do arquivo terminar em uma nova linha, pois a substituição de comando come novas linhas à direita. Nesse caso, você precisará proteger a nova linha e se livrar da que findadiciona ao imprimir:

dir=$(find . -inum 888696; echo x)
cd "${dir%?x}"

Ou, com o GNU find, ele não imprime a nova linha à direita (mas ainda protege alguma no nome do arquivo):

dir=$(find . -inum 888696 -printf "%px" -quit)
cd "${dir%x}"

Também usando o -quitpredicado (também uma extensão GNU), para parar de cuidar da primeira correspondência como uma otimização.

Como alternativa, você pode iniciar um novo shell a partir de dentro find, mas é um pouco feio:

find . -inum 888696 -exec bash -c 'cd "$1" && exec bash' sh {} \;
ilkkachu
fonte
Tentei o seu truque com o "eco x", em diretórios que terminam com nova linha, retorno de carro e ambos, sem êxito.
Gerard H. Pille
@ GerardH.Pille, desculpe, esqueci que a nova linha findadiciona ao imprimir. Editado.
Ilkkachu
Se você substituir o printf por um print0, poderá executar 'cd "$ dir"'.
Gerard H. Pille
@ GerardH.Pille, talvez. Mas o Bash ignora quaisquer bytes nulos na entrada de uma substituição de comando e remove a nova linha à direita somente depois disso. Então dir=$(find -print0)ainda irá lixo do final de linha do nome do arquivo ...
ilkkachu
5

Não com o exec, mas isso pode ser bom o suficiente para você:

cd "$(find . -inum 888696 -type d)"

O "-type d", apenas para ter certeza. Do que eu realmente não sei.

Gerard H. Pille
fonte
Isso falhará se o nome do diretório terminar com uma nova linha.
Kusalananda
Claro, mas os diretórios raramente o fazem. Se eu tentar criar um em um linux ext4, recebo "erro de protocolo". Você não acha que isso é uma perda de tempo?
Gerard H. Pille
2
Bem, os nomes raramente têm caracteres imprimíveis, mas este obviamente tem.
Kusalananda
Quais sistemas de arquivos permitem novas linhas nos nomes de diretório?
Gerard H. Pille
1
@ GerardH.Pille, como você testou isso? mkdir $'foo\n'funciona perfeitamente aqui; Ainda não vi um sistema de arquivos UNIX nativo em que não era suportado.
Charles Duffy
4

Use um fluxo delimitado por NUL para ler a saída findque funciona em todos os casos - incluindo nomes que terminam em novas linhas. Além disso, você pode usar printf '%q'para gerar uma representação legível de um nome de arquivo.

inum=888696
if IFS= read -r -d '' filename < <(find . -inum "$inum" -print0); then
  LC_ALL=C printf 'Located filename: %q\n' "$filename" >&2
  cd -- "$filename"
else
  echo "No file located for inode $inum" >&2
fi
Charles Duffy
fonte
3

Se você receber essa mensagem, sua plataforma do sistema operacional estará com erros. O padrão POSIX requer que um comando nomeado cdesteja disponível no sistema de arquivos para que possa ser chamado via exec().

Agora as más notícias para você:

Mesmo que sua plataforma do sistema operacional não tenha problemas, você simplesmente não viu um aviso, mas não obteve os resultados esperados, pois não ajuda se um programa separado altera seu diretório de trabalho atual e morre imediatamente depois disso.

Se você deseja que cdum comando efetivo seja executado por find, você pode fazer algo como:

find . -type d -exec sh -c 'cd "$1"; some other command' dummy {} \;
esperto
fonte
2
Isso é apenas um bug se a plataforma reivindicar a conformidade POSIX. Ter um utilitário de CD independente não é muito útil; portanto, faz sentido ignorar esse requisito de outra forma, sem afetar a usabilidade da plataforma. Observe que deixar uma expansão de parâmetro sem aspas tem um significado muito especial sh, não algo que você gostaria de fazer. É melhor evitar valores fictícios para esse script embutido, $0como é usado em mensagens de erro, por exemplo (como quando isso cdfalharia).
Stéphane Chazelas
Você quis dizer cd "$1"? Se o nome é difícil de digitar, ele pode muito bem também conter metacaracteres shell ...
Toby Speight
corrigir este foi um erro de digitação
Schily