¿Cómo ejecutar un comando con un directorio como argumento, luego cd al mismo? Me sale "no hay tal archivo o directorio"

15

Me gustaría construir una función corta para hacer lo siguiente. Digamos que muevo el archivo 'file.tex' a mi directorio de documentos:

mv file.tex ~/Documents

Entonces, me gustaría ir cda ese directorio:

cd ~/Documents

Me gustaría generalizar esto a cualquier directorio, para poder hacer esto:

mv file.tex ~/Documents
follow

y haga que el followcomando lea el destino del comando anterior, luego ejecútelo en consecuencia. Para un directorio simple, esto no ahorra mucho tiempo, pero cuando se trabaja con directorios anidados, sería tremendo poder usar

mv file.tex ~/Documents/folder1/subfolder1
follow

Pensé que sería relativamente simple y que podría hacer algo como esto:

follow()
{
    place=`history 2 | sed -n '1p;1q' | rev | cut -d ' ' -f1 | rev`
    cd $place
}

Pero esto no parece funcionar. Si hago eco $place, obtengo la cadena deseada (la estoy probando ~/Documents), pero el último comando devuelve

No such file or directory

El directorio ciertamente existe. Estoy perdido ¿Podrías ayudarme?

Fuego
fuente
Me gustaría señalar que si no le importa mantener file.texla ubicación original, los enlaces simbólicos son una muy buena alternativa, ya que solo tiene que vincular una vez, y siempre apuntará a la última versión.
Kroltan
55
Forma más fácil: escriba cd alt + .para sustituir el último token del comando anterior. Repita para ir más atrás en la historia de los tokens finales. (Digo token no arg, porque foo &toma &como token final). Puedes usar un argumento numérico (con escape-3 alt +. Por ejemplo).
Peter Cordes
ver también combo de cd mkdir
Christopher Bottoms

Respuestas:

18

En lugar de definir una función, puede usar la variable $_, que se expande al último argumento del comando anterior mediante bash. Entonces usa:

cd "$_"

después del mvcomando

También puedes usar la expansión del historial:

cd !:$

Si debe usar una función:

follow () { cd "$_" ;}

$ follow () { cd "$_" ;}
$ mv foo.sh 'foo bar'
$ follow 
foo bar$ 

NB: Esta respuesta está dirigida al formato exacto de argumentos de línea de comando que ha utilizado, ya que estamos tratando con parámetros posicionales. Para otros formatos mv -t foo bar.txt, por ejemplo , es necesario incorporar comprobaciones específicas de antemano, entonces sería apropiado un contenedor.

heemayl
fuente
Su expansión de historial (cd!: $) Funciona perfectamente. Gracias. Sin embargo, el otro (cd "$ _") no: mv file.tex ~ / Downloads / cd "$ _" bash: cd: __bp_preexec_invoke_exec: No existe tal archivo o directorio. Con mucho gusto aceptaré su respuesta como totalmente correcta, y gracias.
Fuego
Siempre he escrito (un tanto derrochador) cd !$o cd $(dirname !$). ¡No sabía sobre la $_variable!
Kalvin Lee
Ahora, ¿qué pasa si lo hago en mv -t ~/Documents file.texlugar de mv file.tex ~/Documents? En pocas palabras, no estoy seguro de que esto se mvpueda resolver en el caso general ... una función envolvente o que los reimplementos podrían ser mejores ...
un CVn
@ MichaelKjörling no funcionará simplemente ... este ejemplo es solo para cubrir el caso que OP tiene, no los casos de borde (o todos) ...
heemayl
No necesitas el colon; !$es equivalente !:$y más rápido de escribir.
Comodín
14

Con las combinaciones de teclas bash estándar, la combinación Alt.copiará el último argumento de la línea de comando anterior en el actual. Entonces, escribiendo

$ mv foo ~/some/long/path/
$ cd <Alt><.>

cedería

$ mv foo ~/some/long/path/
$ cd ~/some/long/path/

y sería incluso menos tipeado que la palabra follow.

Para mayor conveniencia, la repetición de la Alt.combinación buscará los últimos argumentos de todas las líneas de comando anteriores.

Anexo: El nombre del comando bash correspondiente a esta combinación de teclas es yank-last-argo insert-last-argument. Se puede encontrar en la página de manual de bash en "Comandos para manipular el historial" o en el Manual de referencia de Bash más exhaustivo ).

Dubu
fuente
1
Eso es inteligente. ¡Gracias! No tenía idea de que esto existía.
Fuego
@Fire Agregué referencias para esos comandos, para que pueda encontrar muchas más combinaciones de teclas interesantes (e inmediatamente las olvide de nuevo, como siempre hago).
Dubu
1
También se puede utilizar <esc>a continuación .para obtener el mismo resultado que <alt>+., esto, tiene utilidad cuando se tiene BloqMayus reasigna a escapar :)
gnur
1
@gnur vi (m) usuario, supongo. ;-)
Dubu
6

Es casi seguro que se encuentra con el problema de que la expansión de tilde tiene lugar antes de la expansión de parámetros, lo que puede explicarse con un breve ejemplo:

$ cd ~kaz
kaz $ var='~kaz'
kaz $ echo $var
~kaz
kaz $ cd $kaz
bash: cd: ~kaz: No such file or directory

Esto se puede abordar con eval. De todos modos, vas a necesitar eval, porque estás extrayendo comandos del historial y pueden contener expansiones arbitrarias, como:

$ mv file.tex ~/Documents/$(compute_folder_name foo-param)/subfolder1
$ follow

(Hay problemas, como que la reexpansión de estos valores puede que ya no coincida con la expansión original que se produjo. Supongamos que compute_folder_namees una función que incrementa alguna variable global).

Kaz
fuente
44
No es necesario eval. (Nunca.) Pero es bueno detectar los problemas de la secuencia de expansión. Si menciona la mayor conveniencia de la expansión de la historia para usar evalaquí, esta será la mejor respuesta en mi opinión; ninguno de los otros explica realmente por qué la solución del Cartel original no funcionó.
Comodín