Perché i nomi delle mie cartelle sono finiti in questo modo e come posso risolvere questo problema usando uno script?


15

Scusa se questa ha una risposta altrove, non ho idea di come cercare il mio problema.

Stavo eseguendo alcune simulazioni su un server HPC Linux Redhat e il mio codice per la gestione della struttura delle cartelle per salvare l'output aveva un bug sfortunato. Il mio codice matlab per creare la cartella era:

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

dove sp.run_numberera un numero intero. Ho dimenticato di convertirlo in una stringa, ma per qualche motivo l'esecuzione mkdir(folder);(in matlab) è comunque riuscita. In effetti, le simulazioni sono state eseguite senza intoppi e i dati sono stati salvati nella directory corrispondente.

Ora, quando la struttura delle cartelle viene interrogata / stampata ottengo le seguenti situazioni:

  • Quando provo a tab completamento automatico: run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/
  • Quando uso ls: run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?.
  • Quando trasferisco sul mio mac usando rsync, l' --progressopzione mostra: run_\#003/ecc. Con (presumo) il numero corrispondente all'intero in sp.run_numberimbottito a tre cifre, quindi la decima corsa èrun_\#010/
  • Quando visualizzo le cartelle nel finder vedo run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
  • Guardando questa domanda e usando il comando ls | LC_ALL=C sed -n lottengo:
run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$

Non riesco a cdentrare nelle cartelle usando nessuna di queste rappresentazioni.

Ho migliaia di queste cartelle, quindi dovrò risolverlo con uno script. Quale di queste opzioni è la rappresentazione corretta della cartella? Come posso fare riferimento programmaticamente a queste cartelle in modo da rinominarle con un nome correttamente formattato usando uno script bash? E immagino per curiosità, come diavolo è potuto succedere in primo luogo?


4
"Quando provo a eseguire il tab completamento automatico: ... Se provo a digitare ..." Perché digitare e non lasciare che il completamento automatico sia completo per te? Inoltre ^Anon è letteralmente ^seguito da A, ma Ctrl-A (puoi digitarlo usando Ctrl-V Ctrl-A poiché Ctrl-A è generalmente una scorciatoia per la shell).
muru,

@muru che non funziona ... Arrivo run_e devo digitare qualcosa
Phill

Mi dispiace commentato prima di vedere la tua modifica, che riesce a farmi entrare via cd
Phill il

Possibile duplicato di Select unicode filename in Bash
muru,

9
A proposito, la "qualche ragione" per cui mkdir in matlab ha fatto questo è perché SOLO i caratteri non validi in un nome di file o directory su filesystem unix sono NUL e forward-slash /. Qualsiasi altro personaggio è valido, inclusi i personaggi di controllo. Non so cosa avrebbe fatto matlab se sp.run_number fosse 0 (probabilmente si interrompeva con un errore o produceva run_, poiché il byte NUL avrebbe terminato la stringa del nome della directory). Naturalmente, ciò sarebbe problematico anche per i valori a 16 bit (o superiori) che contenevano un byte NUL, e varierebbe anche in base all'endianità del sistema che esegue matlab.
Cas

Risposte:


26

È possibile utilizzare l' renameutilità perl (aka prenameo file-rename) per rinominare le directory.

NOTA: Questo non deve essere confuso con renameda util-linux, o di qualsiasi altra versione.

rename -n 's/([[:cntrl:]])/ord($1)/eg' run_*/

Questo usa la ord()funzione di perl per sostituire ogni carattere di controllo nel nome del file con il numero ordinale per quel carattere. ad esempio ^Adiventa 1, ^Bdiventa 2, ecc.

L' -nopzione è per una corsa a secco per mostrare cosa rename farebbe se lo lasciassi. Rimuovilo (o sostituiscilo con -vun output dettagliato) per rinominarlo effettivamente.

Il emodificatore s/LHS/RHS/egnell'operazione fa sì che perl esegua l'RHS (la sostituzione) come codice perl, e $1sono i dati corrispondenti (il carattere di controllo) dall'LHS.

Se si desidera ottenere numeri con spaziatura zero nei nomi dei file, è possibile combinarli ord()con sprintf(). per esempio

$ rename -n 's/([[:cntrl:]])/sprintf("%02i",ord($1))/eg' run_*/ | sed -n l
rename(run_\001, run_01)$
rename(run_\002, run_02)$
rename(run_\003, run_03)$
rename(run_\004, run_04)$
rename(run_\005, run_05)$
rename(run_\006, run_06)$
rename(run_\a, run_07)$
rename(run_\b, run_08)$
rename(run_\t, run_09)$

Gli esempi sopra funzionano se e solo se sp.run_number nel tuo script matlab era compreso nell'intervallo 0..26 (quindi ha prodotto caratteri di controllo nei nomi delle directory).

Per gestire QUALSIASI carattere a 1 byte (ovvero da 0..255), dovrai utilizzare:

rename -n 's/run_(.)/sprintf("run_%03i",ord($1))/e' run_*/

Se sp.run_numberpotesse essere> 255, dovresti usare la unpack()funzione di perl invece di ord(). Non so esattamente come matlab emetta un int non convertito in una stringa, quindi dovrai sperimentare. Vedi perldoc -f unpackper i dettagli.

ad es. quanto segue disimballerà i valori non firmati a 8 e 16 bit e li azzererà fino a 5 cifre:

 rename -n 's/run_(.*)/sprintf("run_%05i",unpack("SC",$1))/e' run_*/

