Чому імена моєї папки закінчилися так, і як я можу це виправити за допомогою сценарію?


15

Вибачте, якщо на це є відповідь в іншому місці, я не знаю, як шукати свою проблему.

Я виконував деякі імітації на Redhat Linux сервері HPC, і мій код для обробки структури папок для збереження виводу мав нещасний помилку. Мій код matlab для створення папки:

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

де sp.run_numberбуло ціле число. Я забув перетворити його на рядок, але чомусь запустити mkdir(folder);(в matlab) все-таки вдалося. Насправді, симуляції пройшли без перешкод, і дані збереглись у відповідній директорії.

Тепер, коли структура папок запитується / друкується, я отримую такі ситуації:

  • Коли я намагаюся вкласти вкладку автозаповнення: run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/
  • Коли я використовую ls: run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?.
  • Коли я переношу на свій mac за допомогою rsync, --progressпараметр показує: run_\#003/etc. з (я припускаю) число, яке відповідає цілому числу, додане sp.run_numberдо трьох цифр, тож 10-й запуск -run_\#010/
  • Коли я переглядаю папки в пошуку, я бачу run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
  • Дивлячись на це питання і за допомогою команди ls | LC_ALL=C sed -n lя отримую:
run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$

Я не можу керувати cdпапками, використовуючи будь-яке із цих представлень.

У мене є тисячі цих папок, тому мені потрібно виправити це за допомогою сценарію. Який із цих варіантів є правильним поданням папки? Як я можу програмно посилатися на ці папки, щоб перейменувати їх на правильно відформатоване ім'я за допомогою скрипту bash? І я здогадуюсь заради цікавості, як, на пекло, це сталося в першу чергу?


4
"Коли я намагаюся вкласти вкладку автозаповнення: ... Якщо я спробую ввести ..." Навіщо вводити та не дозволяти автозаповненню завершено, якщо для вас? Також ^Aбуквально не ^слідує A, але Ctrl-A (ви можете ввести його за допомогою Ctrl-V Ctrl-A, оскільки Ctrl-A, як правило, є ярликом для оболонки).
муру

@muru, що не працює ... Я добираюсь, run_і мені потрібно щось набрати
Phill

Вибачте, прокоментував, перш ніж я побачив вашу
Phill

Можливий дублікат
Вибору

9
BTW, "деяка причина", чому mkdir в matlab зробив це, це тому, що ТИЛЬКИ недійсні символи у файлі чи імені файлів у Unix файлових системах є NUL та косою косою чергою /. Будь-який інший символ дійсний, включаючи контрольні символи. Я не знаю, що зробив би matlab, якби sp.run_number був 0 (напевно, або перервав з помилкою, або створив run_, оскільки байт NUL припинить рядок імені каталогу). Звичайно, це також було б проблематично для 16-бітових (або вище) значень, що мали в них байт NUL, а також змінюватиметься в залежності від ендіантності системи, що працює в системі matlab.
cas

Відповіді:


26

Ви можете використовувати renameутиліту perl (ака prenameчи file-rename) для перейменування каталогів.

Примітка: Це не слід плутати з renameз util-linux, або будь-яким іншим варіантом.

rename -n 's/([[:cntrl:]])/ord($1)/eg' run_*/

При цьому використовується ord()функція perl для заміни кожного елемента керування у імені файлу порядковим номером цього символу. наприклад ^Aстає 1, ^Bстає 2 і т.д.

-nВаріант для сухої траси , щоб показати , що rename буде робити , якщо ви дозволите. Видаліть його (або замініть його -vдля багатослівного виведення), щоб фактично перейменувати.

eМодифікатора в s/LHS/RHS/egексплуатації причин Perl для виконання RHS (заміна) в якості Perl коду, і $1це збіглися дані (контроль символів) від LHS.

Якщо ви хочете нульовий прокладені числа в іменах файлів, можна комбінувати ord()з sprintf(). напр

$ rename -n 's/([[:cntrl:]])/sprintf("%02i",ord($1))/eg' run_*/ | sed -n l
rename(run_\001, run_01)$
rename(run_\002, run_02)$
rename(run_\003, run_03)$
rename(run_\004, run_04)$
rename(run_\005, run_05)$
rename(run_\006, run_06)$
rename(run_\a, run_07)$
rename(run_\b, run_08)$
rename(run_\t, run_09)$

Наведені вище приклади спрацьовують тоді і лише тоді, коли sp.run_number у вашому скрипті matlab знаходився в діапазоні 0..26 (тому він створював контрольні символи в іменах каталогу).

Щоб мати справу з будь-яким 1-байтовим символом (тобто від 0..255), ви використовуєте:

rename -n 's/run_(.)/sprintf("run_%03i",ord($1))/e' run_*/

Якщо sp.run_numberможе бути> 255, вам доведеться використовувати unpack()функцію perl замість ord(). Я не знаю точно, як matlab видає неперетворений int в рядку, тому вам доведеться експериментувати. Детальніше perldoc -f unpackдив.

наприклад, наступне розпакує як 8-бітові, так і 16-бітні непідписані значення та занулює їх до 5 цифр у ширину:

 rename -n 's/run_(.*)/sprintf("run_%05i",unpack("SC",$1))/e' run_*/

