¿Cómo ejecuto comandos en otra carpeta, sin repetir la ruta de la carpeta?

73

¿Hay una manera inteligente de copiar y mover operaciones o un comando para duplicar un archivo, sin tener que hacer un cd, luego mv, en la misma carpeta?

Por ejemplo, tengo que ejecutar lo siguiente:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

Tenga en cuenta que el directorio donde estoy moviendo el archivo es el mismo, pero tengo que volver a poner toda la ruta y, a veces, se vuelve molesto. Tengo curiosidad por saber si hay otra forma de hacerlo sin tener que poner todo el camino nuevamente , porque la operación se haría en el mismo camino.

Valter Silva
fuente
9
No puedo creer que esto tenga tantos votos positivos. Es un duplicado unix.stackexchange.com/questions/35782/… y unix.stackexchange.com/questions/66889/…
user13107
13
@ user13107 Hay muchas formas de hacer una pregunta, incluidas diferentes palabras. Y si no sabe que la respuesta se llama "expansión de llaves", es posible que no pueda encontrarla de inmediato.
slhck
2
@ user13107 están en un sitio diferente, así que no están duplicados
user151019
1
Mark, gracias, no conocía esa regla sobre los duplicados. @slhck Sí. Entiendo. Estaba frustrado porque mi pregunta sobre Unix.SE se cerró como duplicado y esta se hizo muy popular.
user13107
3
@ user13107, eso es lo que obtienes por publicar en el sitio correcto
Samuel Edwin Ward,

Respuestas:

125

Simplemente use la expansión de llaves :

mv /folder1/folder2/folder3/{file.txt,file-2013.txt}

Esto es equivalente a escribir:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

La expansión de llaves le permite proporcionar más argumentos, por supuesto. Incluso puede pasar rangos a ella, por ejemplo, para crear un par de carpetas de prueba, puede ejecutar mkdir test_{a..z}, y comenzando con Bash 4, puede crear secuencias con relleno de ceros, así, como en touch foo{0001..3}, lo que crea foo0001, foo0002y foo0003. El golpe de hackers Wiki tiene un artículo con un par de ejemplos para usted.

Si tiene que usar dos comandos diferentes, use una subshell y cdallí primero, como en la respuesta de @ Ignacio .

slhck
fuente
55
No sabía sobre la braceexpansión, ¡gracias!
Valter Silva
Lo intenté y parece que no funciona:meniac ~: mv /tmp/f1/f2/f3/f4/f5/f6/{file.txt, file2.txt} mv: cannot stat ``/tmp/f1/f2/f3/f4/f5/f6/{file.txt,': No such file or directory
Valter Silva
55
¿Estás seguro de que estás usando Bash, como en /bin/bash, y no estás en un script que tiene /bin/shen el shebang o algún otro shell que no admite la expansión de llaves? Si corres set, ¿tu SHELLOPTScontenido braceexpand?
slhck
22
Tenga en cuenta que no debe haber espacio entre file.txt,y file2.txt.
slhck
9
Puede hacerlo aún más corto, para evitar errores tipográficos en la parte que no cambia:mv /folder1/folder2/folder3/file{,-2013}.txt
Jan Fabry
74

Ejecute la operación en una subshell.

( cd /folder1/folder2/folder3 && mv file.txt file-2013.txt )

El cambio del directorio de trabajo no se propagará al shell principal.

Ignacio Vazquez-Abrams
fuente
11
+1: Me gusta ese, más portátil a través de las conchas que el truco de expansión de llaves (que es ordenado, pero menos portátil)
Olivier Dulac
@ Olivier, ¿qué te hace pensar que la expansión de llaves no es portátil? ¿Qué shell tienes en mente que no lo admite?
alexis
55
La expansión @alexis Brace no está especificada por POSIX, por lo que no es portátil "por diseño". ash, dash, ksh88Por no hablar de la vieja cáscara de bourne son ejemplo de conchas que no lo soporte.
jlliagre
@jlliagre ¿Cuál de los shells que mencionaste son totalmente compatibles con POSIX? Eso significa que no tendrían expansión de llaves incluso si fuera POSIX. ksh88 fue antes de que POSIX fuera ratificado; debe actualizar al menos a ksh93. Las dos únicas personas a las que les importaría Linux son ash y dash, ya que se usan en algunas pequeñas distribuciones integradas (busybox, iirc?) Y discos de rescate.
Kaz
2
@Kaz Me importa la portabilidad de los comandos de shell y el hecho de que sean interactivos o no, no importa. Por supuesto, usted es libre de no preocuparse por esto, pero acepte que la gente piense lo contrario. El hecho de que siempre use bash o un shell que admita la expansión de barce no significa que sea el caso de todos.
jlliagre
21

Si quieres inteligente, aquí está la expansión de la historia bash

mv /folder1/folder2/folder3/file.txt !#:1:h/file-2013.txt

No usaría esto yo mismo, ya que me resulta imposible memorizar. De vez en cuando uso el equivalente vim , pero tengo que buscarlo casi siempre.

Glenn Jackman
fuente
11

Puedes establecer una variable. Por supuesto, esto tiene el efecto secundario de dejar las variables.

D=/folder1/folder2/folder3; mv $D/file.txt $D/file-2013.txt
sjbotha
fuente
Y, por supuesto, puede evitar el efecto secundario de dejar las variables al poner toda la línea de comando en un subshell: (D="/folder1/folder2/folder3"; mv "$D"/file.txt "$D"/file-2013.txt)o simplemente agregando un unsetcomando al final. (Agregué citas como una "mejor práctica"; si tiene la costumbre de usar siempre citas, no tendrá que detenerse y rascarse la cabeza cuando aparezca un nombre de ruta que contenga caracteres especiales).
Scott,
@Scott si vas a usar una subshell para eliminar los efectos secundarios, es más fácil hacer una cdque establecer una variable. No mucho más fácil, lo admito.
Isaac Rabinovitch
2

Me gustan las otras soluciones, pero aquí hay otra, implementada como un script con matrices bash, pushd, popd:

#!/bin/bash
set -e
# from http://stackoverflow.com/a/246128/178651
script_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# paths relative to the script
relative_paths=( \
path1 \
path2 \
path3 \
path4
)

for relative_path in "${relative_paths[@]}"
do
  pushd "$script_path/$relative_path" > /dev/null 2>&1
  pwd
  mv filename1 filename2
  # could do other stuff in this directory...
  popd > /dev/null 2>&1
done

pushd "$script_path" > /dev/null 2>&1
# could do other stuff in same directory as script...
popd > /dev/null 2>&1
Gary S. Weaver
fuente
1

Slhck responde directamente a la pregunta de la manera más simple posible, pero a Valter también le gusta la respuesta de autopop, así que aquí hay una que sigue la misma línea;

pushd /folder1/folder2/folder3/; mv file.txt file-2013.txt; popd
Isaac Rabinovitch
fuente