Zmień nazwę wielu plików za pomocą skryptów Bash

27

Chcę zmienić nazwę wielu plików w tym samym katalogu przy użyciu skryptów Bash. Nazwy plików są następujące:

file2602201409853.p
file0901201437404.p  
file0901201438761.p  
file1003201410069.p  
file2602201410180.p

Chcę zmienić nazwę na następujący format:

file2503201409853.p
file2503201437404.p  
file2503201438761.p  
file2503201410069.p  
file2503201410180.p

Czytałem o poleceniu zmiany nazwy i próbowałem to zrobić w ten sposób, ale to nic nie robi, myślę, że mam pytania dotyczące składni. Następnie przeczytałem, że można wykonać pętlę za pomocą polecenia mv w następujący sposób:

for file in cmpsms*2014*.p; do
    mv "$file" "${file/cmpsms*2014*.p/cmpsms25032014*.p}"
done

Ale nie mogę zmienić nazwy plików. Co ja robię źle?

franvergara66
źródło
2
Po prawej stronie wyrażenia zastępującego rozszerzenie parametru nie można mieć wyrażenia wzorcowego. Co spodziewałeś się tam być *?
kojiro
@ Kiwi To pytanie dotyczy usunięcia części nazwy pliku. Ergo, bardzo wątpliwie powielone.
CVn
2
Następnym razem opisz zmiany nazw plików, które chcesz wprowadzić (musiałem przyjrzeć się temu przez dłuższy czas, zanim zobaczyłem różnice i podobieństwa). Przykłady są dobre, ale opis i przykłady są jeszcze lepsze.
CVn

Odpowiedzi:

42

Miałeś rację, rozważając zmianę nazwy w pierwszej kolejności. Składnia jest trochę dziwna, jeśli nie jesteś przyzwyczajony do wyrażeń regularnych, ale jest to zdecydowanie najszybsza / najkrótsza droga, gdy wiesz, co robisz:

rename 's/\d{4}/2503/' file*

To po prostu pasuje do pierwszych 4 liczb i zamienia je na te, które określiłeś.

I uprząż testowa ( -vnoznacza mówienie, ale nic nie rób ) przy użyciu nazw plików:

$ rename 's/\d{4}/2503/' file* -vn
file0901201437404.p renamed as file2503201437404.p
file0901201438761.p renamed as file2503201438761.p
file1003201410069.p renamed as file2503201410069.p
file2602201409853.p renamed as file2503201409853.p
file2602201410180.p renamed as file2503201410180.p
Oli
źródło
8
Zauważ, że jest to nazwa Perla dla Debiana i pochodnych (Ubuntu, Mint,…). W innych dystrybucjach Linuksa renamejest zupełnie innym narzędziem do zmiany nazw plików (które dostarcza Debian rename.ul).
Gilles „SO- przestań być zły”
Jeśli nie masz takiego narzędzia, spójrz na odpowiedź @Michael Campbell. Myślę, że każda dystrybucja zastępuje domyślne renamejak debian.
Astery,
25

To powinno załatwić sprawę:

for f in file*; do mv $f ${f/${f:4:8}/25032014}; done

Zastępuje ciąg między czwartym i dwunastym znakiem „25032014”.

chaos
źródło
to for f in file*; do mv $f ${f/${f:4:4}/2503}; doneteż działa.
Avinash Raj
To miłe. Jeśli chcesz tylko zamienić zwykłe słowo na zamianę słów, działa to jak sed. np.for f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Eric
1
@Eric - zamieściłem twoją odpowiedź jako alternatywę, ponieważ uważam, że jest bardziej przejrzysta i elegancka. Jeśli chcesz również wysłać to jako odpowiedź - usunę moje. Dzięki!
Yehosef,
Dlaczego brakuje podwójnych cudzysłowów ?
Wildcard,
Daje mi błąd: „mv: cel„ FILE_NAME ”nie jest katalogiem”
Aubrey
10

to naprawdę odpowiedź @ Erica z góry - ale jest to elegancka odpowiedź, więc zamieszczam ją jako właściwą odpowiedź, aby zwrócić na to większą uwagę.

for f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Yehosef
źródło
1
ptrn='file[0-9][0-9][0-9][0-9]2014[0-9][0-9][0-9][0-9][0-9].p'
path=/dir
( set -- "${path}/"${ptrn} ; for f ; do {
    echo "mv ${path}/${f} \
        ${path}/file25032014${f#2014}" 
} ; done )

To powinno załatwić sprawę. Uwaga - nie mam w zwyczaju wydawania poleceń mv - jak napisano, to tylko echo. Musisz to rozwiązać, zanim to zadziała.

mikeserv
źródło
1

Prosty natywny sposób na zrobienie tego bez zapętlania, z przechodzeniem do katalogu :

find -type f | xargs -I {} mv {} {}.txt

Zmieni nazwę każdego pliku na miejscu.

A poniżej działający przykład z równoległością :

find -name "file*.p" | parallel 'f="{}" ; mv -- {} ${f:0:4}2503${f:8}'
dtrckd
źródło
To było pierwsze łatwe podejście do wymyślenia lepszego rozwiązania. Jeśli chcesz działające polecenie, wykonaj:
dtrckd
find -type f -name "file*.p" | parallel 'ext="{}" ; mv -- {} ${ext:0:4}2503${ext:8}'
dtrckd
0

Jeśli uważasz, że często tego rodzaju rzeczy robisz, poszukaj „rename.pl”. Jest to skrypt perla, ale pozwala po prostu podać mu kod perla (np. Jako wyrażenie ///), i zmieni masową nazwę na podstawie tego wyrażenia lub kodu.

Jest tutaj podstawowa wersja: http://stackoverflow.org/wiki/Rename.pl, ale istnieją inne wersje unoszące się w sieci. To było od wieków, wieków i wieków.

Michael Campbell
źródło