Почему имена моих папок оказались такими, и как я могу исправить это с помощью скрипта?

15

Извините, если есть ответ в другом месте, я не знаю, как искать мою проблему.

Я выполнял некоторые симуляции на HPC-сервере Redhat Linux, и мой код для обработки структуры папок с целью сохранения результатов был неудачной. Мой код 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/и т. Д. С (я полагаю) числом, совпадающим с целым числом, sp.run_numberдополненным до трех цифр, поэтому 10-й прогонrun_\#010/
  • Когда я просматриваю папки в Finder, я вижу 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? И я думаю, ради любопытства, как, черт возьми, это произошло в первую очередь?

Phill
источник
4
«Когда я пытаюсь перейти на вкладку автозаполнения: ... Если я пытаюсь ввести ...» Почему печатать и не разрешить автозаполнение, если для вас? Также ^Aбуквально не ^сопровождается A, но Ctrl-A (вы можете набрать его, используя Ctrl-V Ctrl-A, так как Ctrl-A обычно является ярлыком для оболочки).
Муру
@muru, который не работает ... Я дошел до того, что run_мне нужно что-то напечатать
Фил
Извините, я прокомментировал, прежде чем я увидел ваше редактирование, что мне удалось войти через cd
Phill
Возможная
копия
9
Кстати, «некоторая причина», по которой mkdir в matlab сделал это, заключается в том, что ЕДИНСТВЕННЫЕ недопустимые символы в имени файла или каталога в файловых системах unix - это NUL и прямая косая черта /. Допустим любой другой символ, включая управляющие символы. Я не знаю, что сделал бы matlab, если бы sp.run_number был равен 0 (вероятно, либо прервался с ошибкой, либо произвел run_, так как байт NUL завершил бы строку имени каталога). Конечно, это также было бы проблематично для 16-битных (или более высоких) значений, в которых содержался байт NUL, и также варьировалось бы в соответствии с порядком байтов в системе, выполняющей matlab.
Cas

Ответы:

26

Вы можете использовать renameутилиту perl (aka 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поэтому я не уверен, что это та же самая функция
Фил
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); (в Matlab) все еще удалось.

Таким образом, может показаться, что 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и \tC выходы для тревоги (звонок), Backspace и Tab, соответственно. Они имеют числовые значения 7, 8 и 9, поэтому должно быть понятно, почему они идут после \006. Использование этих escape-символов C - это еще один способ пометить управляющие символы. Конечные знаки доллара отмечают конец линии.

Что касается cd, если предположить, что мои предположения верны, cd run_следует перейти к этому единственному каталогу без нечетного завершающего символа и cd run_?выдать ошибку, поскольку вопросительный знак является символом глобуса, который соответствует любому отдельному символу, и существует несколько совпадающих имен файлов, но cdтолько ожидает одного.

Какой из этих параметров является правильным представлением папки?

Все они, в некотором смысле ...

В Bash вы можете использовать \000и \x00экранирование внутри $'...'кавычек для представления специальных символов, поэтому $'run_\033(восьмеричное) или $'run_\x1b'соответствовать каталогу со значением символа 27 (которое, как оказалось, является ESC). (Я не думаю, что Bash поддерживает экранирование с десятичными числами.)

В ответе cas есть сценарий для их переименования, поэтому я не пойду туда.

ilkkachu
источник
Если это GNU ls, есть несколько параметров цитирования, включая -b/ --escapeи --quoting-style=, или QUOTING_STYLEпеременную окружения, для управления отображением непечатаемых символов. Я не думаю, что есть возможность сделать так, чтобы он предпочитал восьмеричные экранирования над версиями персонажей.
Тоби Спейт
3

Проще всего было бы создать неправильное имя файла и правильное имя файла в той же среде, где произошла ошибка, а затем просто переместить / переименовать папки с правильными именами.

Чтобы избежать коллизий между существующими именами, лучше использовать другую папку назначения.

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

Если возможно, я бы предпочел исправить скрипт и просто запустить его снова; исправление какой-то странной ошибки после смерти, вероятно, стоит дороже и может привести к новым проблемам.

Удачи!

Питер
источник