rinominare in blocco (o visualizzare correttamente) file con caratteri speciali


20

Ho un sacco di directory e sottodirectory che contengono file con caratteri speciali, come questo file:

robbie@phil:~$ ls testsktest.txt 
test?sktest.txt

Trova rivela una sequenza di escape:

robbie@phil:~$ find testsktest.txt -ls 
424512 4000 -rwxr--r-x   1 robbie   robbie    4091743 Jan 26 00:34 test\323sktest.txt

L'unico motivo per cui posso persino digitare i loro nomi sulla console è a causa del completamento della scheda. Questo significa anche che posso rinominarli manualmente (e rimuovere il carattere speciale).

Ho impostato LC_ALL su UTF-8, che non sembra aiutare (anche non su una nuova shell):

robbie@phil:~$ echo $LC_ALL
en_US.UTF-8

Mi sto collegando alla macchina usando ssh dal mio mac. È un'installazione Ubuntu:

robbie@phil:~$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=7.10
DISTRIB_CODENAME=gutsy
DISTRIB_DESCRIPTION="Ubuntu 7.10"

Shell è Bash, TERM è impostato su xterm-color.

Questi file sono lì da un po 'di tempo e non sono stati creati usando quell'installazione di Ubuntu. Quindi non so quali fossero le impostazioni di codifica del sistema.

Ho provato le cose sulla falsariga di:

find . -type f -ls | sed 's/[^a-zA-Z0-9]//g'

Ma non riesco a trovare una soluzione che fa tutto ciò che voglio:

  1. Identifica tutti i file con caratteri non visualizzabili (quanto sopra ignora troppo)
  2. Per tutti quei file in un albero di directory (ricorsivamente), esegui mv oldname newname
  3. Opzionalmente, la possibilità di traslitterare caratteri speciali come ä in un (non richiesto, ma sarebbe fantastico)

O

  1. Visualizza correttamente tutti questi file (e nessun errore nelle applicazioni quando si tenta di aprirli)

Ho bit e pezzi, come iterare su tutti i file e spostarli, ma identificare i file e formattarli correttamente per il comando mv sembra essere la parte difficile.

Sono inoltre benvenute eventuali informazioni aggiuntive sul motivo per cui non vengono visualizzate correttamente o su come "indovinare" la codifica corretta. (Ho provato convmv ma non sembra fare esattamente quello che voglio: http://j3e.de/linux/convmv/ )


La singola risposta di seguito segue il primo modo (trovali e rinomina con la tua nuova codifica), ma il secondo modo sarebbe anche interessante: ora, quando conosci la codifica usata per i nomi dei file remoti, come ssh all'host remoto in tale un modo in cui i nomi dei file sono visualizzati correttamente (e possono essere gestiti digitandone i nomi con la tastiera)?
imz - Ivan Zakharyaschev,

Risposte:


21

Immagino tu veda questo carattere non valido perché il nome contiene una sequenza di byte che non è valida UTF-8. I nomi dei file sui filesystem unix tipici (incluso il tuo) sono stringhe di byte, e spetta alle applicazioni decidere quale codifica utilizzare. Al giorno d'oggi, c'è una tendenza a usare UTF-8, ma non è universale, specialmente in locali che non potrebbero mai vivere con ASCII normale e hanno usato altre codifiche da prima ancora che UTF-8 esistesse.

Prova LC_CTYPE=en_US.iso88591 lsa vedere se il nome del file ha senso in ISO-8859-1 (latino-1). In caso contrario, prova altre impostazioni locali. Nota che LC_CTYPEqui sono importanti solo le impostazioni locali.

In una locale UTF-8, il seguente comando mostrerà tutti i file il cui nome non è valido UTF-8:

grep-invalid-utf8 () {
  perl -l -ne '/^([\000-\177]|[\300-\337][\200-\277]|[\340-\357][\200-\277]{2}|[\360-\367][\200-\277]{3}|[\370-\373][\200-\277]{4}|[\374-\375][\200-\277]{5})*$/ or print'
}
find | grep-invalid-utf8

Puoi verificare se hanno più senso in un'altra locale con ricodifica o iconv :

find | grep-invalid-utf8 | recode latin1..utf8
find | grep-invalid-utf8 | iconv -f latin1 -t utf8

Dopo aver determinato che un gruppo di nomi di file ha una determinata codifica (ad esempio latin1), un modo per rinominarli è

find | grep-invalid-utf8 |
rename 'BEGIN {binmode STDIN, ":encoding(latin1)"; use Encode;}
        $_=encode("utf8", $_)'

Questo usa il comando perl rename disponibile su Debian e Ubuntu. Puoi passarlo -nper mostrare cosa farebbe senza rinominare i file.


Grazie proverò alcune di queste cose più tardi oggi! Sembra che questa sarà la risposta accettata :)
RobbieV,

