Trattare i nomi dei file con i primi caratteri speciali (es. ♫)


30

Recentemente ho trovato un file il cui nome inizia con il carattere '♫'. Volevo copiare questo file, inserirlo in ffmpeg, e fare riferimento in vari altri modi nel terminale. Di solito compio automaticamente nomi di file strani ma questo non riesce poiché non riesco nemmeno a digitare la prima lettera.

Non voglio passare al mouse per eseguire una manovra di copia-incolla. Non voglio memorizzare un sacco di codici per possibili scenari. La mia soluzione ad hoc consisteva nel passare vim, incollare !lse copiare il personaggio in questione, quindi uscire e incollarlo nel terminale. Questo ha funzionato ma è abbastanza orribile.

Esiste un modo più semplice per gestire tali scenari?

NOTA: sto usando il guscio di pesce se cambia le cose.


7
Puoi usare altre parti del file per formare una regex per lavorare con esso? *restoffile.avio qualcosa del genere?
slm

1
In questo caso il nome rimanente era una miscela di Kanji e Katakana (sceneggiatura giapponese), quindi non con facilità.
Zircon,

3
Capito, ho pensato di chiedere. La risposta di Jimmij la risolve allora? Ti dispiacerebbe incollare uno screenshot dei file offensivi? Sarebbe probabilmente utile per gli altri che potrebbero leggere questo in seguito.
slm

1
Sto cercando di farlo funzionare ora. Non so come pubblicare uno screeny ma eseguire i seguenti comandi ti darà il mio finto problema:touch '♫ 漢字カ' touch '♫ 漢字タ'
ZirconCode

1
Con zsh puoi usare le opzioni per avere una scheda che ti dia un menu dal quale puoi selezionare il file appropriato.
Kevin,

Risposte:


35

Se il primo carattere del nome del file è stampabile ma né alfanumerico né gli spazi bianchi, è possibile utilizzare l' [[:punct:]]operatore glob:

$ ls *.txt
f1.txt  f2.txt  ♫abc.txt
$ ls [[:punct:]]*.txt
♫abc.txt

Hmm non sapevo di questi operatori glob, ho letto su di loro e ho imparato un po '(grazie), risolve il problema che avevo che è un singolo file strano nella mia directory. Ora ho questo problema con una grande moltitudine di file, devo fare una nuova domanda o aggiornarla?
ZirconCode

Ho accettato la tua risposta, domani posterò il secondo scenario quando avrò tempo. Grazie per l'aiuto.
Zircon,

6

Il più semplice che mi viene in mente è ls [^a-zA-Z0-9]*e fa il trucco per me, ma la risposta di Terdon è migliore nel portare l'attenzione sull'opzione shell extglob o persino su un approccio indipendente dalla shell.


Questa è una pugnalata abbastanza decente. Potresti ls [^[:alnum:]]*per la stessa cosa. Ma è meglio usare la classe di caratteri che è , piuttosto che le classi che non lo sono ; quindi ls [[:punct:]]*elencherò questo file.
Ricco

6

Ha alcuni switch (come --quote-name, --escape, --literal) per gestire i caratteri non stampabili, ma in questo caso sembra che il personaggio sia "stampabile" ma non "tipizzabile" (almeno sulla mia tastiera! ), quindi nessuno di questi interruttori sembra aiutare.

Pertanto, come approccio generale "forza bruta" per sbarazzarsi di file con qualsiasi carattere nei loro nomi, è possibile fare questo:

$ /bin/ls -1A|cat -n  # list all files (except . and ..), 1 per line, add line numbers
     1  ♫
     2  f1.txt
     3  f2.txt

Trova la riga contenente il file offensivo. Molto probabilmente sarà la prima linea, ma diciamo che è la quinta. Stampa la riga 5 ed esadecimale codificala:

$ /bin/ls -1A|sed -n 5p|xxd -g 1
0000000: e2 99 ab 0a                                      ....

Ignorando il carattere 0a (newline), costruisci una stringa di escape e usa l'opzione -e di echo per tradurre gli escape:

$ echo -e '\xe2\x99\xab'
♫

Ora puoi copiarlo / spostarlo / eliminarlo in questo modo:

$ cp -vi $(echo -e '\xe2\x99\xab') better_name
‘♫’ -> ‘better_name’

Inoltre, se non sei limitato all'uso dello script di shell, puoi farlo in Python in questo modo:

$ python
>>> import os
>>> os.listdir('.')
[ ..., '\xe2\x99\xab', ... ]
>>> print '\xe2\x99\xab'
♫
>>> import shutil
>>> shutil.copy('\xe2\x99\xab', 'better_name')

Usando questo approccio, puoi elaborare molti file, devi solo scrivere la logica per selezionare i file corretti e rinominarli senza clobbering, ecc:

for f in os.listdir('.'):
  if not f.isalnum():
    newname = generate_newname(f)
    if not os.path.exists(newname):
      shutil.copy(f, newname)
    else:
      print newname, 'already exists!'

5

Un approccio simile sarebbe quello di elencare tutti i file che non iniziano con caratteri "normali". In bash puoi farlo con

$ shopt -s extglob
$ ls !([[:alpha:]]*)

Tuttavia, ciò non sembra essere disponibile fish, quindi è possibile utilizzare findinvece:

$ find . -type f -not -name '[[:alpha:]]*'

