J'ai deux fichiers dans un dossier sur mon Ubuntu 16.04:
a1.dat
b1.DAT
Je veux renommer b1.DAT
pour b1.dat
que j'aie les fichiers suivants comme résultat dans le dossier:
a1.dat
b1.dat
J'ai essayé (sans succès):
$ 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).
et
$ 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).
La recherche de ce résultat n'a abouti à aucune solution significative ...
Réponses:
Cette erreur semble provenir de Perl
rename
. Vous devez utiliser des guillemets, mais il vous suffit de spécifier la pièce que vous souhaitez modifier, le style de recherche et de remplacement. La syntaxe est la suivante:Supprimez
-n
après le test pour renommer réellement les fichiers.Pour inclure des fichiers cachés, modifiez le paramètre glob avant d'exécuter la commande:
Si vous souhaitez renommer des fichiers de manière récursive, vous pouvez utiliser
ou s'il y a beaucoup de chemins dans ou en dessous du répertoire courant qui ne se terminent pas par
.DAT
, vous feriez mieux de spécifier ces chemins dans la deuxième commande:Ce sera plus rapide si vos fichiers ont des noms différents qui ne se terminent pas par
.DAT
. [1]Pour désactiver ces paramètres, vous pouvez les utiliser
shopt -u
, par exempleshopt -u globstar
, mais ils sont désactivés par défaut et le seront lorsque vous ouvrirez un nouveau shell.Si cela aboutit à une liste d'arguments excessivement longue, vous pouvez utiliser, par exemple
find
,:ou mieux
L'utilisation
find ... -exec
avec+
est plus rapide que l'utilisation\;
car elle construit une liste d'arguments à partir des fichiers trouvés. À l'origine, je pensais qu'il ne serait pas possible pour vous de l'utiliser, car vous avez mentionné que vous rencontriez unargument list too long
problème, mais maintenant je sais que la liste sera également astucieusement divisée en plusieurs invocations de la commande selon les besoins pour éviter ce problème. [2] .Étant donné
rename
que traitera chaque nom de fichier de la même manière, la longueur de la liste d'arguments n'a pas d'importance car elle peut être divisée en toute sécurité sur plusieurs appels. Si la commande avec laquelle vous utilisez-exec
n'accepte pas plusieurs arguments ou requiert que ses arguments soient dans un ordre particulier ou pour toute autre raison, le fractionnement de la liste d'arguments entraînera quelque chose de indésirable, vous pouvez utiliser\;
, ce qui provoque l'invocation de la commande une fois pour chaque fichier trouvé (si la liste des arguments était trop longue pour d'autres méthodes, cela prendra du temps!).Un grand merci à Eliah Kagan pour les suggestions très utiles pour améliorer cette réponse:
[1] Spécification des noms de fichiers lors de la globalisation .
[2]
find ... -exec
avec+
divise la liste des arguments .la source
-n
de renommer après le test - c'est juste pour montrer ce qui sera changéTu peux faire:
Supprimer
-n
pour que le changement de nom ait lieu.le modèle glob
*.DAT
correspond à tous les fichiers se terminant.DAT
dans le répertoire courantdans la
rename
substitution de,DAT$
matchsDAT
à la fin\L$&
rend le match entier en minuscules;$&
fait référence à l'ensemble du matchSi vous voulez juste faire pour
b1.DAT
:Exemple:
la source
D'autres réponses ont abordé l'un des deux principaux aspects de cette question: celui de savoir comment mener à bien l'opération de changement de nom dont vous aviez besoin. Le but de cette réponse est d'expliquer pourquoi vos commandes n'ont pas fonctionné, y compris la signification de cet étrange message d'erreur "bareword not allowed" dans le contexte de la
rename
commande.La première section de cette réponse concerne la relation entre
rename
et Perl et commentrename
utilise le premier argument de ligne de commande que vous lui transmettez, qui est son argument de code. La deuxième section concerne la façon dont le shell effectue des extensions - en particulier le globbing - pour construire une liste d'arguments. La troisième section concerne ce qui se passe dans le code Perl qui donne des erreurs «Bareword not allowed». Enfin, la quatrième section est un résumé de toutes les étapes qui se déroulent entre la saisie de la commande et l'obtention de l'erreur.1. Lorsque
rename
vous donne des messages d'erreur étranges, ajoutez "Perl" à votre recherche.Dans Debian et Ubuntu, la
rename
commande est un script Perl qui effectue un changement de nom de fichier. Sur les versions antérieures - y compris 14.04 LTS, qui est toujours pris en charge au moment de la rédaction de ce document - c'était un lien symbolique pointant ( indirectement ) vers laprename
commande. Sur les versions plus récentes, il pointe à la place sur la nouvellefile-rename
commande. Ces deux commandes de changement de nom Perl fonctionnent principalement de la même manière, et je vais me référer à elles deux commerename
pour le reste de cette réponse.Lorsque vous utilisez la
rename
commande, vous n'exécutez pas uniquement du code Perl que quelqu'un d'autre a écrit. Vous écrivez également votre propre code Perl et ditesrename
de l'exécuter. Cela est dû au fait que le premier argument de ligne de commande que vous passez à larename
commande, autre que les arguments d'option comme-n
, se compose de code Perl réel . Larename
commande utilise ce code pour opérer sur chacun des chemins d'accès que vous lui transmettez comme arguments de ligne de commande ultérieurs. (Si vous ne passez aucun argument de chemin d'accès, ilrename
lit alors les noms de chemin à partir de l'entrée standard , un par ligne.)Le code est exécuté dans une boucle , qui itère une fois par nom de chemin. En haut de chaque itération de la boucle, avant l'exécution de votre code, la
$_
variable spéciale se voit attribuer le chemin d'accès en cours de traitement. Si votre code entraîne la$_
modification de la valeur de quelque chose d'autre, alors ce fichier est renommé pour avoir le nouveau nom.De nombreuses expressions en Perl opèrent implicitement sur la
$_
variable lorsqu'aucune autre expression ne leur est utilisée comme opérande . Par exemple, l'expression de substitution$str =~ s/foo/bar/
change la première occurrence defoo
dans la chaîne contenue par la$str
variable enbar
, ou la laisse inchangée si elle ne contient pasfoo
. Si vous écrivez simplements/foo/bar/
sans utiliser explicitement l'=~
opérateur , alors il fonctionne$_
. C'est-à-dire ques/foo/bar/
c'est court pour$_ =~ s/foo/bar/
.Il est courant de passer une
s///
expression àrename
comme argument de code (le premier argument de ligne de commande), mais vous ne devez pas. Vous pouvez lui donner n'importe quel code Perl que vous souhaitez qu'il s'exécute à l'intérieur de la boucle, pour examiner chaque valeur de$_
et (conditionnellement) le modifier.Cela a beaucoup de conséquences intéressantes et utiles , mais la grande majorité d'entre elles dépassent largement le cadre de cette question et réponse. La principale raison pour laquelle j'apporte ceci ici - en fait, la principale raison pour laquelle j'ai décidé de poster cette réponse - est de faire valoir que, parce que le premier argument
rename
est en fait du code Perl, chaque fois que vous obtenez un message d'erreur étrange et que vous avoir du mal à trouver des informations à ce sujet en recherchant, vous pouvez ajouter "Perl" à la chaîne de recherche (ou même remplacer "renommer" par "Perl", parfois) et vous trouverez souvent une réponse.2. Avec
rename *.DAT *.dat
, larename
commande n'a jamais vu*.DAT
!Une commande comme
rename s/foo/bar/ *.txt
ne passe généralement pas en*.txt
tant qu'argument de ligne de commande aurename
programme, et vous ne le souhaitez pas , sauf si vous avez un fichier dont le nom est littéralement*.txt
, ce qui, espérons-le, ne vous convient pas.rename
ne pas interpréter les modèles de glob aiment*.txt
,*.DAT
,*.dat
,x*
,*y
ou*
lorsqu'il lui a été transmis comme arguments pathname. Au lieu de cela, votre shell effectue une expansion de nom de chemin sur eux (ce qui est également appelé expansion de nom de fichier et également appelé globbing). Cela se produit avant l'rename
exécution de l' utilitaire. Le shell développe les globs en potentiellement plusieurs chemins d'accès et les transmet tous, en tant qu'arguments de ligne de commande séparés, àrename
. Dans Ubuntu, votre shell interactif est Bash , à moins que vous ne l'ayez modifié, c'est pourquoi je me suis connecté au manuel de référence Bash ci-dessus.Il existe une situation dans laquelle un modèle glob peut être transmis sous la forme d'un seul argument de ligne de commande non développé à
rename
: lorsqu'il ne correspond à aucun fichier. Différents shells présentent un comportement par défaut différent dans cette situation, mais le comportement par défaut de Bash est de simplement passer le glob littéralement. Cependant, vous en avez rarement envie! Si vous le vouliez, vous devez vous assurer que le modèle n'est pas développé, en le citant . Cela vaut pour passer des arguments à n'importe quelle commande, pas seulement àrename
.Les citations ne sont pas uniquement destinées à la globalisation (extension de nom de fichier), car il existe d' autres extensions que votre shell effectue sur du texte non cité et, pour certaines d'entre elles mais pas pour d'autres , également sur du texte entre
"
"
guillemets. En général, chaque fois que vous souhaitez passer un argument contenant des caractères qui peuvent être traités spécialement par le shell, y compris des espaces, vous devez le citer, de préférence avec des'
'
guillemets .Le code Perl
s/foo/bar/
ne contient rien de traité spécialement par le shell, mais cela aurait été une bonne idée pour moi de l'avoir aussi cité - et écrit's/foo/bar/'
. (En fait, la seule raison pour laquelle je ne l' ai pas été qu'il serait source de confusion pour certains lecteurs, comme je l' avais pas encore parlé de citation.) La raison pour laquelle je dis cela aurait été bon est parce qu'il est très fréquent que le code Perl ne contient ces caractères, et si je devais changer ce code, je ne me souviendrais peut-être pas de vérifier si la citation était nécessaire. En revanche, si vous souhaitez que le shell développe un glob, il ne doit pas être cité.3. Ce que l'interprète Perl veut dire par "mots nus non autorisés"
Les messages d'erreur que vous avez montrés dans votre question révèlent que, lorsque vous avez exécuté
rename *.DAT *.dat
, votre shell s'est développé*.DAT
en une liste d'un ou plusieurs noms de fichiers, et que le premier de ces noms de fichiers l'étaitb1.DAT
. Tous les arguments suivants - tous les autres à partir de*.DAT
et tous ceux à partir de - ont été*.dat
développés après cet argument, ils auraient donc été interprétés comme des chemins d'accès.Parce que ce qui s'est réellement exécuté était quelque chose comme
rename b1.DAT ...
, et parce querename
traite son premier argument sans option en tant que code Perl, la question devient: pourquoib1.DAT
produit-il ces erreurs "bareword not allowed" lorsque vous l'exécutez en tant que code Perl?Dans un shell, nous citons nos chaînes pour les protéger contre les extensions de shell involontaires qui autrement les transformeraient automatiquement en d'autres chaînes (voir la section ci-dessus). Les shells sont des langages de programmation à usage spécial qui fonctionnent très différemment des langages à usage général (et leur syntaxe et sémantique très étranges le reflètent). Mais Perl est un langage de programmation à usage général et, comme la plupart des langages de programmation à usage général, le but principal de la citation en Perl n'est pas de protéger les chaînes, mais de les mentionner du tout. C'est en fait une façon dont la plupart des langages de programmation sont similaires au langage naturel. En anglais, et en supposant que vous avez un chien, "votre chien" est une phrase de deux mots, tandis que votre chien est un chien. De même, en Perl,
'$foo'
est une chaîne, tandis que$foo
quelque chose dont le nom est$foo
.Cependant, contrairement à peu près tous les autres langages de programmation à usage général, Perl aussi interpréter parfois le texte sans guillemets en mentionnant une chaîne - une chaîne qui est le « même » comme, dans le sens où il est composé des mêmes caractères le même ordre. Il essaiera d'interpréter le code de cette façon uniquement s'il s'agit d'un mot simple (aucun
$
ou autre sigil, voir ci-dessous), et après il n'a pas pu trouver d'autre sens à lui donner. Ensuite, il le prendra comme une chaîne, sauf si vous le lui dites en activant les restrictions .Les variables en Perl commencent généralement par un caractère de ponctuation appelé sigil , qui spécifie le type large de la variable. Par exemple,
$
signifie scalaire ,@
signifie tableau et%
signifie hachage . ( Il y en a d'autres. ) Ne vous inquiétez pas si vous trouvez cela déroutant (ou ennuyeux), car je ne fais que le dire pour dire que lorsqu'un nom valide apparaît dans un programme Perl mais n'est pas précédé d'un sigil, ce nom est dit être un simple mot .Les mots nus servent à diverses fins, mais ils signifient généralement une fonction intégrée ou un sous-programme défini par l' utilisateur qui a été défini dans le programme (ou dans un module utilisé par le programme). Perl n'a pas de fonctions intégrées appelées
b1
ouDAT
, donc quand l'interpréteur Perl voit le codeb1.DAT
, il essaie de traiterb1
etDAT
comme les noms des sous-programmes. En supposant qu'aucun de ces sous-programmes n'a été défini, cela échoue. Ensuite, à condition que les restrictions n'aient pas été activées, il les traite comme des chaînes. Cela fonctionne, si vous avez réellement si oui ou non l' intention que cela se produise est quiconque conjecture. L'.
opérateur de Perl concatène les chaînes , doncb1.DAT
évalue la chaîneb1DAT
. Autrement dit,b1.DAT
est une mauvaise façon d'écrire quelque chose comme'b1' . 'DAT'
ou"b1" . "DAT"
.Vous pouvez tester cela vous-même en exécutant la commande
perl -E 'say b1.DAT'
, qui transmet le court script Perlsay b1.DAT
à l'interpréteur Perl, qui l'exécute, en imprimantb1DAT
. (Dans cette commande, les'
'
citations indiquent la coquille de passersay b1.DAT
comme un seul argument de ligne de commande, sinon, l'espace causeraitsay
etb1.DAT
à analysable comme des mots séparés etperl
les recevait comme arguments distincts.perl
Ne pas voir les citations elles - mêmes, la shell les supprime .)Mais maintenant, essayez d'écrire
use strict;
dans le script Perl avantsay
. Maintenant, il échoue avec le même type d'erreur que vous avez obtenurename
:Cela s'est produit parce que
use strict;
l'interpréteur Perl ne pouvait pas traiter les mots nus comme des chaînes. Pour interdire cette fonctionnalité particulière, il suffirait vraiment d'activer uniquement lasubs
restriction. Cette commande produit les mêmes erreurs que ci-dessus:Mais généralement, les programmeurs Perl écrivent
use strict;
, ce qui active lasubs
restriction et deux autres.use strict;
est une pratique généralement recommandée. Larename
commande fait donc cela pour votre code. C'est pourquoi vous obtenez ce message d'erreur.4. En résumé, voici ce qui s'est passé:
b1.DAT
tant que premier argument de ligne de commande,rename
traité comme du code Perl à exécuter en boucle pour chaque argument de chemin d'accès.b1
etDAT
lié à l'.
opérateur.b1
etDAT
n'étaient pas préfixés par des sceaux, ils étaient donc traités comme des mots nus.'b1'
et'DAT
'et concaténés. C'est loin de ce que vous vouliez, ce qui montre à quel point cette fonctionnalité n'est souvent pas utile.rename
permet toutes les restrictions (vars
,refs
etsubs
). Par conséquent, vous avez plutôt reçu une erreur.rename
quitter en raison de cette erreur. Étant donné que ce type d'erreur s'est produit tôt, aucune tentative de changement de nom n'a été effectuée, même si vous ne l'avez pas réussi-n
. C'est une bonne chose, qui protège souvent les utilisateurs contre les changements involontaires de nom de fichier et parfois même contre la perte de données réelle.Merci à Zanna , qui m'a aidé à combler plusieurs lacunes importantes dans une version plus récente de cette réponse . Sans elle, cette réponse aurait été beaucoup moins logique et n'aurait peut-être pas été publiée du tout.
la source