Інші відповіді стосуються одного з двох основних аспектів цього питання: питання про те, як успішно виконати необхідну операцію з перейменування. Мета цієї відповіді - пояснити, чому ваші команди не працювали, включаючи значення цього дивного повідомлення про помилку "bareword not allowed" у контексті 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 .
Існує одна ситуація, коли глобальний шаблон може бути переданий як єдиний аргумент командного рядка rename
: коли він не відповідає жодним файлам. У різних ситуаціях оболонки проявляють різну поведінку за замовчуванням у цій ситуації, але поведінка за замовчуванням Баша полягає у тому, щоб просто пройти глобальну точку буквально. Однак ти рідко хочеш цього! Якщо ви цього хотіли, то слід переконатися, що модель не розширюється, цитуючи її. Це стосується передачі аргументів будь-якій команді, а не лише до rename
.
Цитування не тільки для глобулювання (розширення назви файлів), оскільки є інші розширення, які ваша оболонка виконує на тексті без котирування, а для деяких з них, але не на інших , також на текст, укладений у "
"
лапки. Загалом, у будь-який час, коли ви хочете передати аргумент, який містить символи, які можуть бути оброблені спеціально оболонкою, включаючи пробіли, вам слід навести її, бажано з '
'
цитатами .
Код Perl s/foo/bar/
не містить нічого, що спеціально обробляється оболонкою, але мені було б непогано, щоб я це також цитував - і написав 's/foo/bar/'
. (Насправді, єдина причина , я не в тому , що це буде збивати з пантелику деяких читачів, так як я ще не говорив про цитуванні.) Тому я кажу , це було б добре, тому що це дуже поширене , що код Perl дійсно містить таких символів, і якби я міняв цей код, я, можливо, не пам'ятаю, щоб перевірити, чи потрібне цитування. На противагу цьому, якщо ви хочете, щоб оболонка розширила глобус, вона не повинна цитуватися.
3. Що означає перекладач Perl, "барево не дозволено"
Повідомлення про помилки, які ви показали у своєму запитанні, показують, що, коли ви бігли rename *.DAT *.dat
, ваша оболонка розширилася *.DAT
до списку однієї або декількох імен і що перша з цих імен була b1.DAT
. Всі наступні аргументи - і будь-які інші, розширені з, *.DAT
і будь-які розширені з *.dat
--були після цього аргументу, тому вони будуть інтерпретовані як імена шляхів.
Оскільки те, що насправді було запущено, було щось подібне rename b1.DAT ...
, і тому, що rename
розглядає свій перший аргумент, що не є варіантом, як код Perl, виникає питання: чому ж b1.DAT
виникають ці помилки "не дозволяється", коли ви запускаєте його як код 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 зазвичай починаються з пунктуаційного символу під назвою sigil , який визначає широкий тип змінної. Наприклад, $
означає скаляр , @
означає масив і %
означає хеш . ( Є й інші. ) Не хвилюйтесь, якщо ви вважаєте це заплутаним (або нудним), тому що я лише доводжу це, щоб сказати, що коли дійсне ім'я з'являється в програмі Perl, але йому не передує sigil, це ім'я кажуть, що це голове слово .
Бареври служать різним цілям, але вони зазвичай означають вбудовану функцію або визначену користувачем підпрограму , визначену в програмі (або в модулі, який використовується програмою). 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
. Це хороша річ, яка часто захищає користувачів від ненавмисних змін назви файлів, а іноді навіть від фактичної втрати даних.
Дякую Занні , яка допомогла мені усунути декілька важливих недоліків у проекті цієї відповіді . Без неї ця відповідь мала б менше сенсу і не могла бути розміщена зовсім.