¿Ejecutar un comando específico en un directorio dado sin cd'ing a él?

42

¿Hay alguna manera de ejecutar un comando en un directorio diferente sin tener cdque hacerlo? Sé que podría simplemente entrar cdy cdsalir, pero solo estoy interesado en las posibilidades de renunciar a los pasos adicionales :)

Naftuli Kay
fuente
Es bastante trivial para hacer un script que hace esto: echo "#!/bin/bash; cd $1; exec $2" > /usr/local/bin/execindirectory; chmod +x /usr/local/bin/execindirectory. Es posible que deba esforzarse un poco más si desea que realmente sea compatible con las "etiquetas" de opciones, tales como -dy otras cosas.
LawrenceC
Como estados desconocidos por el usuario en una respuesta, todos los ejemplos que ha dado aquí y en los comentarios se abordan mejor con otras soluciones, por lo que no está claro si realmente hay un problema que debe resolverse aquí. ¿Puedes encontrar un mejor ejemplo?
Caleb

Respuestas:

55

No sé si esto cuenta, pero puedes hacer una subshell:

$ (cd /var/log && cp -- *.log ~/Desktop)

El directorio solo se cambia para esa subshell, por lo que evitará el trabajo de necesitar cd -después.

Michael Mrozek
fuente
2
Eso es lo que suelo hacer.
Adam Byrtek
Agradable, me había olvidado por completo de las subcapas, muy útil en este caso.
Naftuli Kay
44
Para evitar el caos potencial, sub a cabo el punto y coma con dos símbolos de unión: $ (cd /var/log && cp *.log ~/Desktop). De esa manera, si el directorio no existe, no se ejecutan más comandos.
Naftuli Kay
Nota para cualquier otra persona tan ingenua como yo: $ al inicio no es parte del comando, solo todo lo que sigue.
Maltronic
14

Algunos programas tienen opciones con las que puede decirles que se hagan chdir (2) ellos mismos (por ejemplo, GNU tar 's -C/ --directory).

Sin embargo, fuera de tales programas, algo tendrá que cambiar . Podrías escribir y usar algún tipo de programa "binario" compilado en lugar de que el shell lo haga, pero probablemente no produciría muchos beneficios.

En un comentario en otra respuesta, usted dio un ejemplo:

execindirectory -d /var/log "cp *.log ~/Desktop"

Como el *.logpatrón se expande por el propio shell (no cp ), algo tendrá que cambiar al directorio antes de que un shell evalúe su comando.

Si solo está interesado en evitar tener que "devolver el CD", puede usar una subshell para aislar el efecto del CD de su instancia de shell de trabajo.

(cd /path/to/dir && some command)

Puede empaquetar esto en una función de shell. (Eliminé la -dopción de su uso de ejemplo, ya que este comando no tiene mucho sentido si el directorio es realmente opcional).

runindir() { (cd "$1" && shift && eval "$@"); }

runindir /var/log 'cp *.log ~/Desktop'  # your example
runindir /var/log cp \*.log \~/Desktop  # eval takes multiple args

runindir /var/log cp \*.log ~/Desktop   # it is okay to expand tilde first
Chris Johnsen
fuente
2
Me gusta esta solución, excepto que personalmente usaría pushd / popd
NJ
10

No para socavar el valor de las respuestas dadas por otras personas, pero creo que lo que quieres es esto:

(cd /path/to && ./executable [ARGS])

Tenga en cuenta los parens para invocar cden un sub-shell.

alex
fuente
No lo creo. Según tengo entendido, él quiere terminar en el directorio inicial.
Adam Byrtek
Oh, me olvidé por completo de envolver eso en un sub-shell. Corregí mi respuesta, gracias.
alex
4

Aquí hay algo que debería permitirle cdregresar a donde estaba (usando Bash), ya que no olvidarse de hacerlo parece ser el propósito de la pregunta:

# Save where you are and cd to other dir
pushd /path/to/dir/that/needs/to/be/current/dir

run-your-command

# Get back where you were at the beginning.
popd

(EDITAR: versión ligeramente más corta, gracias a @ Random832)

Bruno
fuente
1
podrías simplemente pushd other-dir, en lugar depushd .; cd other-dir
Random832
@ Random832, buen punto!
Bruno
2

Tristemente, tu ejemplo:

execindirectory -d /var/log "cp *.log ~/Desktop"

no necesita un cambio en el directorio, porque

cp /var/log/*.log ~/Desktop

haría lo mismo ¿No puedes acercarte a tu verdadero problema? Porque podríamos conocer una mejor solución para eso también.

Una forma complicada de resolver su problema, que está muy lejos de la elegancia de la solución de Michaels, es el uso de find, que tiene un interruptor '-execdir' que se realiza en el directorio, donde se encuentra un archivo. Mal adoptado a su ejemplo:

find /var/log -maxdepth 1 -type f -name "*.log" -execdir echo cp {} ~/Desktop ";"

Quizás sea útil para tu problema real. -okdir en lugar de -execdir le pedirá que confirme cada invocación.

-okdir y -execdir pueden necesitar la instalación de gnu-find, que generalmente se usa en Linux.

usuario desconocido
fuente
1

¿Qué tal ./your/path/command.sh?

bdictator
fuente
No, en realidad quería decir algo como lo siguiente: execindirectory -d /var/log "cp *.log ~/Desktop".
Naftuli Kay
Soy perfectamente consciente de que esto no es estrictamente necesario, por cierto, solo estoy interesado en si realmente se puede hacer.
Naftuli Kay