Zastępowanie kropek w nazwie pliku podkreśleniami oprócz rozszerzenia

9

Czy ktoś może zasugerować, jak zmienić nazwę nazwy pliku:

head.body.date.txt

Do:

head_body_date.txt

Czy istnieje uniksowa instrukcja do zmiany nazwy w Unixie ?

SG
źródło
9
Czy zakładasz, że .tar.gzjest to rozszerzenie? Witamy również w U&L!
EKons,
2
Czy naprawdę masz na myśli Uniksa, a nie Linuksa? Który Unix?
terdon
1
Oczywista odpowiedź brzmi mv head.body.date.txt head_body_date.txt. Jeśli masz inne ograniczenia lub prawdziwe przykłady, zaktualizuj swoje pytanie o te. W obecnej sytuacji nie jest jasne, czy pytanie dotyczy pliku o tej wyraźnej nazwie, pojedynczego katalogu, w którym wszystkie pliki mają określony format, czy też chcesz przeszukać hierarchię katalogów w poszukiwaniu określonych nazw i zmienić je.
Kusalananda

Odpowiedzi:

9

Iteruj po nazwach plików i użyj rozszerzenia parametru do konwersji:

for f in *.*.*.txt; do i="${f%.txt}"; echo mv -i -- "$f" "${i//./_}.txt"; done

Wzorzec ekspansji parametrów ${f//./_}zastępuje wszystkie .s literą _s w nazwie pliku ( $f).

Powyższe wykona próbę wstępną, aby umożliwić faktyczną zmianę nazwy, usuń echo:

for f in *.*.*.txt; do i="${f%.txt}"; mv -i -- "$f" "${i//./_}.txt"; done

Jeśli chcesz poradzić sobie z dowolnym rozszerzeniem, nie tylko .txt:

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     echo mv -i -- "$f" "${pre//./_}.${suf}"; done

Po sprawdzeniu usuń echodla faktycznego działania

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     mv -i -- "$f" "${pre//./_}.${suf}"; done

Ogólny, dla dowolnej liczby kropek, co najmniej jeden:

for f in *.*; do pre="${f%.*}"; suf="${f##*.}"; \
                 mv -i -- "$f" "${pre//./_}.${suf}"; done
heemayl
źródło
czy istnieje ogólny sposób, jeśli istnieje dowolna liczba kropek?
Ciprian Tomoiagă,
1
@CiprianTomoiaga Do:for f in *.*; do ...; done
heemayl
Mogę zasugerować umieszczenie *.*wzorca prosto w przykładzie, ponieważ teraz kod wygląda tak, jakby działał tylko ze stałą liczbą kropek.
ilkkachu
@ilkkachu Wystarczająco edytowane.
heemayl
Dziękuję bardzo, to zadziałało dla mnie. i trochę nauki!
SG
4

z perlopartymrename

$ rename -n 's/\.[^.]+$(*SKIP)(*F)|\./_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)
  • \.[^.]+$(*SKIP)(*F) pomiń ten wzór i poszukaj alternatywnych dopasowań
  • |\./_/gzastąpić wszystko .z_

Lub używając negatywnego spojrzenia w przyszłość

$ rename -n 's/\.(?![^.]+$)/_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)

Gdy będzie to w porządku, usuń -nopcję

Sundeep
źródło
3
rename 's/\.(?=[^.]*\.)/_/g' *.txt

Używa zamiany wyrażeń regularnych, aby znaleźć wszystkie oprócz ostatniej instancji .w nazwie pliku (nie przechwytywanie z wyprzedzeniem) i zastąpić je _. Uogólnia na, *.*jeśli chcesz.

(ta konkretna wersja renamewydaje się być instalowana przez util-linux). Używam Ubuntu 12.04(tak, poważnie przestarzała maszyna).

Jonathan Carroll
źródło
2

bash:

old=head.body.date.txt oldb=${old%.*} olde=${old##*.} ; \
mv -- "$old" "${oldb//./_}.${olde}"
agc
źródło
(1) Powinieneś użyć mv --, aby ochronić się przed „starymi” nazwami plików, które zaczynają się od -. (2) Powinieneś wstawić $oldcudzysłowy ( "$old"), aby uchronić się przed „starymi” nazwami plików, które zawierają spacje lub znaki specjalne dla powłoki (jak *i ?). (3) Twoja odpowiedź kończy się niepowodzeniem w nieco patologicznym przypadku, w którym rozszerzenie zawiera znak podkreślenia: head.body.date.t_xtzostaje zmieniona na head_body_date_t.xt.
Scott,
@Scott, dzięki. Kod jest teraz poprawiany zgodnie ze wszystkimi trzema wymienionymi elementami.
agc,
1

Korzystanie mv, seda revw jednym wierszu:

mv "head.body.date.txt" "$(echo head.body.date.txt | rev | sed 's/\./_/2g' | rev)"

Jeśli chcesz zastosować go do wszystkich txtplików w bieżącym rep, użycie globów wydaje się trudne ze względu na to, jak mvdziała, ale możesz zrobić forpętlę w jednowierszowym:

for file in *.txt; do mv "$file" "$(echo $file | rev | sed 's/\./_/2g' | rev)"; done

Nieco dłużej, ale możesz dopasować kilka wzorów w swojej pętli!

Valentin B.
źródło
2
(1) Arrghhh! Nie rób $(ls …); po prostu zrób for file in *.txt. (2) Należy użyć więcej cytatów: mv "$file" "$(…)".
Scott,
Dziękuję Scott, należycie odnotowany i zredagowany! Nadal jestem młodzieńcem w skorupce, proszę, bądź łagodny;)
Valentin B.,
Z perspektywy czasu, używanie renamejak kilka innych sugerowanych w swoich odpowiedziach wydaje się prostsze ...
Valentin B.,
-1
 mv head.body.date.txt head_body_date.txt

Jest to tak proste, jak dla pojedynczego pliku na raz. Nie określasz, czy chcesz to robić rekurencyjnie w katalogu, czy w całym katalogu, aby było to najwygodniejsze i szybkie rozwiązanie.

coderodour
źródło