La scoperta | Il comando grep '[[: print:]]' sembra restituire semplicemente tutti i file. UTF-8 non dovrebbe essere compatibile con molte altre codifiche con caratteri "normali"?
RobbieV,

@RobbieV: ho sbagliato a scrivere e intendevo grep [^[:print:]]cercare personaggi non stampabili. Ma ho appena provato con GNU grep e le sequenze UTF-8 non valide non vengono catturate [^[:print:]](il che ha senso in quanto non sono caratteri non stampabili, non sono affatto personaggi). Ho modificato il mio post con un modo più lungo di seguire le linee con sequenze utf8 non valide. Nota che ho anche corretto la direzione degli esempi recodee iconv.
Gilles 'SO- smetti di essere malvagio' il

Funzionava perfettamente. Ho provato tutti i comandi tranne quello iconv, e funzionano tutti come previsto. Pura magia!
RobbieV,

Anche la codifica latin1 suggerita era quella corretta :)
RobbieV,

1

So che questa è una vecchia domanda, ma ho cercato per tutta la notte una soluzione simile. Ho trovato alcuni suggerimenti utili ma non hanno fatto esattamente quello di cui avevo bisogno, quindi ho dovuto mescolarne alcuni per ottenere il risultato corretto che stavo cercando

per rimuovere semplicemente caratteri speciali e sostituirli con un punto (.)

for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done

per usare in un cronjob ho fatto quanto segue per eseguire ogni minuto

*/1 * * * * cd /path/to/files/ && for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done >/dev/null 2>&1

Spero che qualcuno lo trovi utile perché ha reso la mia giornata :)


(1) Per chiarezza, potresti voler cambiare `…`in $(…)- vedi questo , questo e questo . (2) Dovresti sempre citare i riferimenti alle variabili della shell (ad es. "$f") A meno che tu non abbia una buona ragione per non farlo e sei sicuro di sapere cosa stai facendo. Questo vale anche per echo "$f" | sed …. Si applica anche all'intera $(…)(o `…`) espressione; Per esempio, mv "$f" "$(echo "$f" | sed "…")". ... (proseguendo)
Scott,

(Proseguendo) ... (3) Dovresti dire , per proteggerti dai nomi dei file che iniziano con . (4) Se hai file denominati “foo ♥ bar.txt” e “foo ♠ bar.txt”, questo (tenterà di) rinominarli entrambi in “foo.bar.txt”, causando probabilmente tutti tranne uno dei file da distruggere. (5) Perché mai vorresti farlo una volta al minuto? mv -- "$f" …-
Scott,

Ho uno script torrent che scarica automaticamente i file. e a volte alcuni file contengono dei caratteri che gettano via l'uploader. quindi, semplicemente rinominando i file con caratteri speciali, il mio cron ha risolto tutti i miei problemi e l'uploader ha svolto il suo lavoro senza problemi.
Topps70,

così (questo è il motivo per cui - down_loaded.ext) si trasforma in (this.fi.le.tha.t.was.down.loaded.ext)
Topps70

0

Ora, quando sai quale codifica viene utilizzata per i nomi dei file sull'estremità remota ("latin1" - in base ai commenti alla prima risposta), puoi anche seguire il secondo modo - eseguire un termine locale e ssh in tale modo in cui i nomi dei file remoti vengono visualizzati correttamente (piuttosto che nel primo modo: rinominarli) .

Come me , potresti avviare un terminale localmente che funzionerebbe con quella codifica speciale, forse in questo modo:

LC_ALL = en_US.latin1 xvt &

xvt sta per il tuo programma terminale.

Forse, la localizzazione esistente viene chiamata en_US.iso88591e non en_US.latin1, come pensavo.


0

Questo non soddisfa i requisiti di massa, ma ho appena avuto un problema simile in cui avevo più versioni di un file con nomi simili che differivano solo per un singolo carattere strano. Sfortunatamente questo significava che non potevo rinominare i trasgressori usando il trucco jolly che di solito uso.

Alla fine ho usato Filezilla per connettermi come client SFTP, ho cercato i file e li ho rinominati usando la GUI. Filezilla ha gestito abbastanza bene i personaggi malvagi.

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.