Sostituzione dei punti nel nome del file con caratteri di sottolineatura tranne l'estensione


9

Qualcuno può suggerire su come rinominare il nome del file:

head.body.date.txt

Per:

head_body_date.txt

Esiste un'istruzione a riga singola per rinominare Unix ?


9
Pensi che .tar.gzsia un'estensione? Inoltre, benvenuto in U&L!
EKons,

2
Intendi davvero Unix rispetto a Linux? Quale Unix?
terdon

1
La risposta ovvia è mv head.body.date.txt head_body_date.txt. Se hai altre restrizioni o esempi reali, ti preghiamo di aggiornare la tua domanda con queste. Allo stato attuale, non è chiaro se la domanda si riferisca a un file con quel nome esplicito, a una singola directory in cui tutti i file hanno un formato particolare o se si desidera cercare una gerarchia di directory per nomi particolari e modificarli.
Kusalananda

Risposte:


9

Scorrere i nomi dei file e utilizzare l'espansione dei parametri per la conversione:

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

Il modello di espansione del parametro, ${f//./_}sostituisce tutte le .s con _s nel nome file ( $f).

Quanto sopra eseguirà un ciclo a secco, per consentire l'effettiva ridenominazione, rimuovere echo:

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

Se vuoi occuparti di qualsiasi estensione, non solo .txt:

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

Dopo aver controllato rimuovi echoper azione effettiva:

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

Generico, per un numero arbitrario di punti, almeno uno:

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

esiste un modo generale se esiste un numero arbitrario di punti?
Ciprian Tomoiagă,

1
@CiprianTomoiaga Do:for f in *.*; do ...; done
heemayl

Potrei suggerire di mettere il *.*modello dritto nell'esempio, poiché ora il codice sembra funzionare solo con un numero fisso di punti.
ilkkachu,

@ilkkachu Abbastanza giusto, modificato.
heemayl

Grazie mille, ha funzionato per me. e un po 'di apprendimento!
SG

4

con perlbasatorename

$ rename -n 's/\.[^.]+$(*SKIP)(*F)|\./_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)
  • \.[^.]+$(*SKIP)(*F) salta questo schema e cerca corrispondenze alternative
  • |\./_/gsostituire tutto .con_

Oppure, usando lookahead negativo

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

Una volta che va bene, rimuovere l' -nopzione


3
rename 's/\.(?=[^.]*\.)/_/g' *.txt

Utilizza la sostituzione regex per trovare tutti tranne l'ultima istanza di .nel nome file (lookahead non di acquisizione) e sostituirli con _. Generalizza *.*se ti piace.

(questa particolare versione di renamesembra essere installata tramite util-linux). Sto usando Ubuntu 12.04(sì, macchina gravemente obsoleta).


2

bash:

old=head.body.date.txt oldb=${old%.*} olde=${old##*.} ; \
mv -- "$old" "${oldb//./_}.${olde}"

(1) Dovresti usare mv --, per proteggerti dai "vecchi" nomi di file che iniziano con -. (2) Dovresti mettere $oldtra virgolette ( "$old"), per proteggerti dai "vecchi" nomi di file che contengono spazi o caratteri speciali per la shell (come *e ?). (3) La tua risposta fallisce nel caso in qualche modo patologico in cui l'estensione contiene un carattere di sottolineatura: head.body.date.t_xtviene rinominata head_body_date_t.xt.
Scott,

@Scott, grazie. Il codice è ora ottimizzato come per tutti e tre gli elementi citati.
agc,

1

Utilizzando mv, sede revin una sola riga:

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

Se vuoi applicarlo su tutti i txtfile nel rappresentante attuale, usare globs sembra complicato a causa di come mvfunziona, ma puoi fare un forciclo in una riga:

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

Leggermente più lungo, ma puoi abbinare diversi modelli nel tuo loop!


2
(1) Arrghhh! Non farlo $(ls …); fallo e basta for file in *.txt. (2) Si dovrebbe usare più citazioni: mv "$file" "$(…)".
Scott,

Grazie Scott, debitamente notato e modificato! Sono ancora un giovane in guscio, per favore sii gentile;)
Valentin B.

Col senno di poi, l'uso renamecome molti altri hanno suggerito nelle loro risposte suona più semplice però ...
Valentin B.

-1
 mv head.body.date.txt head_body_date.txt

È semplice come quello per un singolo file alla volta. Non si specifica se si desidera che ciò avvenga in modo ricorsivo all'interno di una directory o dell'intera directory, in modo che sia la soluzione più conveniente e rapida.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.