Por que não posso redirecionar uma saída de nome de caminho de um comando para “cd”?

26

Eu estou tentando obter cd para aceitar um nome de diretório redirecionado para ele de outro comando. Nenhum desses métodos funciona:

$ echo $HOME | cd
$ echo $HOME | xargs cd

Isso funciona:

$ cd $(echo $HOME)

Por que o primeiro conjunto de comandos não funciona e há outros que também falham dessa maneira?

    
por Jhonathan 05.10.2012 / 14:47

6 respostas

31

cd não é um comando externo - é uma função interna do shell. Ele é executado no contexto do shell atual e não, como fazem os comandos externos, em um contexto fork / exec'd como um processo separado.

Seu terceiro exemplo funciona, porque o shell expande a variável e a substituição de comando antes de chamar o cd builtin, de modo que cd receba o valor de ${HOME} como seu argumento.

Sistemas POSIX do tem um binário cd - na minha máquina FreeBSD, está em /usr/bin/cd , mas não faz o que você pensa. Chamar o binário cd faz com que o shell bifurque / exec o binário, o que realmente altera seu diretório de trabalho para o nome que você passa. No entanto, assim que isso acontecer, o binário é encerrado e o processo forked / exec'd desaparece, retornando ao seu shell, que ainda está no diretório em que estava antes de iniciar.

    
por 05.10.2012 / 15:03
23

cd não lê entrada padrão. É por isso que o seu primeiro exemplo não funciona.

xargs precisa de um nome de comando, ou seja, um nome de um executável independente. cd precisa ser um comando interno do shell e não teria nenhum efeito (além de verificar se você pode mudar para esse diretório e os potenciais efeitos colaterais que pode ter para diretórios montados automaticamente) se fosse um executável. É por isso que seu segundo exemplo não funciona.

    
por 05.10.2012 / 14:56
4

Além da boa resposta existente, também é importante mencionar que um pipe cria um novo processo, que possui seu próprio diretório de trabalho separado. Portanto, tentar fazer isso não funcionará:

echo test | cd /

Assim, você não estará na pasta / depois que o shell retornar deste comando.

    
por 05.10.2012 / 21:08
4

Além das respostas corretas já dadas: Se você executar o bash e quiser descobrir o que é um "comando" como o cd , você pode usar type

$ type cd
cd is a shell builtin

ou porque não:

$ type time
time is a shell keyword

enquanto, por exemplo, o tempo do gnu normalmente já está incluído na sua distribuição favorita:

$ which time
/usr/bin/time

Okey okey você entendeu, então o que diabos é tipo?

$ type type
type is a shell builtin

Aqui está um trecho manual:

       type [-aftpP] name [name ...]
          With no options, indicate how each name would be interpreted  if  used  as  a
          command name.  If the -t option is used, type prints a string which is one of
          alias, keyword, function, builtin,  or  file  if  name  is  an  alias,  shell
          reserved word, function, builtin, or disk file, respectively.  If the name is
          not found, then nothing is printed, and an exit status of false is  returned.
          If  the -p option is used, type either returns the name of the disk file that
          would be executed if name were specified as a command  name,  or  nothing  if
          ‘‘type  -t  name’’ would not return file.  The -P option forces a PATH search
          for each name, even if ‘‘type -t name’’ would not return file.  If a  command
          is  hashed,  -p  and -P print the hashed value, not necessarily the file that
          appears first in PATH.  If the -a option is used,  type  prints  all  of  the
          places  that  contain  an  executable  named name.  This includes aliases and
          functions, if and only if the -p option is  not  also  used.   The  table  of
          hashed  commands  is  not  consulted when using -a.  The -f option suppresses
          shell function lookup, as with the command builtin.  type returns true if any
          of the arguments are found, false if none are found.
    
por 05.10.2012 / 20:39
0

Como outros já disseram, isso não funcionará porque cd é um comando interno do shell, não um programa externo, então ele não tem nenhuma entrada padrão na qual você possa canalizar qualquer coisa.

Mas, mesmo que funcionasse, não faria o que você deseja: um canal gera um novo processo e redireciona a saída padrão do primeiro comando para a entrada padrão do segundo, portanto, apenas o novo processo mudaria. seu diretório de trabalho atual; isso não poderia afetar o primeiro processo de qualquer maneira.

    
por 06.10.2012 / 19:24
-2

Outra opção são os backticks, que colocam o stdout de um comando como um argumento de linha de comando de um segundo comando e são mais portáteis do que $(...) . Por exemplo:

cd 'echo $HOME'

ou mais geralmente;

cd 'anycommand -and whatever args'

Observe que o uso de backticks depende do shell para executar o comando e substituir a saída na linha de comando. A maioria das conchas suportam isso.

    
por 05.10.2012 / 18:16