Andere Antworten haben einen der beiden Hauptaspekte dieser Frage angesprochen: die Frage, wie der von Ihnen benötigte Umbenennungsvorgang erfolgreich ausgeführt werden kann. Der Zweck dieser Antwort ist zu erklären, warum Ihre Befehle nicht funktionierten, einschließlich der Bedeutung dieser seltsamen Fehlermeldung "Bareword nicht erlaubt" im Kontext des rename
Befehls.
Der erste Abschnitt dieser Antwort befasst sich mit der Beziehung zwischen rename
und Perl und der rename
Verwendung des ersten Befehlszeilenarguments, das Sie übergeben, nämlich des Codearguments. Im zweiten Abschnitt geht es darum, wie die Shell Erweiterungen - insbesondere Globbing - ausführt, um eine Argumentliste zu erstellen. Der dritte Abschnitt befasst sich mit den Vorgängen im Perl-Code, der Fehler "Bareword nicht erlaubt" enthält. Schließlich enthält der vierte Abschnitt eine Zusammenfassung aller Schritte, die zwischen der Eingabe des Befehls und dem Abrufen des Fehlers ausgeführt werden.
1. Wenn rename
Sie seltsame Fehlermeldungen erhalten, fügen Sie Ihrer Suche "Perl" hinzu.
In Debian und Ubuntu ist der rename
Befehl ein Perl- Skript, das das Umbenennen von Dateien durchführt. Bei älteren Versionen - einschließlich 14.04 LTS, das zum jetzigen Zeitpunkt noch unterstützt wird - war dies ein symbolischer Link , der ( indirekt ) auf den prename
Befehl verweist . In neueren Versionen verweist es stattdessen auf den neueren file-rename
Befehl. Diese beiden Perl-Umbenennungsbefehle funktionieren größtenteils auf die gleiche Weise, und ich beziehe mich nur auf beide, wie rename
für den Rest dieser Antwort.
Wenn Sie den rename
Befehl verwenden, führen Sie nicht nur Perl-Code aus, den jemand anderes geschrieben hat. Sie schreiben auch Ihren eigenen Perl-Code und fordern ihn rename
auf, ihn auszuführen. Dies liegt daran, dass das erste Befehlszeilenargument, das Sie an den rename
Befehl übergeben, außer Optionsargumenten wie -n
, aus tatsächlichem Perl-Code besteht . Der rename
Befehl verwendet diesen Code, um jeden der Pfadnamen zu verarbeiten , die Sie als nachfolgende Befehlszeilenargumente übergeben. (Wenn Sie keine Pfadnamenargumente übergeben, werden stattdessen rename
Pfadnamen aus der Standardeingabe gelesen , einer pro Zeile.)
Der Code ist im Innern läuft eine Schleife , die iteriert einmal pro Pfad. Am Anfang jeder Iteration der Schleife wird der speziellen $_
Variablen vor der Ausführung Ihres Codes der Pfadname zugewiesen, der gerade verarbeitet wird. Wenn Ihr Code bewirkt, dass der Wert von $_
in etwas anderes geändert wird, wird diese Datei umbenannt, um den neuen Namen zu erhalten.
Viele Ausdrücke in Perl arbeiten implizit mit der $_
Variablen, wenn ihnen kein anderer Ausdruck zur Verwendung als Operand zugewiesen wird . Zum Beispiel kann der Substitutionsausdruck $str =~ s/foo/bar/
ändert das erste Auftreten foo
in der Zeichenfolge durch den gehaltenen $str
variable an bar
, oder lässt sie unverändert , wenn es nicht enthält foo
. Wenn Sie nur schreiben, s/foo/bar/
ohne den =~
Operator explizit zu verwenden , wird er ausgeführt $_
. Das heißt, das s/foo/bar/
ist die Abkürzung für $_ =~ s/foo/bar/
.
Es ist üblich , passieren einen s///
Ausdruck zu rename
als Code Argument (dh der erste Befehlszeilenargument), aber Sie nicht müssen. Sie können ihm einen beliebigen Perl-Code geben, damit er innerhalb der Schleife ausgeführt wird, um jeden Wert zu untersuchen $_
und (bedingt) zu ändern.
Dies hat viele coole und nützliche Konsequenzen , aber die überwiegende Mehrheit von ihnen geht weit über den Rahmen dieser Frage und Antwort hinaus. Der Hauptgrund, warum ich dies hier anspreche - in der Tat der Hauptgrund, warum ich mich dazu entschlossen habe, diese Antwort zu veröffentlichen - ist, darauf hinzuweisen, dass, da das erste Argument rename
tatsächlich Perl-Code ist, jedes Mal, wenn Sie eine seltsame Fehlermeldung erhalten und Sie Wenn Sie Probleme haben, Informationen zu finden, indem Sie suchen, können Sie der Suchzeichenfolge "Perl" hinzufügen (oder manchmal sogar "Umbenennen" durch "Perl" ersetzen), und Sie werden häufig eine Antwort finden.
2. Mit rename *.DAT *.dat
hat der rename
Befehl nie gesehen *.DAT
!
Ein Befehl wie wird rename s/foo/bar/ *.txt
normalerweise nicht *.txt
als Befehlszeilenargument an das rename
Programm übergeben, und Sie möchten dies nicht, es sei denn, Sie haben eine Datei, deren Name buchstäblich lautet *.txt
, was Sie hoffentlich nicht tun.
rename
nicht interpretieren glob Muster mögen *.txt
, *.DAT
, *.dat
, x*
, *y
, oder , *
wenn sie es als Pfadname Argumente übergeben. Stattdessen führt Ihre Shell eine Pfadnamenerweiterung für sie durch (die auch als Dateinamenerweiterung und auch als Globbing bezeichnet wird). Dies geschieht, bevor das rename
Dienstprogramm ausgeführt wird. Die Shell erweitert Globs in potenziell mehrere Pfadnamen und übergibt sie alle als separate Befehlszeilenargumente an rename
. In Ubuntu ist Ihre interaktive Shell Bash , es sei denn, Sie haben sie geändert. Deshalb habe ich oben auf das Bash-Referenzhandbuch verwiesen .
Es gibt eine Situation, in der ein Glob-Muster als einzelnes nicht erweitertes Befehlszeilenargument übergeben werden kann rename
: Wenn es keinen Dateien entspricht. Unterschiedliche Shells weisen in dieser Situation ein unterschiedliches Standardverhalten auf, aber Bashs Standardverhalten besteht darin, den Glob einfach buchstäblich zu übergeben. Das wollen Sie aber selten! Wenn Sie es wollten, sollten Sie sicherstellen, dass das Muster nicht erweitert wird, indem Sie es zitieren . Dies gilt für die Übergabe von Argumenten an einen Befehl, nicht nur an rename
.
Das Zitieren dient nicht nur zum Globbing (Dateinamenerweiterung), da Ihre Shell andere Erweiterungen für nicht zitierten Text und für einige von ihnen, aber nicht für andere , auch für in "
"
Anführungszeichen eingeschlossenen Text ausführt . Wenn Sie ein Argument übergeben möchten, das Zeichen enthält, die von der Shell speziell behandelt werden können, einschließlich Leerzeichen, sollten Sie es im Allgemeinen in Anführungszeichen setzen, vorzugsweise in '
'
Anführungszeichen .
Der Perl-Code s/foo/bar/
enthält nichts, was speziell von der Shell behandelt wird, aber es wäre eine gute Idee für mich gewesen, das auch zu zitieren - und zu schreiben 's/foo/bar/'
. (In der Tat, der einzige Grund , warum ich tat , war nicht , dass es für einige Leser wäre verwirrend, da ich über zitierte noch nicht gesprochen hatte.) Der Grund sagen , dass ich dies wäre gut gewesen ist , weil es sehr häufig ist , dass Perl - Code nicht enthalten Solche Zeichen, und wenn ich diesen Code ändern würde, könnte ich nicht daran denken, zu überprüfen, ob ein Zitat erforderlich ist. Wenn Sie dagegen möchten, dass die Shell einen Glob erweitert, darf dieser nicht in Anführungszeichen gesetzt werden.
3. Was der Perl-Interpreter unter "Barwort nicht erlaubt" versteht
Die Fehlermeldungen, die Sie in Ihrer Frage angezeigt haben, zeigen, dass rename *.DAT *.dat
Ihre Shell beim Ausführen *.DAT
zu einer Liste mit einem oder mehreren Dateinamen erweitert wurde und dass der erste dieser Dateinamen war b1.DAT
. Alle nachfolgenden Argumente - sowohl alle anderen *.DAT
als auch alle erweiterten Argumente - *.dat
kamen nach diesem Argument, sodass sie als Pfadnamen interpretiert worden wären.
Da das, was tatsächlich ausgeführt wurde, ungefähr so rename b1.DAT ...
war und rename
das erste Argument ohne Option als Perl-Code behandelt wird, stellt sich die Frage: Warum werden b1.DAT
diese Fehler "Bareword nicht zulässig" erzeugt, wenn Sie es als Perl-Code ausführen?
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 einer Shell zitieren wir unsere Zeichenfolgen , um sie vor unbeabsichtigten Shell-Erweiterungen zu schützen, die sie sonst automatisch in andere Zeichenfolgen umwandeln würden (siehe Abschnitt oben). Shells sind spezielle Programmiersprachen, die ganz anders funktionieren als Allzwecksprachen (und ihre sehr seltsame Syntax und Semantik spiegeln dies wider). Perl ist jedoch eine universelle Programmiersprache, und wie die meisten universellen Programmiersprachen besteht der Hauptzweck des Zitierens in Perl nicht darin , Zeichenfolgen zu schützen , sondern sie überhaupt zu erwähnen. Auf diese Weise ähneln die meisten Programmiersprachen der natürlichen Sprache. Auf Englisch und wenn Sie einen Hund haben, ist "Ihr Hund" eine Zwei-Wort-Phrase, während Ihr Hund ein Hund ist. In ähnlicher Weise ist in Perl '$foo'
eine Zeichenfolge, während $foo
es sich um etwas handelt, dessen Name lautet $foo
.
Doch im Gegensatz zu fast all anderen Allzweck-Programmiersprache, wird Perl auch manchmal nicht notierten Text interpretieren als erwähnen einen String - eine Zeichenfolge , die die „gleiche“ wie es ist, in dem Sinne , dass es in den gleichen Zeichen aufgebaut ist die gleiche Reihenfolge. Es wird nur dann versucht, Code so zu interpretieren, wenn es sich um ein Barwort handelt (kein $
oder ein anderes Siegel, siehe unten) und nachdem es keine andere Bedeutung gefunden hat, um es zu geben. Dann wird es als Zeichenfolge verwendet, es sei denn, Sie weisen es an, indem Sie Einschränkungen aktivieren .
Variablen in Perl beginnen normalerweise mit einem Interpunktionszeichen, das als Siegel bezeichnet wird und den allgemeinen Typ der Variablen angibt. Zum Beispiel $
bedeutet Skalar , @
Mittel Array und %
mittels Hash . ( Es gibt andere. ) Machen Sie sich keine Sorgen, wenn Sie dies verwirrend (oder langweilig) finden, denn ich spreche es nur an, um zu sagen, dass, wenn ein gültiger Name in einem Perl-Programm erscheint, aber kein Siegel vorangestellt ist, dieser Name soll ein Barwort sein .
Barwörter dienen verschiedenen Zwecken, bezeichnen jedoch normalerweise eine integrierte Funktion oder eine benutzerdefinierte Unterroutine , die im Programm (oder in einem vom Programm verwendeten Modul) definiert wurde. Perl hat keine Funktionen in integrierten genannt b1
oder DAT
, also , wenn der Perl - Interpreter den Code sieht b1.DAT
, versucht sie zu behandeln b1
und DAT
wie die Namen von Subroutinen. Vorausgesetzt, es wurden keine solchen Unterprogramme definiert, schlägt dies fehl. Sofern Einschränkungen nicht aktiviert wurden, werden sie als Zeichenfolgen behandelt. Dies wird funktionieren, aber ob Sie dies tatsächlich beabsichtigt haben oder nicht , ist unklar. Der Perl- .
Operator verkettet Zeichenfolgen und b1.DAT
wertet sie daher als Zeichenfolge ausb1DAT
. Das heißt, b1.DAT
ist ein schlechter Weg, um so etwas wie 'b1' . 'DAT'
oder zu schreiben "b1" . "DAT"
.
Sie können dies selbst testen, indem Sie den Befehl ausführen perl -E 'say b1.DAT'
, der das kurze Perl-Skript say b1.DAT
an den Perl-Interpreter übergibt , der es druckt b1DAT
. (In diesem Befehl wird die '
'
Anführungszeichen sagen dem Shell übergeben say b1.DAT
als ein einziges Befehlszeilenargument, andernfalls würde der Raum verursacht say
und b1.DAT
wird als getrennte Worte analysiert und perl
sich als separate Argumente erhalten würde. perl
Hat nicht die Anführungszeichen selbst sehen, wie die Shell entfernt sie .)
Versuchen Sieuse strict;
jetzt, vorher im Perl-Skript zu schreibensay
. Jetzt schlägt es mit der gleichen Art von Fehler fehl, die Sie erhalten haben 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.
Dies geschah, weil use strict;
der Perl-Interpreter Barewords nicht als Zeichenfolgen behandeln durfte. Um dieses spezielle Merkmal zu verbieten, würde es wirklich ausreichen, nur die subs
Einschränkung zu aktivieren . Dieser Befehl erzeugt die gleichen Fehler wie oben:
perl -E 'use strict "subs"; say b1.DAT'
Aber normalerweise schreiben Perl-Programmierer nur use strict;
, was die subs
Einschränkung und zwei andere ermöglicht. use strict;
wird allgemein empfohlen. Der rename
Befehl erledigt dies also für Ihren Code. Deshalb erhalten Sie diese Fehlermeldung.
4. Zusammenfassend ist Folgendes passiert:
- Ihre Shell wurde
b1.DAT
als erstes Befehlszeilenargument übergeben, das rename
als Perl-Code behandelt wurde , der für jedes Pfadnamenargument in einer Schleife ausgeführt wird.
- Dies wurde so verstanden ,
b1
und DAT
mit dem angeschlossenen .
Betreiber.
b1
und DAT
wurden nicht mit Siegeln vorangestellt, so dass sie als Barwörter behandelt wurden.
- Diese beiden Barwörter wären als Namen von integrierten Funktionen oder benutzerdefinierten Unterprogrammen verwendet worden, aber keiner dieser Namen hatte einen dieser Namen.
- Wenn "strenge Subs" nicht aktiviert worden wären, wären sie wie die Zeichenfolgenausdrücke
'b1'
und 'DAT
'behandelt und verkettet worden. Das ist weit von dem entfernt, was Sie beabsichtigt haben, was zeigt, dass diese Funktion oft nicht hilfreich ist.
- Aber „strict subs“ wurde aktiviert, weil
rename
alle ermöglicht Einschränkungen ( vars
, refs
, und subs
). Daher haben Sie stattdessen einen Fehler erhalten.
rename
Beenden Sie aufgrund dieses Fehlers. Da diese Art von Fehler früh auftrat, wurden keine Versuche zum Umbenennen von Dateien unternommen, obwohl Sie nicht bestanden hatten -n
. Dies ist eine gute Sache, die Benutzer häufig vor unbeabsichtigten Dateinamenänderungen und gelegentlich sogar vor tatsächlichem Datenverlust schützt.
Vielen Dank an Zanna , die mir geholfen hat, einige wichtige Mängel in einem besseren Entwurf dieser Antwort zu beheben . Ohne sie hätte diese Antwort viel weniger Sinn ergeben und könnte überhaupt nicht veröffentlicht werden.