Plik mv systemu Linux o długiej nazwie

19

W Linuksie czasami zmieniam nazwy plików w ten sposób:

mv dir1/dir2/dir3/file.txt  dir1/dir2/dir3/file.txt.old

Zauważ, że chcę po prostu zmienić nazwę pliku, a nie przenieść go do innego katalogu.

Czy istnieje polecenie, które pozwoliłoby mi wykonać skróconą wersję tego polecenia? Mam na myśli coś takiego:

mv dir1/dir2/dir3/file.txt  file.txt.old

a może nawet coś takiego (aby po prostu dołączyć do nazwy):

mv dir1/dir2/dir3/file.txt  {}.old

Moim celem nie jest ponowne podawanie pełnej ścieżki.

Wiem, że te „przykłady”, które napisałem, nie działają, ale to tylko pomysł na to, co chcę osiągnąć.

Nie chcę wpuszczać cd do katalogu.

santiago arizti
źródło
8
Dlaczego nie przejdziesz do katalogu? Jest szybki i rozwiązuje twój problem.
Michael Hampton
Mam do czynienia z wieloma podkatalogami z tej samej lokalizacji, jest wolniej, jeśli muszę wracać do tego rodzica za każdym razem
santiago arizti
3
Nikt nie powiedział, że musisz zmienić katalog na inny, tylko ten, którego chcesz.
Michael Hampton
Zauważ, że (cd dir1/dir2/dir3 && exec mv file.txt{,.old})ma efektywnie taką samą wydajność jak kod bez podprocesu, ponieważ execunika fork()ingerencji podczas zewnętrznego wywoływania polecenia, więc masz dokładnie jedno rozwidlenie.
Charles Duffy,

Odpowiedzi:

45

dla pojedynczego pliku spróbuj

mv dir1/dir2/dir3/file.{txt,txt.old}

gdzie X{a,b}konstrukcja rozwija się Xa Xb, możesz uzyskać podgląd za pomocą

echo dir1/dir2/dir3/file.{txt,txt.old}

aby sprawdzić, czy pasuje do twoich potrzeb.

Uwaga:

  1. to dla wielu plików

    mv dir1/dir2/dir3/file{1,2,3}.{txt,txt.old}
    

jest mało prawdopodobne, aby rozwinąć się do tego, czego chcesz. (rozwinie się to do pliku file.txt plik1.txt.old plik2.txt ...)

  1. {txt,txt.old}można skrócić do {,.old}jak w komentarzu

  2. jeśli nazwa katalogu jest jednoznaczna, można użyć znaku zastępczego.

    mv *1/*2/d*/*.{,old}
    

do użytku z wieloma plikami rename

rename -n s/txt/old.txt/ dir1/dir2/dir3/file*.txt 

upuść, -naby mieć skuteczną zmianę nazwy.

Archemar
źródło
1
Fajnie, nie znałem tego sposobu ekspansji! dziękuję
santiago arizti
14
Byłoby mv dir1/dir2/dir3/file.txt{,.old}również nie działa, a nawet być krótszy?
Josh
3
@Josh Tak, działa idealnie i wymaga mniejszej liczby naciśnięć klawiszy. Używam tego konstruktu bardzo regularnie.
rlf
2
to zabawne, jak możesz używać Linuksa przez lata i ciągle znajdować nowe triki
Santiago Arizona
Sądzę, że wszystkie te „sztuczki” byłyby bardziej oczywiste, gdybym odbył jakieś formalne szkolenie w języku bash, ale po prostu uczyłem się wystarczająco, aby się dogadać.
Santiago arizti
6

Polecenie renamezmienia nazwy wszystkich dopasowanych plików. Jego głównym celem jest zmiana nazwy wielu plików, ale jeśli wyrażenie Perla pasuje tylko do jednego pliku, wówczas zmieni nazwę tylko tego jednego pliku. Aby uzyskać szczegółowe informacje i distro składni konkretnego proszę przeczytać stronę man: man rename.

Przykładowe użycie: zmień nazwę „/path/file.txt” na „/path/file.txt.old”:

rename 's/file.txt/file.txt.old/g' /path/file.txt

Krótsza notacja (dzięki shalomb):

rename 's/$/.old/' /path/file.txt
rename '$_.=".old"' /path/file.txt

Do użytku na sucho rename -n.

Więcej przykładów i szczegółów można znaleźć na https://thepcspy.com/read/bulk-rename-files-in-ubuntu/

fabiański
źródło
spoko, wiedziałem o poleceniu zmiany nazwy, po prostu nigdy nie wiedziałem, co może zrobić, dziękuję!
Santiago arizti
6
Niestety różne dystrybucje Linuksa mają różne renamepolecenia o zupełnie innym zachowaniu.
kasperd
1
W przypadku tego konkretnego zadania zmiany nazwy poprzez dołączenie .olddo nazwy pliku, prawdopodobnie wygodniej jest zrobić rename 's/$/.old/' /path/to/file.txtlubrename '$_.=".old"' /path/to/file.txt
shalomb
@Fabian - Nie robiłem nic, tylko dążyłem do „najkrótszej ręki” dla tego, co wydaje się być często używanym idiomem, którego szuka OP :)
shalomb
4

