Ich habe zwei Dateien in einem Ordner auf meinem Ubuntu 16.04:
a1.dat
b1.DAT
Ich möchte in umbenennen b1.DAT
, b1.dat
damit ich folgende Dateien im Ordner habe:
a1.dat
b1.dat
Ich habe es versucht (erfolglos):
$ rename *.DAT *.dat
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).
und
$ find . -iname "*.DAT" -exec rename DAT dat '{}' \;
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
Die Suche danach ergab keine sinnvolle Lösung ...
Antworten:
Dieser Fehler scheint von Perl zu stammen
rename
. Sie müssen Anführungszeichen verwenden, aber Sie müssen nur den Teil angeben, den Sie ändern möchten, den Stil suchen und ersetzen. Die Syntax lautet wie folgt:-n
Nach dem Testen entfernen , um die Dateien tatsächlich umzubenennen.Um versteckte Dateien einzuschließen, ändern Sie die Glob-Einstellung, bevor Sie den Befehl ausführen:
Wenn Sie Dateien rekursiv umbenennen möchten, können Sie verwenden
Wenn sich im oder unter dem aktuellen Verzeichnis viele Pfade befinden, die nicht mit enden
.DAT
, sollten Sie diese Pfade im zweiten Befehl angeben:Dies ist schneller, wenn Ihre Dateien verschiedene Namen haben, die nicht auf enden
.DAT
. [1]Zum Deaktivieren dieser Einstellungen können Sie
shopt -u
z. B. verwendenshopt -u globstar
, diese sind jedoch standardmäßig deaktiviert und werden deaktiviert, wenn Sie eine neue Shell öffnen.Wenn dies zu einer zu langen Argumentliste führt, können Sie beispielsweise Folgendes verwenden
find
:oder besser
Die Verwendung
find ... -exec
mit+
ist schneller als die Verwendung,\;
da aus den gefundenen Dateien eine Argumentliste erstellt wird. Ursprünglich dachte ich, dass Sie es nicht verwenden können, weil Sie erwähnt haben, dass Sie einargument list too long
Problem haben, aber jetzt weiß ich, dass die Liste bei Bedarf auch geschickt in mehrere Aufrufe des Befehls unterteilt wird, um dieses Problem zu vermeiden [2] .Da
rename
jeder Dateiname auf dieselbe Weise verarbeitet wird, spielt es keine Rolle, wie lang die Argumentliste ist, da sie sicher auf mehrere Aufrufe aufgeteilt werden kann. Wenn der Befehl, mit dem Sie arbeiten,-exec
nicht mehrere Argumente akzeptiert oder erfordert, dass seine Argumente in einer bestimmten Reihenfolge vorliegen, oder wenn aus einem anderen Grund das Aufteilen der Argumentliste zu unerwünschten Ereignissen führt, können Sie\;
den Befehl einmal aufrufen für jede gefundene Datei (wenn die Argumentliste für andere Methoden zu lang war, dauert dies lange!).Vielen Dank an Eliah Kagan für die sehr nützlichen Vorschläge zur Verbesserung dieser Antwort:
[1] Angabe der Dateinamen beim Globbing .
[2]
find ... -exec
mit+
teilt die Argumentliste auf .quelle
-n
Umbenennung nach dem Testen entfernen - es ist nur zu zeigen, was geändert wirdDu kannst tun:
Drop
-n
für die eigentliche Umbenennung.Das Glob-Muster
*.DAT
stimmt mit allen Dateien überein,.DAT
die im aktuellen Verzeichnis endenin der
rename
Auswechslung derDAT$
SpieleDAT
am Ende\L$&
macht das ganze Match klein;$&
bezieht sich auf das ganze SpielWenn Sie nur tun möchten für
b1.DAT
:Beispiel:
quelle
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 derrename
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 denprename
Befehl verweist . In neueren Versionen verweist es stattdessen auf den neuerenfile-rename
Befehl. Diese beiden Perl-Umbenennungsbefehle funktionieren größtenteils auf die gleiche Weise, und ich beziehe mich nur auf beide, wierename
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 ihnrename
auf, ihn auszuführen. Dies liegt daran, dass das erste Befehlszeilenargument, das Sie an denrename
Befehl übergeben, außer Optionsargumenten wie-n
, aus tatsächlichem Perl-Code besteht . Derrename
Befehl verwendet diesen Code, um jeden der Pfadnamen zu verarbeiten , die Sie als nachfolgende Befehlszeilenargumente übergeben. (Wenn Sie keine Pfadnamenargumente übergeben, werden stattdessenrename
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 Auftretenfoo
in der Zeichenfolge durch den gehaltenen$str
variable anbar
, oder lässt sie unverändert , wenn es nicht enthältfoo
. Wenn Sie nur schreiben,s/foo/bar/
ohne den=~
Operator explizit zu verwenden , wird er ausgeführt$_
. Das heißt, dass/foo/bar/
ist die Abkürzung für$_ =~ s/foo/bar/
.Es ist üblich , passieren einen
s///
Ausdruck zurename
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 derrename
Befehl nie gesehen*.DAT
!Ein Befehl wie wird
rename s/foo/bar/ *.txt
normalerweise nicht*.txt
als Befehlszeilenargument an dasrename
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 dasrename
Dienstprogramm ausgeführt wird. Die Shell erweitert Globs in potenziell mehrere Pfadnamen und übergibt sie alle als separate Befehlszeilenargumente anrename
. 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 anrename
.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 warb1.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 undrename
das erste Argument ohne Option als Perl-Code behandelt wird, stellt sich die Frage: Warum werdenb1.DAT
diese Fehler "Bareword nicht zulässig" erzeugt, wenn Sie es als Perl-Code ausführen?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
oderDAT
, also , wenn der Perl - Interpreter den Code siehtb1.DAT
, versucht sie zu behandelnb1
undDAT
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 undb1.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-Skriptsay b1.DAT
an den Perl-Interpreter übergibt , der es drucktb1DAT
. (In diesem Befehl wird die'
'
Anführungszeichen sagen dem Shell übergebensay b1.DAT
als ein einziges Befehlszeilenargument, andernfalls würde der Raum verursachtsay
undb1.DAT
wird als getrennte Worte analysiert undperl
sich als separate Argumente erhalten würde.perl
Hat nicht die Anführungszeichen selbst sehen, wie die Shell entfernt sie .)Versuchen Sie
use strict;
jetzt, vorher im Perl-Skript zu schreibensay
. Jetzt schlägt es mit der gleichen Art von Fehler fehl, die Sie erhalten habenrename
: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 diesubs
Einschränkung zu aktivieren . Dieser Befehl erzeugt die gleichen Fehler wie oben:Aber normalerweise schreiben Perl-Programmierer nur
use strict;
, was diesubs
Einschränkung und zwei andere ermöglicht.use strict;
wird allgemein empfohlen. Derrename
Befehl erledigt dies also für Ihren Code. Deshalb erhalten Sie diese Fehlermeldung.4. Zusammenfassend ist Folgendes passiert:
b1.DAT
als erstes Befehlszeilenargument übergeben, dasrename
als Perl-Code behandelt wurde , der für jedes Pfadnamenargument in einer Schleife ausgeführt wird.b1
undDAT
mit dem angeschlossenen.
Betreiber.b1
undDAT
wurden nicht mit Siegeln vorangestellt, so dass sie als Barwörter behandelt wurden.'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.rename
alle ermöglicht Einschränkungen (vars
,refs
, undsubs
). 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.
quelle