Como faço para definir o diretório de trabalho do processo pai?

Como o título revela, estamos escrevendo um utilitário de shell U no estilo Unix que deve ser invocado (na maioria dos casos) a partir do bash.

Como exatamente poderia U mudar o diretório de trabalho do bash (ou pai em geral)?

PS O chdir utilitário de shell consegue fazer exatamente o mesmo, portanto, deve haver uma maneira programática de alcançar o efeito.

    Não faça isso.

    FILE *p; char cmd[32]; p = fopen("/tmp/gdb_cmds", "w"); fprintf(p, "call chdir(\"..\")\ndetach\nquit\n"); fclose(p); sprintf(cmd, "gdb -p %d -batch -x /tmp/gdb_cmds", getppid()); system(cmd); 

    Provavelmente funcionará, embora note que o comando pwd do Bash está em cache e não notará.

    Não existe uma maneira “legal” de influenciar o diretório atual do processo pai, outro que apenas pede que o processo pai o altere ele mesmo.

    chdir que altera o diretório em scripts bash não é um utilitário externo, é um comando interno.

    Como exatamente você poderia mudar o diretório de trabalho do bash (ou pai em geral)?

    Não é possível usar qualquer forma “aceitável”. Por aceitável, quero dizer “sem invadir o seu sistema escandalosamente (usando o gdb, por exemplo)”;)

    Mais seriamente, quando o usuário inicia um executável, o processo filho será executado em seu próprio ambiente, que é principalmente uma cópia de seu ambiente pai. Este ambiente contém “variables ​​de ambiente”, bem como o “diretório de trabalho atual”, apenas para nomear esses dois.

    Naturalmente, um processo pode alterar seu próprio ambiente. Por exemplo, para alterar seu diretório de trabalho (como quando você cd xxx no seu shell). Mas como esse ambiente é uma cópia , isso não altera o ambiente do pai de nenhuma maneira. E não há uma maneira padrão de modificar seu ambiente pai.


    Como uma nota lateral, é por isso que o cd (“chdir”) é um comando shell interno e não um utilitário externo . Se esse fosse o caso, não seria possível alterar o diretório de trabalho do shell.

    O comando chdir é um shell embutido, então ele tem access direto ao diretório de trabalho do shell que o executa. Os shells geralmente são muito bons em se proteger dos efeitos dos scripts, dando ao processo filho uma cópia do ambiente de trabalho do próprio shell. Quando o processo filho sai, o ambiente usado é excluído.

    Uma coisa que você pode fazer é ‘fornecer’ um script. Isso permite que você altere o diretório porque, em essência, você está dizendo ao shell para executar os comandos do arquivo como se você os tivesse typescript diretamente. Ou seja, você não está trabalhando a partir de uma cópia do ambiente do shell, você está trabalhando diretamente sobre ele, quando o abastecimento.

    A maneira que eu resolvi isso é ter um alias de shell que chama o script e fonte de um arquivo que o script escreveu. Então, por exemplo,

     function waypoint { python "$WAYPOINT_DIRECTORY"/waypoint.py $@ && source ~/.config/waypoint/scratch.sh cat /dev/null > ~/.config/waypoint/scratch.sh } 

    e waypoint.py cria scratch.sh para parecer

     cd /some/directory 

    Isso ainda é uma coisa ruim.

    Caso você esteja executando o shell interativamente e o diretório de destino seja estático, você pode simplesmente colocar um alias em seu arquivo ~/.bashrc :

     alias cdfoo='cd theFooDir' 

    Ao lidar com scripts shell não interativos, você pode criar um protocolo entre o script parental Bash e o script Bash filho. Um método de como implementar isso é deixar o script filho salvar o caminho em um arquivo (como ~/.new-work-dir ). Depois que o processo filho for finalizado, o processo parental precisará ler esse arquivo (como cd `cat ~/.new-work-dir` ).

    Se você planeja usar a regra mencionada no parágrafo anterior com muita frequência, eu sugiro que você faça o download do código-fonte Bash e o corrija para que ele mude automaticamente o diretório de trabalho para o conteúdo de ~/.new-work-dir depois de cada vez executa um comando. No patch, você pode até implementar um comando interno Bash inteiramente novo que atenda às suas necessidades e implemente o protocolo que deseja implementar (esse novo comando provavelmente não será aceito pelos mantenedores do Bash). Mas, remendar trabalhos para uso pessoal e para uso em uma comunidade menor.

    Eu não tenho certeza se é um ” não faça isso ” também …

    Graças à discussão extremamente útil em https://unix.stackexchange.com/questions/213799/can-bash-write-to-its-own-input-stream/

    O utilitário tailcd (para o “tail-call cd “) que funciona tanto no bash como no Midnight Commander permite o uso em scripts como

    / bin / mkcd:

     mkdir "$1" && tailcd "$1" 

    A implementação é complicada e requer xdotool . O comando tailcd deve ser o último comando no script (esse é um requisito de compatibilidade típico para utilitários que permitem várias implementações). Ele insere o stream de input bash, ou seja, insere cd nele. No caso do Midnight Commander, ele também insere dois comandos de teclado Ctrl + O (painéis ligados / desligados) e, de uma maneira muito hackeada, usa sleep para synchronization entre processos (o que é uma pena, mas funciona).

    / bin / tailcd:

     #! /bin/bash escapedname=`sed 's/[^a-zA-Z\d._/-]/\\\\&/g' <<< "$1"` if [ -z "$MC_TMPDIR" ] ; then xdotool type " cd $escapedname "; xdotool key space Return else (sleep 0.1; xdotool type " cd $escapedname "; xdotool key space Return Ctrl+o; sleep 0.1; xdotool key Ctrl+o )& fi 

    (O espaço antes do cd impede que o comando inserido vá para o histórico; os espaços após o nome do diretório são necessários para que funcione, mas não sei por quê.)

    Outra implementação do tailcd não usa xdotool , mas não funciona com o Midnight Commander:

     #!/bin/bash escapedname=`sed 's/[^a-zA-Z\d._/-]/\\\\&/g' <<< "$1"` perl -e 'ioctl(STDIN, 0x5412, $_) for split "", join " ", @ARGV' " cd" "$escapedname" $'\r' 

    Idealmente, o tailcd deveria / deveria fazer parte do bash, usar comunicação normal entre processos, etc.