¿Es posible cambiar el directorio de trabajo del shell principal mediante programación?

8

Quiero escribir un código que me permita cambiar a algunos directorios a los que suelo ir. Digamos que este programa es mycdy /a/very/long/path/namees el directorio al que quiero ir.

Así que simplemente puedo escribir en mycd 2lugar de cd /a/very/long/path/name. Aquí supongo que mycdsabe se 2refiere a eso /a/very/long/path/name. También puede haber mycd 1, mycd 3, ... etc.

El problema es que tengo que escribir mycdcomo un script de shell y escribir . mycd 2para hacer lo que deseo porque, de lo contrario, el script simplemente se ejecuta en un script secundario que no cambia nada sobre el shell primario que realmente me interesa.

Mi pregunta es:

  • ¿Puedo hacerlo sin usar source? porque se . mycdsupone que mycdtiene que ser un script de shell y esto también podría introducir algunas funciones que no quiero.

  • ¿Puedo implementarlo en otros lenguajes de programación?

Javran
fuente

Respuestas:

23

hacer mycduna función para que el cdcomando se ejecute en su shell actual. Guárdelo en su archivo ~ / .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
fuente
Gracias, no he pensado en usar funciones, y esto simplemente permite todo: ahora puedo dejar mycdpasar $@cualquier programa que me guste.
Javran
Asegúrese de citar "$@"para que cualquier argumento que contenga espacios en blanco se maneje correctamente.
Glenn Jackman
9

No puede cambiar el directorio actual de un shell desde otro proceso. Solo el proceso en sí puede cambiar su propio directorio actual. Esto también es válido para algunas otras características, como las variables de entorno y los descriptores de archivo.

En realidad, es posible afectar el directorio actual de otro proceso al hacer que ejecute una chdirllamada del sistema a través de la ptracellamada del sistema, que es lo que permite que los depuradores funcionen. Sin embargo, si el proceso mantiene algunas estructuras de datos internas que tienen que ser consistentes con el directorio actual actual, es probable que el programa se bloquee. Para un shell, este enfoque no tiene oportunidad de funcionar.

Necesita organizar su código para que lo ejecute el propio shell. La forma normal de proceder sería convertirlo en una función de shell y almacenarlo en su ~/.bashrc. Si esto no es posible, por ejemplo, porque es un código que desea distribuir, escriba un archivo fuente de shell que contenga la definición de la función y diga a las personas que hagan que su shell interactivo lea su archivo con el .comando .

Gilles 'SO- deja de ser malvado'
fuente
1
En realidad, existe la posibilidad de hacerlo "funcionar", pero no es trivial, es propenso a errores y debe evitarse a toda costa. Para demostrar que en realidad es "posible", tenga en cuenta esta secuencia de comandos shell en el que el padre es 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. Ejecutar como braindead-cd-parent /. Verá que pwdregresa /y también lo hace ls, etc. comportarse. Pero el prompt ( PS1) aún no ha cambiado, los ojos de las personas están lastimados, etc. Por lo tanto, no haga esto incluso si es posible.
Lekensteyn
1
@Lekensteyn Ese es el ptracemétodo que menciono. Funciona bien en programas que no se preocupan mucho por su directorio actual. En un shell, muchas cosas ( PWDvariables, avisos, etc.) se volverán incorrectas, y el shell puede bloquearse o comportarse mal.
Gilles 'SO- deja de ser malvado'
5

Como señaló usted mismo, los scripts de shell siempre se ejecutan en un subshell, que no puede influir en su shell principal.

Sin embargo, puedes ...

  • usa un alias:
    alias mycd2='cd /a/very/long/path/name'
  • haga que su script 1 envíe un comando de shell válido

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

    ... y ejecuta su salida: $(mycd 2)

1: Probablemente quiera usar una casedeclaración en lugar de la ifcondición en el ejemplo.

n.st
fuente
55
Un alias es pasable. Un guión es el mismo problema que ya tiene. Esta pregunta grita la función de shell.
Ricky Beam