Другие ответы касались одного из двух основных аспектов этого вопроса: как успешно выполнить операцию переименования, которая вам нужна. Цель этого ответа - объяснить, почему ваши команды не работают, в том числе значение этого странного сообщения об ошибке «bareword not selected» в контексте rename
команды.
В первом разделе этого ответа речь идет об отношениях между rename
Perl и о том, как rename
используется первый передаваемый им аргумент командной строки, который является аргументом кода. Второй раздел о том, как оболочка выполняет расширения - в частности, глобальные операции - для построения списка аргументов. В третьем разделе рассказывается о том, что происходит в коде Perl, который выдает ошибки «Bareword не разрешен». Наконец, четвертый раздел - это краткое изложение всех шагов, которые выполняются между вводом команды и получением ошибки.
1. Когда rename
вы получаете странные сообщения об ошибках, добавьте «Perl» в ваш поиск.
В Debian и Ubuntu rename
команда представляет собой скрипт Perl, который выполняет переименование файлов. В более старых выпусках - включая 14.04 LTS, которая все еще поддерживается на момент написания этой статьи - это была символическая ссылка, указывающая ( косвенно ) на prename
команду. В более новых выпусках он указывает вместо новой file-rename
команды. Эти две команды переименования в Perl работают в основном одинаково, и я просто обращусь к ним обоим, как и rename
к остальной части этого ответа.
Когда вы используете rename
команду, вы не просто запускаете Perl-код, написанный кем-то другим. Вы также пишете свой собственный код Perl и предлагаете rename
запустить его. Это связано с тем, что первый аргумент командной строки, который вы передаете rename
команде, отличный от аргументов, подобных опции-n
, состоит из фактического кода Perl . Команда rename
использует этот код для работы с каждым из путей, которые вы передаете в качестве последующих аргументов командной строки. (Если вы не передаете аргументы rename
пути, вместо этого считывает пути из стандартного ввода , по одному на строку.)
Код выполняется внутри цикла , который повторяется один раз для каждого пути. В верхней части каждой итерации цикла перед выполнением кода специальной $_
переменной присваивается имя пути, обрабатываемого в данный момент. Если ваш код вызывает изменение значения $_
на другое, этот файл переименовывается, чтобы получить новое имя.
Многие выражения в Perl неявно работают с $_
переменной, если им не дано никакого другого выражения для использования в качестве операнда . Так , например, выражение подстановки $str =~ s/foo/bar/
изменяет первое вхождение foo
в строке , принадлежащих $str
переменной к bar
, или оставляет его неизменным , если она не содержит foo
. Если вы просто написать s/foo/bar/
без явного использования на =~
оператора , то он работает на $_
. Это сказать, что s/foo/bar/
это мало для $_ =~ s/foo/bar/
.
Распространено передать в s///
выражение для в rename
качестве кода аргумента (т.е. первого аргумента командной строки), но вы не должны. Вы можете дать ему любой Perl-код, который вы хотите, чтобы он выполнялся внутри цикла, проверять каждое значение $_
и (условно) изменять его.
Это имеет много интересных и полезных последствий , но подавляющее большинство из них выходит за рамки этого вопроса и ответа. Основная причина, по которой я привожу это здесь - фактически, главная причина, по которой я решил опубликовать этот ответ - состоит в том, что, поскольку первым аргументом rename
является фактически код Perl, в любое время вы получаете странное сообщение об ошибке, и вы возникают проблемы с поиском информации об этом с помощью поиска, вы можете добавить «Perl» в строку поиска (или даже иногда заменить «переименовать» на «Perl»), и вы часто найдете ответ.
2. С rename *.DAT *.dat
, то rename
команда никогда не видела *.DAT
!
Такая команда, как rename s/foo/bar/ *.txt
правило, не передается программе *.txt
в качестве аргумента командной строки rename
, и вы этого не хотите , если только у вас нет файла с буквальным именем *.txt
, чего, как мы надеемся, нет.
rename
не интерпретирует образцы GLOB нравится *.txt
, *.DAT
, *.dat
, x*
, *y
, или *
когда ей передается в качестве аргумента имени пути. Вместо этого ваша оболочка выполняет расширение пути к ним (которое также называется расширением имени файла и также называется глобализацией). Это происходит до rename
запуска утилиты. Оболочка расширяет глобусы до потенциально нескольких имен путей и передает их всем в качестве отдельных аргументов командной строки rename
. В Ubuntu ваша интерактивная оболочка - это Bash , если вы не изменили ее, поэтому я привел ссылку на справочное руководство Bash выше.
Существует одна ситуация, когда шаблон glob может быть передан как один нерасширенный аргумент командной строки rename
: когда он не соответствует ни одному файлу. Разные оболочки демонстрируют разное поведение по умолчанию в этой ситуации, но поведение Bash по умолчанию состоит в том, чтобы просто передавать глобус буквально. Однако вы редко этого хотите! Если вы этого хотите, то убедитесь, что шаблон не раскрыт, заключив его в кавычки . Это касается передачи аргументов любой команде, а не только rename
.
Кавычки предназначены не только для глобирования (расширения имени файла), потому что существуют другие расширения, которые ваша оболочка выполняет для текста без кавычек и, для некоторых из них, но не для других , также для текста, заключенного в "
"
кавычки. В общем, всякий раз, когда вы хотите передать аргумент, который содержит символы, которые могут обрабатываться оболочкой специально, включая пробелы, вы должны заключать его в кавычки, предпочтительно с '
'
кавычками .
Код Perl s/foo/bar/
не содержит ничего, специально обработанного оболочкой, но для меня было бы неплохо процитировать это тоже - и написать 's/foo/bar/'
. (На самом деле, единственная причина , я не в том , что это будет сбивать с толку некоторых читателей, так как я еще не говорил о цитировании.) Поэтому я говорю , это было бы хорошо, потому что это очень распространено , что код Perl действительно содержит такие символы, и если бы я должен был изменить этот код, я мог бы не забыть проверить, нужно ли заключать в кавычки. Напротив, если вы хотите, чтобы оболочка расширяла глобус, она не должна заключаться в кавычки.
3. Что интерпретатор Perl подразумевает под «неиспользованным голым словом»
Сообщения об ошибках, которые вы показывали в своем вопросе, показывают, что при запуске rename *.DAT *.dat
ваша оболочка расширялась *.DAT
до списка из одного или нескольких имен файлов и что первое из этих имен было b1.DAT
. Все последующие аргументы - как любые другие, развернутые из, так *.DAT
и любые расширения из *.dat
--came после этого аргумента, поэтому они были бы интерпретированы как имена путей.
Потому что то, что на самом деле выполнялось, было чем-то похожим rename b1.DAT ...
, и поскольку rename
его первый b1.DAT
неопциональный аргумент обрабатывается как код Perl, возникает вопрос: почему возникают ошибки «не разрешено использование слова», когда вы запускаете его как код 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).
В оболочке мы цитируем наши строки, чтобы защитить их от непреднамеренных расширений оболочки , которые в противном случае автоматически преобразовали бы их в другие строки (см. Раздел выше). Оболочки - это языки программирования специального назначения, которые работают совсем не так, как языки общего назначения (и их очень странный синтаксис и семантика отражают это). Но Perl - это язык программирования общего назначения, и, как и большинство языков программирования общего назначения, основной целью цитирования в Perl является не защита строк, а упоминание их вообще. Это на самом деле так, что большинство языков программирования похожи на естественный язык, В английском языке и предположим, что у вас есть собака, «ваша собака» - это фраза из двух слов, а ваша собака - собака. Точно так же в Perl '$foo'
есть строка, а $foo
есть то, чье имя $foo
.
Однако, в отличие от почти любого другого языка программирования общего назначения, Perl также иногда интерпретирует текст без кавычек как упоминание строки - строки, которая является «такой же», как она, в том смысле, что она состоит из тех же символов в тот же порядок. Он будет пытаться интерпретировать код таким образом, только если это голое слово (нет $
или другой символ, см. Ниже), и после этого он не сможет найти никакого другого значения, чтобы дать его. Тогда он будет восприниматься как строка, если вы не запретите это , включив ограничения .
Переменные в Perl обычно начинаются с символа пунктуации, называемого символом , который указывает широкий тип переменной. Например, $
означает скаляр , @
означает массив и %
означает хэш . ( Есть и другие. ) Не беспокойтесь , если вы обнаружите , что в заблуждение (или скучно), потому что я только доведя его до сказать , что , когда действительное имя появляется в программе Perl , но не предшествует сигилы, что имя называется голым словом .
Голые слова служат различным целям, но они обычно означают встроенную функцию или пользовательскую подпрограмму , которая была определена в программе (или в модуле, используемом программой). Perl не имеет встроенных функций, вызываемых b1
или DAT
, поэтому, когда интерпретатор Perl видит код b1.DAT
, он пытается обрабатывать b1
и DAT
как имена подпрограмм. Предполагая, что такие подпрограммы не были определены, это терпит неудачу. Затем, если ограничения не были включены, он обрабатывает их как строки. Это сработает, хотя кто-то догадывался , действительно ли вы собирались это сделать. .
Оператор Perl объединяет строки , поэтому b1.DAT
вычисляет строкуb1DAT
, То есть b1.DAT
это плохой способ написать что-то вроде 'b1' . 'DAT'
или "b1" . "DAT"
.
Вы можете проверить это самостоятельно, запустив команду perl -E 'say b1.DAT'
, которая передает короткий сценарий say b1.DAT
Perl интерпретатору Perl, который его запускает, печатая b1DAT
. (В этой команде, в '
'
кавычки сказать оболочки пройти say b1.DAT
как единый аргумент командной строки, в противном случае пространство будет вызывать say
и b1.DAT
быть разобрано как отдельные слова , и perl
будут получать их в виде отдельных аргументов. perl
Ничего не видим кавычки сами, так как оболочка их убирает .)
Но теперь попробуйте написатьuse strict;
в Perl-скрипте раньше say
. Теперь происходит сбой с той же самой ошибкой, которую вы получили от 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.
Это произошло потому, что use strict;
запретил интерпретатору Perl рассматривать голые слова как строки. Чтобы запретить эту особенность, было бы достаточно включить только subs
ограничение. Эта команда выдает те же ошибки, что и выше:
perl -E 'use strict "subs"; say b1.DAT'
Но обычно программисты на Perl просто пишут use strict;
, что разрешает subs
ограничение и два других. use strict;
как правило, рекомендуется практика. Таким образом, rename
команда делает это для вашего кода. Вот почему вы получаете это сообщение об ошибке.
4. В итоге, вот что произошло:
- Ваша оболочка передана
b1.DAT
в качестве первого аргумента командной строки, который rename
обрабатывается как код Perl для запуска в цикле для каждого аргумента пути.
- Это было принято означать
b1
и DAT
связано с .
оператором.
b1
и DAT
не были префиксом с символами, поэтому они рассматривались как голые слова.
- Эти два голых слова были бы приняты как имена встроенных функций или любых пользовательских подпрограмм, но ни у одного из этих имен не было таких вещей.
- Если бы «строгие подпрограммы» не были включены, то они были бы обработаны как строковые выражения
'b1'
и 'DAT
»и объединены. Это далеко от того, что вы намеревались, что показывает, как часто эта функция бесполезна.
- Но «строгие подлодки» была включена, потому что
rename
позволяет все ограничения ( vars
, refs
и subs
). Таким образом, вы получили ошибку вместо.
rename
выйти из-за этой ошибки. Так как такого рода ошибки произошли рано, не было никаких попыток переименования файлов, даже если вы не прошли -n
. Это хорошая вещь, которая часто защищает пользователей от непреднамеренных изменений имени файла и иногда даже от фактической потери данных.
Благодарю Занну , которая помогла мне устранить несколько важных недостатков в более удобном наброске этого ответа . Без нее этот ответ был бы менее понятным и, возможно, вообще не был бы опубликован.