У меня есть два файла в папке на моем Ubuntu 16.04:
a1.dat
b1.DAT
Я хочу переименовать, b1.DAT
чтобы b1.dat
в результате в папке были следующие файлы:
a1.dat
b1.dat
Я пытался (безуспешно):
$ 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).
и
$ 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).
Поиск этого не привел к значимому решению ...
Ответы:
Похоже, эта ошибка исходит от Perl
rename
. Вам нужно использовать цитаты, но вам нужно только указать часть, которую вы хотите изменить, стиль поиска и замены. Синтаксис такой:Удалить
-n
после тестирования, чтобы фактически переименовать файлы.Чтобы включить скрытые файлы, измените параметр glob перед запуском команды:
Если вы хотите рекурсивно переименовывать файлы, вы можете использовать
или если в текущем каталоге или под ним находится много путей, которые не заканчиваются
.DAT
, лучше указать эти пути во второй команде:Это будет быстрее, если ваши файлы имеют разные имена, не заканчивающиеся на
.DAT
. [1]Вы можете отключить эти настройки
shopt -u
, напримерshopt -u globstar
, но они по умолчанию отключены и будут отключены при открытии новой оболочки.Если это приводит к чрезмерно длинному списку аргументов, вы можете использовать, например
find
,:или лучше
Использование
find ... -exec
with+
быстрее, чем использование,\;
поскольку оно создает список аргументов из найденных файлов. Первоначально я думал, что вы не сможете использовать его, потому что вы упомянули, что у вас возниклаargument list too long
проблема, но теперь я знаю, что список будет также хитро разбит на несколько вызовов команды по мере необходимости, чтобы избежать этой проблемы. [2] .Поскольку
rename
все имена файлов будут обрабатываться одинаково, не имеет значения, насколько длинен список аргументов, поскольку его можно безопасно разделить на несколько вызовов. Если команда, с которой вы используете-exec
, не принимает несколько аргументов или требует, чтобы ее аргументы были в определенном порядке, или по какой-либо другой причине разделение списка аргументов приведет к чему-то нежелательному, вы можете использовать его\;
, что вызовет команду один раз. для каждого найденного файла (если список аргументов был слишком длинным для других методов, это займет много времени!).Большое спасибо Элии Каган за очень полезные предложения по улучшению этого ответа:
[1] Указание имен файлов при подстановке .
[2]
find ... -exec
с+
разбивает список аргументов .источник
-n
из переименования после тестирования - это просто чтобы показать, что будет измененоТы можешь сделать:
Drop
-n
для фактического переименования, чтобы иметь место.шаблон glob
*.DAT
совпадает со всеми файлами.DAT
в текущем каталогев
rename
подстановке,DAT$
совпаденияDAT
в конце\L$&
делает весь матч в нижнем регистре;$&
относится ко всему матчуЕсли вы просто хотите сделать для
b1.DAT
:Пример:
источник
Другие ответы касались одного из двух основных аспектов этого вопроса: как успешно выполнить операцию переименования, которая вам нужна. Цель этого ответа - объяснить, почему ваши команды не работают, в том числе значение этого странного сообщения об ошибке «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?В оболочке мы цитируем наши строки, чтобы защитить их от непреднамеренных расширений оболочки , которые в противном случае автоматически преобразовали бы их в другие строки (см. Раздел выше). Оболочки - это языки программирования специального назначения, которые работают совсем не так, как языки общего назначения (и их очень странный синтаксис и семантика отражают это). Но 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
:Это произошло потому, что
use strict;
запретил интерпретатору Perl рассматривать голые слова как строки. Чтобы запретить эту особенность, было бы достаточно включить толькоsubs
ограничение. Эта команда выдает те же ошибки, что и выше:Но обычно программисты на Perl просто пишут
use strict;
, что разрешаетsubs
ограничение и два других.use strict;
как правило, рекомендуется практика. Таким образом,rename
команда делает это для вашего кода. Вот почему вы получаете это сообщение об ошибке.4. В итоге, вот что произошло:
b1.DAT
в качестве первого аргумента командной строки, которыйrename
обрабатывается как код Perl для запуска в цикле для каждого аргумента пути.b1
иDAT
связано с.
оператором.b1
иDAT
не были префиксом с символами, поэтому они рассматривались как голые слова.'b1'
и'DAT
»и объединены. Это далеко от того, что вы намеревались, что показывает, как часто эта функция бесполезна.rename
позволяет все ограничения (vars
,refs
иsubs
). Таким образом, вы получили ошибку вместо.rename
выйти из-за этой ошибки. Так как такого рода ошибки произошли рано, не было никаких попыток переименования файлов, даже если вы не прошли-n
. Это хорошая вещь, которая часто защищает пользователей от непреднамеренных изменений имени файла и иногда даже от фактической потери данных.Благодарю Занну , которая помогла мне устранить несколько важных недостатков в более удобном наброске этого ответа . Без нее этот ответ был бы менее понятным и, возможно, вообще не был бы опубликован.
источник