Muszę zmienić nazwę zestawu plików, używając rename
polecenia (z wyrażeniem regularnym). Po kilku próbach nie jestem w stanie znaleźć wyrażenia, które uzyska oczekiwany wynik.
Mam taki wzór pliku:
prefix_ some_name _other.txt
Wszystkie pliki zaczynają się od „ prefix_
” i kończą się na „ _other.txt
”, a część some_name może składać się z wielu (alfanumerycznych) słów oddzielonych podkreślnikami. Możliwe jest więc:
prefix_one_name_other.txt
prefix_this_is_my_name_1_this1_other.txt
Muszę zmienić nazwy takich plików:
other_one-name_ datetime other_this-is-my-name-1-this1_ datetime
Innymi słowy:
- Musisz usunąć „
prefix
” (pozostawiając podkreślenie) other
Token „ ” przechodzi na początek nazwy pliku- W some_name przekonwertuj podkreślenie (_) na myślnik (-)
- Znak podkreślenia na końcu nazwy pliku (po jakiejś nazwie ) musi pozostać
- Musisz usunąć
.txt
rozszerzenie, zastąpione datetime .
Co próbowałem:
rename 's/fw_([a-z]+)_(\d)_(\w+\d)_(\w+)\.txt/$4_$1-$2-$3_'$datahora'/' *.txt
$datahora
ma wartość daty / godziny (przetestowano). Działa to zgodnie z oczekiwaniami
prefix_name_1_gnt1_other.txt
ale nie z
prefix_other_name_2_gnt2_other.txt
Gdzie popełniłem błąd? Jak inaczej mogę to osiągnąć?
Zawiesiłem zdanie, ponieważ na razie nie jestem w stanie znaleźć wyrażenia regularnego, które działałoby dla wszystkich posiadanych nazw plików. Wiem, że pierwszy element w ciągu jest zawsze prefix
częścią, a ostatni element jest wtedy other.txt
częścią ciągu. Możliwe jest podzielenie łańcucha na tablicę i uzyskanie elementów potrzebnych do zbudowania nowej nazwy. W rzeczywistości coś takiego.
datahora="20140718-080000"
arrfiles=( *.txt )
for curfile in ${arrfiles[*]}
do
arrparts=( ${curfile//_/ } )
numitems=${#arrparts[*]}
newname=""
for (( c=1; c<numitems-1; c++ ))
do
newname+="${arrparts[c]}-"
done
newname=${newname%-}
arrparts[numitems-1]=${arrparts[numitems-1]/.txt/}
newname="${arrparts[numitems-1]}_${newname}_$datahora"
echo "$curfile pasa a $newname"
mv ${curfile} ${newname}
done
Po zrobieniu tego w ten sposób, spróbowałem ponownie @peterph sugestię, a na koniec skończyłem z kilkoma kombinacjami regexów. Pomyśl coś takiego:
rename 's/_/-/g' *.txt
rename 's/^fw-(.*)-([^-]*)(\.txt)/$2.$1$3/' *.txt
rename 's/(\w+)\.(.*)(\.txt)/$1_$2_'$datahora'/' *.txt
Nie jestem pewien, jakie jest najlepsze podejście. Moim zdaniem wariant wyrażenia regularnego wydaje się bardziej elegancki, ale potrzebuję trzech operacji zmiany nazwy (dostępu trzy razy na dysk), aby wykonać pracę, podczas gdy array
wariant zapisuje tylko raz na dysku.
¿Co sądzisz o tych dwóch rozwiązaniach? ...
Dzięki jeszcze raz.
Odpowiedzi:
O ile nie
rename
możesz zaakceptować wielu poleceń podstawiania, a katalog główny nazwy pliku (some_name
) może zawierać więcej niż jeden znak podkreślenia, musisz to zrobić w dwóch krokach: a) zastąpienie znaków podkreślenia myślnikami ib) (ponowne) przenoszenie fragmentów w pliku nazwy.Wyrażenia regularne, których szukasz, mogą na przykład:
Pierwszy wykonuje podkreślenie, aby przerywać tłumaczenia, a drugi zamienia katalog główny i sufiks oraz dołącza zawartość
DATETIME
zmiennych środowiskowych do nazw. I oczywiście pomija prefiks i rozszerzenie.[^-]*
Część pasuje dowolny ciąg nie zawierający kreskę. Jeśli sufiks jest zawsze taki sam, możesz umieścić go tam dosłownie, jak ma to miejsce w przypadku prefiksu (i odwrotnie - jeśli prefiks może się różnić, użyj,^[^-]*-
aby dopasować go jako dowolny ciąg niezawierający myślnika znajdujący się między początkiem pliku imię i (a więc) pierwszy myślnik).Jeśli
rename
obsługujesz wiele poleceń, po prostu połącz je:źródło
other-this-is-1-name-20140717-093458
Kiedy szukam:other_this-is-1-name_20140717-093458
zwróć uwagę na podkreślenie poother
i przed datetime.$2
podkreślnikami w drugim wyrażeniu regularnym.