2008-10-27 10 views
10

¿Cree que es aceptable cambiar de directorio dentro de scripts Bash o Perl? ¿O debería uno evitar hacer esto a toda costa?¿Cuál es la mejor práctica para cambiar los directorios de trabajo dentro de los scripts?

¿Cuál es la mejor práctica para este problema?

+0

No entiendo la pregunta. ¿Cómo puede alguien decir que su secuencia de comandos hizo un CD a un nuevo directorio? –

+0

Las respuestas actuales se aproximan a esto desde una perspectiva de "es sintaxis válida y no afecta el shell de los padres, por lo que está bien". Veo otra parte de esta pregunta, algo así como "está codificando en estilo de codificación feo de scripts, similar a las líneas excesivamente largas de Python o nombres de variables mal elegidos, algo que se puede hacer pero es una buena práctica para evitar". – dfarrell07

Respuesta

15

El directorio de trabajo actual es local para el shell de ejecución, por lo que no puede afectar al usuario a menos que esté "punteando" (ejecutándolo en el shell actual, en lugar de ejecutarlo normalmente creando un nuevo proceso de shell) guión.

Una forma muy buena de hacer esto es utilizar subcapas, que a menudo hago en alias.

alias build-product1='(cd $working-copy/delivery; mvn package;)' 

El un paréntesis se asegurará de que el comando se ejecuta desde un sub-shell, y por lo tanto no afectará el directorio de trabajo de mi concha. Además, no afectará al último directorio de trabajo, por lo que cd -; funciona como se esperaba.

4

No hago esto a menudo, pero a veces puede ahorrar un poco de dolor de cabeza. Solo asegúrese de que si cambia directorios, siempre cambia de nuevo al directorio desde el que comenzó. De lo contrario, cambiar las rutas del código podría dejar la aplicación en algún lugar que no debería ser.

+0

No en derivadas de Unix, no podría. –

+0

Sí, puede hacerlo si toma "aplicación" como "el mismo ejecutable, pero con funciones diferentes"; simplemente no puede cambiar el proceso principal 'cwd'. – Tanktalus

+0

¿Qué tipo de interpretación de la palabra "aplicación" te llevaría a pensar que? – ephemient

1

Considere también que Unix y Windows tienen una pila de directorios integrada: pushd and popd. Es extremadamente fácil de usar.

25

Al igual que Hugo dijo, no se puede afectar a la función CCW del proceso principal, por lo que no hay problema.

Donde la pregunta es más aplicable es si no controla todo el proceso, como en una subrutina o módulo. En esos casos, usted desea salir de la subrutina en el mismo directorio que ingresó, de lo contrario, la sutil acción a distancia se arrastra y causa errores.

Puede que esto a mano ...

use Cwd; 
sub foo { 
    my $orig_cwd = cwd; 
    chdir "some/dir"; 

    ...do some work... 

    chdir $orig_cwd; 
} 

pero que tiene problemas. Si la subrutina regresa temprano o muere (y la excepción queda atrapada) su código seguirá estando en some/dir. Además, el chdir s puede fallar y debe recordar verificar cada uso. Bleh.

Afortunadamente, hay un par de módulos para hacerlo más fácil. File :: pushd es uno, pero prefiero File::chdir.

use File::chdir; 
sub foo { 
    local $CWD = 'some/dir'; 

    ...do some work... 
} 

Archivo :: chdir hace que el cambio en la asignación de directorios a $CWD. Y puede localizar $CWD para que se restablezca al final de su alcance, no importa qué. También verifica automáticamente si el chdir tiene éxito y arroja una excepción en caso contrario. Algunas veces lo usa en scripts porque es muy conveniente.

+0

Lo tomo File :: chdir no es un módulo básico? Si está tratando de apegarse a los módulos centrales, ¿el método de Hugo es la siguiente mejor opción? – SSilk

+0

@Silver La técnica de Hugo es bastante diferente y más aplicable a cosas como scripts de construcción que ejecutan otros comandos. El mío es aplicable a las partes internas de los programas y las bibliotecas. Ambos intentan aislar por completo el cambio de directorio para que no afecte a nada más. – Schwern

2

Para Perl, tiene el módulo File::pushd de CPAN, que hace que cambiar localmente el directorio de trabajo sea bastante elegante. Citando la sinopsis:

use File::pushd; 

    chdir $ENV{HOME}; 

    # change directory again for a limited scope 
    { 
     my $dir = pushd('/tmp'); 
     # working directory changed to /tmp 
    } 
    # working directory has reverted to $ENV{HOME} 

    # tempd() is equivalent to pushd(File::Temp::tempdir) 
    { 
     my $dir = tempd(); 
    } 

    # object stringifies naturally as an absolute path 
    { 
    my $dir = pushd('/tmp'); 
    my $filename = File::Spec->catfile($dir, "somefile.txt"); 
    # gives /tmp/somefile.txt 
    } 
3

Encabezaré los comentarios de Schwern y Hugo anteriores. Tenga en cuenta la precaución de Schwern sobre volver al directorio original en caso de una salida inesperada. Proporcionó el código de Perl apropiado para manejar eso. Señalaré el comando de captura shell (Bash, Korn, Bourne).

trampa "cd $ saved_dir" 0

volverá a saved_dir en la salida subnivel (si está .'ing el archivo).

micrófono

0

¿Es del todo posible para tratar de utilizar rutas cuantificados totalmente, y no hacer ninguna suposición sobre qué directorio Actualmente se encuentra en? p.ej.

use FileHandle; 
use FindBin qw($Bin); 
# ... 
my $file = new FileHandle("< $Bin/somefile"); 

en lugar de

use FileHandle; 
# ... 
my $file = new FileHandle("< somefile"); 

Esto probablemente será más fácil en el largo plazo, ya que no tiene que preocuparse de cosas extrañas que suceden (la secuencia de comandos matando o muriendo antes de que pudiera poner la el directorio de trabajo actual vuelve a donde estaba), y es posiblemente más portátil.

Cuestiones relacionadas