4

Rinomina i collegamenti simbolici

Un approccio per gestire i nomi di file con caratteri speciali - come primi caratteri o altrove nel nome del file è quello di rinominare in nomi più semplici .

Questo può essere usato anche se è necessario conservare i nomi dei file originali : rinominare una copia dei nomi dei file.
Ciò può essere fatto copiando i file, ma anche creando collegamenti simbolici o hardlink ai file e rinominandoli. cpcrea collegamenti simbolici anziché copie con l'opzione -s( -lper collegamenti fissi).

Usa "detox" per pulire i nomi

Per rinominare nomi di file puliti, detoxpuò essere utilizzato; Rinomina i file per ripulire i nomi dei file in base a varie regole definite in un detoxrcfile. Per impostazione predefinita, i caratteri UTF8 sono appena rimossi; Con l'opzione -s utf_8-onlysono sostituiti da _:

$ touch '♫ 漢字カ' ♫foo
$ ls -1
♫foo
♫ 漢字カ
$ detox -s utf_8-only * 
$ ls -1                
_ ___
_foo


"disintossicazione" sui link simbolici

In combinazione con il lavoro su collegamenti simbolici come descritto sopra:

$ mkdir orig
$ cd orig 
$ touch '♫ 漢字カ' ♫foo
$ cd ..
$ mkdir clean
$ cd clean 
$ cp -s ../orig/* .
$ ll               
lrwxrwxrwx 1 14 Oct  8 05:52 ♫foo -> ../orig/♫foo
lrwxrwxrwx 1 21 Oct  8 05:52 ♫\ 漢字カ -> ../orig/♫\ 漢字カ
$ ls -1
♫foo
♫ 漢字カ
$ detox --special -s utf_8-only *
$ ll                                
lrwxrwxrwx 1 21 Oct  8 05:52 _\ ___ -> ../orig/♫\ 漢字カ
lrwxrwxrwx 1 14 Oct  8 05:52 _foo -> ../orig/♫foo

2

Non lo uso fish, ma la documentazione dice che è possibile inserire un carattere Unicode prefissando il suo codice esadecimale con \u(per caratteri a 16 bit) o \U(per caratteri a 32 bit). Penso che il codice sia 491eb, quindi potresti fare:

mv \U000491ebabc.mp3 abc.mp3

rinominare ♫abc.mp3.

Nota che hai bisogno degli zeri iniziali, altrimenti abcalla fine saranno trattati come cifre esadecimali e parte del codice carattere; per un carattere a 32 bit è necessario inserire 8 cifre.


2

Non so se era già il caso nel 2014 quando hai posto la domanda, ma nelle versioni attuali di fish(a partire dal 2019), puoi premere Tabdue volte, per ottenere una selezione in stile zsh in cui puoi usare i tasti freccia per selezionare visivamente il file desiderato senza dover digitare alcuna parte del nome file.


2

Fish non supporta i caratteri jolly parentesi ¹ in base alla progettazione.

function find_special_filename
    find ! -path './.*' -name '[^-.a-zA-Z0-9_]*' $argv
end

Il comando non cerca nelle directory e visualizza nomi di file nascosti che non iniziano con i caratteri letters, digits, . _ -(cf la documentazione di find).

Nota: $argv è una variabile di matrice speciale (Fish shell) che contiene gli argomenti della funzione, pertanto il comando sottostante può ricevere qualsiasi espressione (ad es. Alias ).

find_special_filename -exec mv '{}' misc/ \;

¹ In effetti, Fish supporta l'espansione di parentesi (espansione di variabili di array) ma Bash utilizza un'altra terminologia (espansioni di parametri e nome file).


1

Usa zshe digita ciò che verrà dopo. ZSH supporta il completamento automatico fuzzy e può gestirlo. (È particolarmente bello con il plugin OH-MY-ZSH .)


0

Non hai detto se vuoi mantenere questi nomi di file problematici. Una soluzione potrebbe essere quella di "risolvere" il problema una volta per tutte rinominando (alcuni o tutti) i tuoi file con nomi che puoi digitare eseguendo questo script:

#!/bin/sh
for old in *
do
      printf "%s ...? " "$old"
      if read new  &&  [ "$new" != "" ]
      then
             mv -i "$old" "$new"
      fi
done

Questo elencherà i nomi dei file esistenti, ciascuno seguito da ...?. Basta digitare Enterper lasciare un file così com'è; o digita un nuovo nome per rinominarlo. L' -iopzione ti chiederà di confermare la sovrascrittura se si specifica il nome di un altro file esistente.

Questo script può essere modificato in diversi modi:

  • È possibile modificare il carattere jolly (* ) in qualcosa di più restrittivo, ad esempio *.avi *.mov, quindi non è necessario guardare ogni file.
  • Si potrebbe cambiare il mvversocp , in modo da mantenere una copia del file con il suo nome attuale e creare un (temporaneo?) Copia con un nome tipizzabile.
  • È possibile creare un nuovo nome file basato sul nome file esistente. Per esempio,

    if read pfx  &&  [ "$pfx" != "" ]
    then
            mv -i "$old" "$pfx$old"
    fi
    

    che ti consente di schiaffeggiare un prefisso davanti al vecchio nome. Se scegli un prefisso univoco, questo ti permetterà di usare il completamento automatico.

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.