Grazie per i dettagli! Sto provando a provarlo con l' -nopzione, ma mi sta dicendo che è un'opzione non valida - le informazioni sulla versione mi danno rename from util-linux 2.23.2quindi non sono sicuro che sia la stessa funzione
Phill

3
ecco perché ho specificato la versione perlrename dell'utility. util-linux's renameè molto diverso, molto meno in grado, e le opzioni della riga di comando sono incompatibili. se stai eseguendo debian o simili, prova a installare il file-renamepacchetto. altrimenti installa il pacchetto appropriato per la tua distribuzione. potrebbe essere già installato, provare a eseguirlo prenameo file-renamesemplicemente rename.
Cas

Sì, ho pensato che fosse il caso. Vedrò se riesco a far funzionare uno di quelli. Grazie ancora per il tempo dedicato ad aiutarmi!
Phill,

11

E immagino per curiosità, come diamine è successo in primo luogo?

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

dove sp.run_numberera un numero intero. Ho dimenticato di convertirlo in una stringa, ma per qualche motivo in esecuzione mkdir(folder); (in matlab) ancora riuscito.

Quindi, sembrerebbe che mkdir([...])in Matlab concatena i membri dell'array per creare il nome file come stringa. Ma invece gli hai dato un numero, e i numeri sono ciò che realmente sono i personaggi su un computer. Quindi, quando lo sp.run_numberera 1, ti dava il personaggio con valore 1, e poi il personaggio con valore 2, ecc.

Questi sono personaggi di controllo, non hanno simboli stampabili e stamparli su un terminale avrebbe altre conseguenze. Quindi, invece, sono spesso rappresentati da diversi tipi di escape: \001(ottale), \x01(esadecimale), ^Asono tutte rappresentazioni comuni per il personaggio con valore 1. Il carattere con valore zero è un po 'diverso, è il byte NUL che viene utilizzato per contrassegnare la fine di una stringa in C e nelle chiamate di sistema Unix.

Se avessi superato 31, inizieresti a vedere caratteri stampabili, 32 è spazio (non molto visibile però), 33 = !, 34 = "ecc.

Così,

  • run_ run_^A/ run_^B/- Il primo run_corrisponde a quello con zero byte, la stringa finisce lì. Gli altri mostrano che piace usare la shell per visualizzare i codici di controllo con ^A. La notazione suggerisce anche che il carattere con valore numerico 1 può essere inserito come Ctrl-A, anche se è necessario dire alla shell di interpretare non come un carattere di controllo, ma come un valore letterale, Ctrl-V Ctrl-Aalmeno in Bash.

  • ls: run_ run_? run_?- lsnon ama stampare caratteri non stampabili sul terminale, li sostituisce con punti interrogativi.

  • rsync: run_\#003/- quello è nuovo per me, ma l'idea è la stessa, la barra rovesciata segna una via di fuga, e il resto è il valore numerico del personaggio. Mi sembra che il numero qui sia in ottale, come nel più comune \003.

  • usando il comando ls | LC_ALL=C sed -n l... run_\006$ run_\a$ run_\b$ run_\t$- \a, \be \tsono C escape per rispettivamente allarme (campana), backspace e tab. Hanno i valori numerici 7, 8 e 9, quindi dovrebbe essere chiaro il motivo per cui vengono dopo \006. L'uso di tali escape C è un altro modo per contrassegnare i caratteri di controllo. I segni del dollaro finale segnano la fine della linea.

Per quanto riguarda cd, supponendo che le mie assunzioni siano giuste, cd run_dovrebbe andare in quella singola directory senza un carattere trailing strano e cd run_?dovrebbe dare un errore poiché il punto interrogativo è un carattere glob che corrisponde a qualsiasi singolo carattere e ci sono più nomi di file corrispondenti, ma cdsolo se ne aspetta uno.

Quale di queste opzioni è la rappresentazione corretta della cartella?

Tutti, in un certo senso ...

In Bash, puoi usare le lettere \000e \x00escape tra $'...'virgolette per rappresentare i caratteri speciali, quindi $'run_\033(ottale) o $'run_\x1b'corrispondere alla directory con il valore del carattere 27 (che sembra essere ESC). (Non credo che Bash supporti le escape con numeri decimali.)

la risposta di cas ha uno script per rinominare quelli, quindi non ci andrò.


Se è GNU ls, ci sono alcune opzioni di quotazione tra cui -b/ --escapee --quoting-style=, o la QUOTING_STYLEvariabile d'ambiente, per controllare come vengono visualizzati i caratteri non stampabili. Non penso che ci sia un'opzione per far sì che preferisca le fughe ottali rispetto alle versioni dei personaggi.
Toby Speight,

3

Il più semplice sarebbe creare il nome file errato e il nome file corretto nello stesso ambiente in cui si è verificato l'incidente, quindi spostare / rinominare le cartelle con i nomi corretti.

Per evitare collisioni tra nomi esistenti, utilizzare un'altra cartella di destinazione.

./saveLocationA/wrongname1 -> ./saveLocationB/correctname1
./saveLocationA/wrongname2 -> ./saveLocationB/correctname2
./saveLocationA/wrongname3 -> ./saveLocationB/correctname3

Se possibile, preferirei correggere lo script ed eseguirlo di nuovo; correggere alcuni strani bug post mortem probabilmente costa di più e può introdurre nuovi problemi.

In bocca al lupo!

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.