é possível alterar o diretório de trabalho do shell pai programaticamente?

8

Eu quero escrever algum código para permitir que eu mude para alguns diretórios aos quais costumo ir. Digamos que este programa seja mycde /a/very/long/path/nameé o diretório que eu quero acessar.

Então eu posso simplesmente digitar em mycd 2vez de cd /a/very/long/path/name. Aqui, eu suponho mycdque 2se refere a isso /a/very/long/path/name. Também pode haver mycd 1, mycd 3... etc.

O problema é que eu tenho que escrever mycdcomo um script de shell e digitar . mycd 2para fazer a coisa desejada, porque, caso contrário, o script será executado em um script filho que não muda nada no shell pai com o qual realmente me importo.

Minha pergunta é:

  • posso fazer isso sem usar source? porque . mycdassume mycdque deve ser um script de shell e isso também pode introduzir algumas funções que eu não quero.

  • posso implementá-lo em outras linguagens de programação?

Javran
fonte

Respostas:

23

faça mycduma função para que o cdcomando seja executado no seu shell atual. Salve-o no seu arquivo ~ / .bashrc.

function mycd {
    if (( $# == 0 )); then
        echo "usage: $FUNCNAME [1|2|3|...]"
        return
    fi
    case $1 in
        1) cd /tmp ;;
        2) cd /a/very/long/path/name ;;
        3) cd /some/where/else ;;
        *) echo "unknown parameter" ;;
    esac
}
Glenn Jackman
fonte
Obrigado, não pensei em usar funções, e isso só permite tudo: agora posso deixar mycdpassar $@para qualquer programa que eu goste.
Javran
Certifique-se de citar "$@"para que todos os argumentos que contenham espaços em branco sejam manipulados corretamente.
Glenn Jackman
9

Você não pode alterar o diretório atual de um shell de outro processo. Somente o próprio processo pode alterar seu próprio diretório atual. Isso também vale para algumas outras características, como variáveis ​​de ambiente e descritores de arquivo.

Na verdade, é possível afetar o diretório atual de outro processo, fazendo com que ele execute uma chdirchamada do ptracesistema por meio da chamada do sistema, que é o que permite que os depuradores funcionem. No entanto, se o processo mantiver algumas estruturas de dados internas que precisam ser consistentes com o diretório atual atual, é provável que o programa trava. Para um shell, essa abordagem não tem chance de funcionar.

Você precisa providenciar para que seu código seja executado pelo próprio shell. A maneira normal de proceder seria torná-lo uma função shell e armazená-lo no seu ~/.bashrc. Se isso não for possível, por exemplo, porque é o código que você deseja distribuir, escrever um arquivo de origem concha que contém a definição da função, e dizer às pessoas para ter seu shell interativo ler o seu arquivo com o .comando .

Gilles 'SO- parar de ser mau'
fonte
1
Na verdade, existe uma chance de fazê-lo "funcionar", mas não é trivial, propenso a erros e deve ser evitado a todo custo. Para mostrar que na verdade é "possível", considere este script shell onde o pai é Bash: ws=$1; gdb -p $(ps h -o ppid -p $$) -ex "call chdir(\"$wd\")" -ex "call set_working_directory(\"$wd\")" -ex detach -ex q -batch. Executar como braindead-cd-parent /. Você verá que os pwdretornos, o /mesmo acontece ls, etc. se comportam. Mas o prompt ( PS1) ainda permanece inalterado, os olhos das pessoas estão magoados, etc. Portanto, não faça isso, mesmo que seja possível.
Lekensteyn
1
@Lekensteyn Esse é o ptracemétodo que mencionei. Funciona bem em programas que não se importam muito com o diretório atual. Em um shell, muitas coisas ( PWDvariáveis, prompt etc.) vão ficar erradas, e o shell pode travar ou se comportar mal.
Gilles 'SO- stop be evil'
5

Como você mesmo apontou, os scripts de shell são sempre executados em um subshell, o que não pode influenciar seu shell pai.

Você pode, no entanto ...

  • use um alias:
    alias mycd2='cd /a/very/long/path/name'
  • faça com que seu script 1 produza um comando shell válido ...

    #!/bin/bash
    if [ "x$1" = "x2" ]
    then
        echo "cd /a/very/long/path/name"
    fi

    ... e execute sua saída: $(mycd 2)

1: você provavelmente desejará usar uma caseinstrução em vez da ifcondição no exemplo.

n.st
fonte
5
Um alias é aceitável. Um script é o mesmo problema que ele já tem. Esta pergunta grita função shell.
Ricky Beam