Jak wykonywać polecenia w innym folderze bez powtarzania ścieżki folderu?

73

Czy jest jakiś sprytny sposób, aby zrobić kopię i przenieść czynności lub polecenia do kopiowania pliku, bez konieczności zrobić cd, to mvpóźniej, w tym samym folderze?

Na przykład muszę uruchomić następujące czynności:

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

Zauważ, że katalog, do którego przenoszę plik, jest taki sam, ale muszę ponownie podać całą ścieżkę, a czasem robi się to denerwujące. Jestem ciekawy, czy istnieje inny sposób, aby to zrobić bez konieczności ponownego wprowadzania całej ścieżki , ponieważ operacja zostałaby wykonana na tej samej ścieżce.

Valter Silva
źródło
9
Nie mogę uwierzyć, że ma tak wiele pozytywnych opinii. Jest to duplikat unix.stackexchange.com/questions/35782/... i unix.stackexchange.com/questions/66889/...
user13107
13
@ user13107 Istnieje wiele sposobów zadawania pytań, w tym inne sformułowania. A jeśli nie wiesz, że odpowiedź nazywa się „rozwinięciem nawiasu klamrowego”, możesz nie być w stanie jej znaleźć od razu.
slhck
2
@ user13107 są na innej stronie, więc nie są duplikatami
user151019
1
Mark, dzięki, nie znałem tej reguły dotyczącej duplikatów. @slhck Tak. Rozumiem. Byłem po prostu sfrustrowany, ponieważ moje pytanie dotyczące Unix.SE zostało zamknięte jako duplikat, a to stało się tak popularne.
user13107,
3
@ user13107, właśnie to dostajesz za publikowanie na właściwej stronie
Samuel Edwin Ward

Odpowiedzi:

125

Wystarczy użyć rozszerzenia nawiasu klamrowego :

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

Jest to równoważne z pisaniem:

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

Rozwijanie nawiasów pozwala oczywiście podać więcej argumentów. Można nawet podać zakresy do niej, na przykład, aby utworzyć kilka folderów testowych, można uruchomić mkdir test_{a..z}, a wychodząc z Bash 4, można tworzyć sekwencje zero-wyściełane, a także, jak w touch foo{0001..3}, który tworzy foo0001, foo0002i foo0003. Bash Hakerzy Wiki ma artykuł z kilkoma przykładami dla Ciebie.

Jeśli musisz użyć dwóch różnych poleceń, użyj podpowłoki i cdtam najpierw, jak w odpowiedzi @ Ignacio .

slhck
źródło
5
Nie wiedziałem o bracerozszerzeniu, dziękuję!
Valter Silva
Próbowałem i wydaje się, że nie działa: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
5
Czy na pewno używasz Bash, jak w /bin/bash, i nie jesteś w skrypcie, który ma /bin/shw shebang lub innej powłoce, która nie obsługuje rozwijania nawiasów? Jeśli biegniesz set, czy SHELLOPTSzawierasz braceexpand?
slhck
22
Zauważ, że pomiędzy file.txt,i nie powinno być spacji file2.txt.
slhck
9
Możesz go jeszcze skrócić, aby uniknąć literówek w części, która się nie zmienia:mv /folder1/folder2/folder3/file{,-2013}.txt
Jan Fabry
74

Uruchom operację w podpowłoce.

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

Zmiana katalogu roboczego nie zostanie propagowana do powłoki nadrzędnej.

Ignacio Vazquez-Abrams
źródło
11
+1: Podoba mi się ten, bardziej przenośny między pociskami niż sztuczka ekspansji nawiasów klamrowych (która jest zgrabna, ale mniej przenośna)
Olivier Dulac
@Olivier, co sprawia, że ​​uważasz, że rozszerzenie nawiasów klamrowych nie jest przenośne? Którą powłokę masz na myśli, która nie obsługuje?
Alexis
5
@alexis Rozszerzenie Brace nie jest określone przez POSIX, więc nie jest przenośne „zgodnie z projektem”. ash, dash, ksh88Nie mówiąc już stare Bourne powłoki są przykładem powłoki nie wspierającej.
jlliagre
@jlliagre Które ze wspomnianych powłok są w pełni zgodne z POSIX? Oznacza to, że nie mieliby rozszerzenia nawiasu klamrowego, nawet gdyby był to POSIX. ksh88 był przed ratyfikacją POSIX; powinieneś uaktualnić do co najmniej ksh93. Jedynymi dwoma, na których w Linuksie by się przejmowało, są ash i dash, ponieważ są one używane w niektórych małych osadzonych dystrybucjach (busybox, iirc?) I dyskach ratunkowych.
Kaz
2
@Kaz Dbam o przenośność poleceń powłoki i fakt, że są one interaktywne lub nie mają znaczenia. Oczywiście z pewnością możesz się tym nie przejmować, ale zaakceptuj, że ludzie myślą inaczej. Fakt, że zawsze używasz bash lub powłoki obsługującej ekspansję barce, nie oznacza, że ​​tak jest w przypadku wszystkich.
jlliagre
21

Jeśli chcesz sprytnego, oto rozszerzenie historii bash

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

Nie użyłbym tego sam, ponieważ nie mogę zapamiętać. Czasami używam ekwiwalentu vima , ale prawie za każdym razem muszę go szukać.

Glenn Jackman
źródło
11

Możesz ustawić zmienną. Oczywiście ma to efekt uboczny polegający na pozostawieniu zmiennych w pobliżu.

D=/folder1/folder2/folder3; mv $D/file.txt $D/file-2013.txt
sjbotha
źródło
I oczywiście można uniknąć efektu ubocznego pozostawiania zmiennych (zmiennych), umieszczając całą linię poleceń w podpowłoce: (D="/folder1/folder2/folder3"; mv "$D"/file.txt "$D"/file-2013.txt)lub po prostu dodając unsetpolecenie na końcu. (Dodałem cytaty jako „najlepszą praktykę”; jeśli masz w zwyczaju ciągłego używania cytatów, nie będziesz musiał zatrzymywać się i drapać się w głowę, gdy pojawi się nazwa ścieżki zawierająca znaki specjalne.)
Scott
@Scott, jeśli zamierzasz użyć podpowłoki w celu wyeliminowania efektów ubocznych, łatwiej jest zrobić cdniż ustawić zmienną. Nie jest to dużo łatwiejsze, przyznaję.
Izaak Rabinovitch
2

Lubię inne rozwiązania, ale oto inne, zaimplementowane jako skrypt z tablicami 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
źródło
1

Slhck bezpośrednio odpowiada na pytanie w najprostszy możliwy sposób, ale Valter lubi również odpowiedź autopop, więc oto ta, która ma te same linie;

pushd /folder1/folder2/folder3/; mv file.txt file-2013.txt; popd
Izaak Rabinowicz
źródło