Altre risposte hanno affrontato uno dei due aspetti principali di questa domanda: quello di come eseguire con successo l'operazione di ridenominazione necessaria. Lo scopo di questa risposta è spiegare perché i tuoi comandi non hanno funzionato, incluso il significato di quello strano messaggio di errore "password non consentita" nel contesto del rename
comando.
La prima sezione di questa risposta riguarda la relazione tra rename
e Perl e il modo in cui rename
utilizza il primo argomento della riga di comando che viene passato, ovvero l'argomento codice. La seconda sezione riguarda il modo in cui la shell esegue espansioni - in particolare globbing - per costruire un elenco di argomenti. La terza sezione riguarda ciò che sta accadendo nel codice Perl che genera errori "Bareword non consentito". Infine, la quarta sezione è un riepilogo di tutti i passaggi che avvengono tra l'immissione del comando e il recupero dell'errore.
1. Quando rename
ti danno strani messaggi di errore, aggiungi "Perl" alla tua ricerca.
In Debian e Ubuntu, il rename
comando è uno script Perl che esegue la ridenominazione dei file. Nelle versioni precedenti, tra cui 14.04 LTS, che è ancora supportato al momento della stesura di questo documento, si trattava di un collegamento simbolico che puntava ( indirettamente ) al prename
comando. Nelle versioni più recenti, punta invece al file-rename
comando più recente . Quei due comandi di rinomina Perl funzionano principalmente allo stesso modo, e farò riferimento a entrambi come rename
per il resto di questa risposta.
Quando usi il rename
comando, non stai solo eseguendo il codice Perl scritto da qualcun altro. Stai anche scrivendo il tuo codice Perl e stai dicendo rename
di eseguirlo. Questo perché il primo argomento della riga di comando che passi al rename
comando, diverso dagli argomenti di opzione come -n
, è costituito dal codice Perl effettivo . Il rename
comando utilizza questo codice per operare su ciascuno dei nomi di percorso che viene passato come successivo argomento della riga di comando. (Se non passi alcun argomento sul nome percorso, rename
legge invece i nomi percorso dall'input standard , uno per riga.)
Il codice viene eseguito all'interno di un ciclo , che viene ripetuto una volta per percorso. Nella parte superiore di ogni iterazione del ciclo, prima dell'esecuzione del codice, alla $_
variabile speciale viene assegnato il nome percorso attualmente in fase di elaborazione. Se il tuo codice fa sì che il valore di $_
venga cambiato in qualcos'altro, quel file viene rinominato con il nuovo nome.
Molte espressioni in Perl operano implicitamente sulla $_
variabile quando non hanno altre espressioni da usare come operando . Ad esempio, l'espressione sostituzione $str =~ s/foo/bar/
cambia la prima occorrenza foo
nella stringa detenuto dalla $str
variabile a bar
, o foglie inalterata se non contiene foo
. Se scrivi semplicemente s/foo/bar/
senza usare esplicitamente l' =~
operatore , allora funziona $_
. Questo per dire che s/foo/bar/
è l'abbreviazione di $_ =~ s/foo/bar/
.
E 'comune per passare un'espressione di come l'argomento di codice (ad esempio, il primo argomento della riga di comando), ma non è necessario. Puoi dargli qualsiasi codice Perl che desideri venga eseguito all'interno del ciclo, per esaminare ogni valore e (condizionatamente) modificarlo.s///
rename
$_
Ciò ha molte conseguenze interessanti e utili , ma la stragrande maggioranza di esse va ben oltre lo scopo di questa domanda e risposta. Il motivo principale per cui lo mostro qui - in effetti, il motivo principale per cui ho deciso di pubblicare questa risposta - è quello di sottolineare che, poiché il primo argomento rename
è il codice Perl, ogni volta che ricevi un messaggio di errore strano e tu hai difficoltà a trovare informazioni a riguardo cercando, puoi aggiungere "Perl" alla stringa di ricerca (o persino sostituire "rinominare" con "Perl", a volte) e spesso troverai una risposta.
2. Con rename *.DAT *.dat
, il rename
comando non ha mai visto *.DAT
!
Un comando come in rename s/foo/bar/ *.txt
genere non passa *.txt
come argomento della riga di comando al rename
programma e non lo si desidera, a meno che non si disponga di un file il cui nome è letteralmente *.txt
, cosa che si spera non sia possibile.
rename
non interpreta i modelli glob piace *.txt
, *.DAT
, *.dat
, x*
, *y
, o *
quando passa ad esso come argomenti del percorso. Invece, la tua shell esegue l'espansione del nome del percorso su di essi (che è anche chiamato espansione del nome file e anche chiamato globbing). Ciò accade prima che rename
venga eseguita l' utilità. La shell espande i globs in percorsi potenzialmente multipli e li passa tutti, come argomenti della riga di comando separati, a rename
. In Ubuntu, la tua shell interattiva è Bash , a meno che tu non l'abbia modificata, motivo per cui ho collegato il manuale di riferimento di Bash sopra.
Esiste una situazione in cui un modello glob può essere passato come singolo argomento della riga di comando non espanso a rename
: quando non corrisponde a nessun file. Diverse shell mostrano un comportamento predefinito diverso in questa situazione, ma il comportamento predefinito di Bash è semplicemente quello di passare letteralmente il globo. Tuttavia, raramente lo desideri! Se lo volevi, dovresti assicurarti che il modello non sia espanso, citandolo . Questo vale per passare argomenti a qualsiasi comando, non solo a rename
.
La citazione non è solo per globbing (espansione del nome del file), perché ci sono altre espansioni che la tua shell esegue sul testo non quotato e, per alcuni di essi ma non altri , anche sul testo racchiuso tra "
"
virgolette. In generale, ogni volta che si desidera passare un argomento che contiene caratteri che possono essere trattati in modo speciale dalla shell, inclusi gli spazi, è necessario citarlo, preferibilmente tra '
'
virgolette .
Il codice Perl s/foo/bar/
non contiene nulla trattato in modo speciale dalla shell, ma sarebbe stata una buona idea anche per me averlo citato e scritto 's/foo/bar/'
. (In realtà, l'unico motivo che ho fatto non era che sarebbe fonte di confusione per alcuni lettori, come io non avevo ancora parlato citando.) Il motivo per cui dico questo sarebbe stato buono è perché è molto comune che il codice Perl non contiene tali personaggi, e se dovessi cambiare quel codice, potrei non ricordare di verificare se fosse necessario un preventivo. Al contrario, se si desidera che il guscio di espandersi in un glob, deve non essere citato.
3. Cosa intende l'interprete Perl con "password non consentita"
I messaggi di errore che hai mostrato nella tua domanda rivelano che, quando hai eseguito rename *.DAT *.dat
, la tua shell si è espansa *.DAT
in un elenco di uno o più nomi di file e che il primo di quei nomi di file era b1.DAT
. Tutti gli argomenti successivi, sia quelli espansi *.DAT
che quelli espansi, sono *.dat
arrivati dopo quell'argomento, quindi sarebbero stati interpretati come nomi di percorso.
Perché ciò che è stato effettivamente eseguito è stato qualcosa di simile rename b1.DAT ...
e perché rename
considera il suo primo argomento non opzionale come codice Perl, la domanda diventa: perché b1.DAT
produce questi errori "non consentiti" quando lo esegui come codice Perl?
Bareword "b1" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
In una shell, citiamo le nostre stringhe per proteggerle da espansioni involontarie della shell che altrimenti le trasformerebbero automaticamente in altre stringhe (vedere la sezione sopra). Le shell sono linguaggi di programmazione per scopi speciali che funzionano in modo molto diverso dai linguaggi di uso generale (e la loro strana sintassi e semantica lo riflettono). Ma Perl è un linguaggio di programmazione generico e, come la maggior parte dei linguaggi di programmazione generici, lo scopo principale di citare in Perl non è proteggere le stringhe, ma menzionarle affatto. Questo è in realtà un modo in cui la maggior parte dei linguaggi di programmazione sono simili al linguaggio naturale. In inglese, e supponendo che tu abbia un cane, "il tuo cane" è una frase di due parole, mentre il tuo cane è un cane. Allo stesso modo, in Perl, '$foo'
è una stringa, mentre $foo
è qualcosa il cui nome è $foo
.
Tuttavia, a differenza di quasi tutti gli altri linguaggi di programmazione general-purpose, Perl anche a volte interpretare il testo non quotate come citano una stringa - una stringa che è la "stessa", come, nel senso che si compone degli stessi personaggi in lo stesso ordine. Tenterà di interpretare il codice in questo modo solo se si tratta di una parola nuda (no $
o altro sigillo, vedi sotto), e dopo non riuscirà a trovare nessun altro significato per dargli. Quindi lo prenderà come una stringa, a meno che tu non lo dica abilitando le restrizioni .
Le variabili in Perl in genere iniziano con un carattere di punteggiatura chiamato sigillo , che specifica il tipo ampio della variabile. Ad esempio, $
significa scalare , @
significa array e %
significa hash . ( Ce ne sono altri. ) Non preoccuparti se lo trovi confuso (o noioso), perché lo sto solo sollevando per dire che quando un nome valido appare in un programma Perl ma non è preceduto da un sigillo, quel nome si dice che sia una parola nuda .
Le parole chiave servono a vari scopi, ma di solito indicano una funzione integrata o una subroutine definita dall'utente che è stata definita nel programma (o in un modulo utilizzato dal programma). Perl non ha funzioni integrate chiamate b1
o DAT
, quindi quando l'interprete Perl vede il codice b1.DAT
, cerca di trattare b1
e DAT
come nomi di subroutine. Supponendo che non siano state definite tali subroutine, ciò fallisce. Quindi, a condizione che le restrizioni non siano state abilitate, le tratta come stringhe. Funzionerà, anche se la tua intenzione è reale o meno . L' .
operatore di Perl concatena le stringhe , quindi b1.DAT
valuta la stringab1DAT
. Cioè, b1.DAT
è un brutto modo di scrivere qualcosa di simile 'b1' . 'DAT'
o "b1" . "DAT"
.
Puoi provarlo tu stesso eseguendo il comando perl -E 'say b1.DAT'
, che passa il breve script say b1.DAT
Perl all'interprete Perl, che lo esegue, stampandolo b1DAT
. (In questo comando, le '
'
citazioni dicono guscio di passare say b1.DAT
come un unico argomento della riga di comando, altrimenti lo spazio causerebbe say
e b1.DAT
viene analizzato come parole separate e perl
li riceverebbe come argomenti separati. perl
Non non vedere le citazioni stessi, come la shell li rimuove .)
Ma ora, prova a scrivere primause strict;
nello script Perl say
. Ora fallisce con lo stesso tipo di errore che hai ricevuto rename
:
$ perl -E 'use strict; say b1.DAT'
Bareword "b1" not allowed while "strict subs" in use at -e line 1.
Bareword "DAT" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
Ciò è accaduto perché use strict;
vietava all'interprete Perl di trattare le parole d'ordine come stringhe. Per proibire questa particolare funzionalità, sarebbe davvero sufficiente abilitare solo la subs
restrizione. Questo comando produce gli stessi errori di cui sopra:
perl -E 'use strict "subs"; say b1.DAT'
Ma di solito i programmatori Perl scriveranno semplicemente use strict;
, il che abilita la subs
limitazione e altri due. use strict;
è generalmente una pratica raccomandata. Quindi il rename
comando fa questo per il tuo codice. Ecco perché ricevi quel messaggio di errore.
4. In sintesi, ecco cosa è successo:
- La shell è passata
b1.DAT
come primo argomento della riga di comando, che ha funzionato rename
come codice Perl da eseguire in un ciclo per ogni argomento del percorso.
- Questo è stato preso per significare
b1
e DAT
collegato con l' .
operatore.
b1
e DAT
non erano preceduti da sigilli, quindi venivano trattati come parole spoglie.
- Queste due parole nude sarebbero state prese come nomi di funzioni integrate o di subroutine definite dall'utente, ma nessuna di queste cose aveva uno di quei nomi.
- Se i "sottotitoli rigidi" non fossero stati abilitati, sarebbero stati trattati come le espressioni di stringa
'b1'
e 'DAT
'e concatenati. È lontano da ciò che intendevi, il che chiarisce come questa funzione spesso non sia utile.
- Ma "subs severe" è stata attivata, in quanto
rename
consente a tutti le restrizioni ( vars
, refs
, e subs
). Pertanto, hai ricevuto invece un errore.
rename
chiuso a causa di questo errore. Poiché questo tipo di errore si è verificato in anticipo, non è stato effettuato alcun tentativo di ridenominazione dei file, anche se non è stato superato -n
. Questa è una buona cosa, che spesso protegge gli utenti da modifiche involontarie al nome del file e occasionalmente anche dall'effettiva perdita di dati.
Grazie a Zanna , che mi ha aiutato a risolvere alcune importanti carenze in una bozza più accattivante di questa risposta . Senza di lei, questa risposta avrebbe avuto molto meno senso e potrebbe non essere pubblicata affatto.