W przypadku jednorazowego przypadku, jeśli nie chcę zmieniać mojego bieżącego katalogu, mogę po prostu użyć podpowłoki:

(cd dir1/dir2/dir3/ && mv file.txt file.txt.old)

Ponieważ cdznajdujesz się w podpowłoce, nie zmieniłeś katalogu w swojej rzeczywistej powłoce

Adam
źródło
4
Szybszy i bezpieczniejszy w użyciu && exec mv- w ten sposób nie próbujesz zmienić nazwy, jeśli się cdnie powiedzie, i execzużywa podpowłokę, unikając w ten sposób obniżenia wydajności.
Charles Duffy
Zgadzam się z && Przypadkiem jednorazowym, jak powiedziałem, nie martwiłbym się kosztem podpowłoki (bądź prosty: łatwiej jest pamiętać, jak to zrobić, ważniejsze jest IMO)
Adam
Twierdzę, że jeśli zamierzasz zapamiętać tylko jeden sposób, zapamiętanie efektywnego sposobu pomaga upewnić się, że nie wybierzesz nieefektywnej trasy w przypadkach, gdy ma to znaczenie.
Charles Duffy
4

Podoba mi się rozwiązanie @ archemar polegające na użyciu rozszerzenia {}, ponieważ możesz go użyć, gdy już uruchomiłeś linię poleceń. Oto kilka innych możliwości kompletności:

F="dir1/dir2/dir3/file.txt" ; mv "$F" "$F.old"

(cudzysłowy są konieczne tylko wtedy, gdy w nazwie masz spacje lub inne znaki dzielące słowa)

mymv() {
    mv "$1/$2" "$1/$3"
}

mymv dir1/dir2/dir3 file.txt file.txt.old
mymv dir5/dir6/dir7 file.txt file.txt.old

Uwagi:

  • To jest składnia bash, możesz używać innej powłoki
  • mymv może być dowolnym rozsądnym ciągiem, użyłem mymv do „mojego ruchu”.
  • Definicję funkcji można umieścić w pliku .bash_profile

Inny:

cd dir1/dir2/dir3 ; mv file.txt file.txt.old ; cd -

ale

(cd dir1/dir2/dir3/ && exec mv file.txt file.txt.old)

(od @Adam i @CharlesDuffy) jest prawdopodobnie lepszy w przypadku awarii płyty CD.

Law29
źródło
1
Nie używaj mmv, istnieje już program o takiej nazwie.
glglgl
1
@glglgl Gotowe :)
Law29
2

Jeśli chcesz wejść do podkatalogu w celu skrócenia mvpolecenia, ale chcesz później wrócić do bieżącego katalogu, możesz to zrobić na dwa sposoby. Jednym z nich jest umieszczenie cdiw mvpodpowłoce (jak już zasugerowano).

Drugim jest używanie pushdi popdzmiana katalogów:

pushd dir1/dir2/dir3/; mv file.txt file.txt.old; popd

pushdKomenda jest niczym cd, oprócz tego, że najpierw wypycha nazwę bieżącego katalogu na stosie. popdusuwa górną nazwę ze stosu i przechodzi do tego katalogu.

AndyB
źródło
pushdi popdsą rozszerzeniami przeznaczonymi do użytku interaktywnego - POSIX wyraźnie je podaje jako „wyniki nie są określone”, a powłoka zbudowana do uruchamiania skryptów (tj. w minimalnym środowisku osadzonym) nie musi ich obsługiwać.
Charles Duffy
2

Po prostu bym to zrobił

cd dir1/dir2/dir3/
mv file.txt file.txt.old
cd ~- # go to the most recent directory
glglgl
źródło
0

Rozwiązanie polegające na: mv something{.txt,.txt.old}używają „bashism”. Jeśli chcesz mieć bardziej przenośny sposób, używając wspólnych manipulacji zmiennymi:

# rename all files "file*.txt" of directory /dir1/dir2/dir3 into file*.txt.old:
for f in dir1/dir2/dir3/file*.txt ; do
  mv "$f" "${f/.txt/.txt.old}"  # note there are no terminating "/"
done


# "${var/A/B}" is the content of var with the first occurence of "A" replaced by "B"
Olivier Dulac
źródło
2
Zobacz pubs.opengroup.org/onlinepubs/009695399/utilities/…, gdzie znajduje się odpowiednia specyfikacja POSIX - ${var/text/replacement}to sam bashizm.
Charles Duffy,
@CharlesDuffy oh ... Zasmucasz mnie :(
Olivier Dulac