Дякуємо за деталі! Я намагаюся перевірити це за допомогою -nпараметра, але він говорить мені про його недійсний варіант - інформація про версію дає мені, rename from util-linux 2.23.2так що я не впевнений, що його та ж функція
Phill

3
ось чому я вказав версію Perlrename утиліти. util-linux's renameдуже різний, набагато менш здатний, а параметри командного рядка несумісні. якщо ви працюєте з debian чи подібними, спробуйте встановити file-renameпакет. інакше встановіть відповідний пакет для вашого дистрибутива. можливо, він уже встановлений, спробуйте запустити prenameабо file-renameзамість просто rename.
cas

Так, я думав, що це так. Я побачу, чи зможу я змусити когось із них працювати. Ще раз дякую, що знайшли час, щоб допомогти мені!
Філ

11

І я здогадуюсь заради цікавості, як, в біса, це сталося в першу чергу?

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

де sp.run_numberбуло ціле число. Я забув перетворити його на рядок, але чомусь працює mkdir(folder); (у матлабі) все-таки досяг успіху.

Таким чином, здається, що mkdir([...])в Matlab об'єднує членів масиву, щоб побудувати ім'я файлу як рядок. Але ви замість цього дали йому номер, і цифри - це те, що насправді є персонажами на комп'ютері. Отже, коли це sp.run_numberбуло 1, воно надало тобі персонажа зі значенням 1, а потім персонажа зі значенням 2тощо.

Це контрольні символи, вони не мають символів для друку, і друк їх на терміналі матиме інші наслідки. Отже, натомість вони часто представлені різними видами втеч: \001(восьмеричний), \x01(шестнадцятковий) - ^Aце всі поширені уявлення для персонажа зі значенням 1. Символ зі значенням нуль дещо інший, це байт NUL, який використовується для позначення кінця рядка в C і в системних викликах Unix.

Якщо ви піднялися вище 31, ви б почали бачити символи для друку, 32 - пробіл (не дуже видно), 33 = !, 34 = "тощо.

Так,

  • run_ run_^A/ run_^B/- Перший run_відповідає тому, що має нульовий байт, рядок закінчується там. Інші показують, що ваша оболонка любить використовувати відображення контрольних кодів ^A. Позначення також натякає на те, що знак з числовим значенням 1 можна вводити як Ctrl-A, хоча вам потрібно сказати оболонці, щоб інтерпретувати не як контрольний символ, а як буквальний, Ctrl-V Ctrl-Aробити це хоча б у Bash.

  • ls: run_ run_? run_?- lsне любить друкувати недруковані символи на терміналі, він замінює їх знаками запитання.

  • rsync run_\#003/. Мені здається, що число тут у восьмеричному, як у більш поширеному \003.

  • за допомогою команди ls | LC_ALL=C sed -n l... run_\006$ run_\a$ run_\b$ run_\t$- \a, \bі \tє C втечі для сигналу тривоги (дзвінка), зворотної області та вкладки відповідно. Вони мають числові значення 7, 8 і 9, тому повинно бути зрозуміло, чому вони приходять після \006. Використання цих C-втеч - це ще один спосіб позначення контрольних символів. Кінцеві знаки долара позначають кінці рядка.

Що стосується cd, якщо я припускаю, що мої припущення є правильними, cd run_слід перейти до тієї однієї директорії, яка не має непарного символу, і cd run_?повинна дати помилку, оскільки знак питання - це глобальний символ, який відповідає будь-якому одному символу, і є декілька відповідних імен файлів, але cdтільки очікує одного.

Який із цих варіантів є правильним поданням папки?

Усі вони, в певному сенсі ...

У Bash ви можете використовувати \000і \x00ухиляється всередині $'...'лапок, щоб представити спеціальні символи, так $'run_\033(восьмеричний) або $'run_\x1b'відповідати директорії зі значенням символу 27 (що трапляється як ESC). (Я не думаю, що Bash підтримує втечу з десятковими числами.)

У відповіді cas є сценарій, щоб перейменувати їх, тому я туди не піду.


Якщо це GNU ls, існують деякі варіанти котирування, включаючи -b/ --escapeта --quoting-style=або QUOTING_STYLEзмінну середовища, щоб контролювати відображення символів, що не друкуються. Я не думаю, що є можливість зробити так, щоб він віддав перевагу восьмеричним втечам над версіями персонажів.
Toby Speight

3

Найпростіше було б створити неправильне ім’я файлу та правильне ім’я файлу в тому самому середовищі, де трапилася невідповідність, а потім просто перемістити / перейменувати папки на правильні імена.

Щоб уникнути зіткнень між наявними іменами, краще використовувати іншу папку призначення.

./saveLocationA/wrongname1 -> ./saveLocationB/correctname1
./saveLocationA/wrongname2 -> ./saveLocationB/correctname2
./saveLocationA/wrongname3 -> ./saveLocationB/correctname3

Якщо можливо, я вважаю за краще виправити сценарій і просто запустити його ще раз; виправлення деяких дивних помилок після смерті, ймовірно, коштує дорожче і може створити нові проблеми.

Удачі!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.