РЕШЕНО - названия файлов (файлы с очень интересными названиями)

На самом деле это единственный раздел про unix на этом форуме

Модератор: /dev/random

v4567
Сообщения: 162
ОС: Devuan

РЕШЕНО - названия файлов

Сообщение v4567 »

Когда в результате обсуждения придём к какому то решению, то это решение наверное можно будет поместить в тему "Полезные советы и скрипты" .
Как то по серьёзному не работал с файлами в скриптах, а это оказалось совсем не просто, из-за того что в названиях могут быть спец символы. Например символ перевода строки '\n' или Backspace '\b'
Например как быть если в файле символ перевода строки.
Нашёл как его заменить на обратный слеш и 'n', при помощи sed:

Код: Выделить всё

sed ':a;N;$!ba;s/\n/\\n/g'
Читая в интернете расшифровку этой загадочной надписи, ничего толком так и не понял. Объясните пожалуйста как для домохозяйки.

В результате этой замены мы ведь получим файл уже с другим названием. Например был: 11"символ перевода строки"11, стал 11\n11 А вдруг в этой папке был файл с наиважнейшей государственно-межгалактической информацией под названием 11\n11, в результате он будет перезаписан и информация навсегда будет утрачена :cray:

А как быть с файлами в названии которых есть '\b' или ещё что нибудь....

PS: Не ужели со времён создания unix и стандартов, нельзя было немного подумать наперёд и как то решить эту проблему.......
Последний раз редактировалось v4567 20.04.2019 19:40, всего редактировалось 1 раз.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5159
ОС: Gentoo

Re: названия файлов

Сообщение /dev/random »

v4567 писал:
20.04.2019 02:29
sed ':a;N;$!ba;s/\n/\\n/g'
Эта строка ничего не делает ни с какими файлами. Она берёт текст с stdin, заменяет в нём переводы строк на \n, и отправляет результат на stdout.
v4567 писал:
20.04.2019 02:29
PS: Не ужели со времён создания unix и стандартов, нельзя было немного подумать наперёд и как то решить эту проблему.......
Вы не описали никакой конкретной проблемы. Что вы пытаетесь сделать и что у вас не получается?
Спасибо сказали:
Аватара пользователя
s.xbatob
Сообщения: 1139
ОС: Fedora

Re: названия файлов

Сообщение s.xbatob »

v4567 писал:
20.04.2019 02:29
Не ужели со времён создания unix и стандартов, нельзя было немного подумать наперёд и как то решить эту проблему
Все было предусмотрено с самого начала: имена файлов состоят не из символов, а из байт, из которых только два имеют значение. Остальные произвольные, ядро из никак не интерпретирует.
Для преобразования их в символы и обратно существует общепринятый механизм представления того, что в символы не преобразуется или вызывает проблемы: экранирование. Вот им и надо пользоватья.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 19369
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: названия файлов

Сообщение Bizdelnick »

А зачем их на что-то заменять? Просто учитесь жить с этим. Но если уж пытаетесь экранировать какие-то символы, то не забывайте экранировать и сам экранирующий символ.
Некоторое время назад я задумал серию статей о работе с шеллом. Написана пока только одна, как раз по данной теме. Выкладываю раньше времени, надеюсь, поможет в чём-то разобраться: https://mikhirev.ru/shell_scripting/files.html
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
v4567
Сообщения: 162
ОС: Devuan

Re: названия файлов

Сообщение v4567 »

/dev/random писал:
20.04.2019 08:23
v4567 писал:
20.04.2019 02:29
sed ':a;N;$!ba;s/\n/\\n/g'
Эта строка ничего не делает ни с какими файлами. Она берёт текст с stdin, заменяет в нём переводы строк на \n, и отправляет результат на stdout.
Это понятно.

Код: Выделить всё

s/\n/\\n/g
Этим куском кода меняем символ перевода строки, (все символы перевода строки, где бы они не встретились), (здесь вот не понятно \n это два символа "\" плюс "n" или это символ перевода строки?), на два символа "\" плюс "n".

Не понятно, что делает вот этот кусок кода:

Код: Выделить всё

:a;N;$!ba;
Bizdelnick то что описано в статье я знаю, но всё равно за статью спасибо! Она очень полезная и пригодится.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5159
ОС: Gentoo

Re: названия файлов

Сообщение /dev/random »

v4567 писал:
20.04.2019 14:19
Не понятно, что делает вот этот кусок кода:

Код: Выделить всё

:a;N;$!ba;
:a - метка для goto с именем a
N - добавить к буферу, с которым работает sed, перевод строки и после него следующую строку, не удаляя и не выводя текущую
$... - если последняя строка
$!... - если не последняя строка ("!" - это отрицание)
$!ba - если не последняя строка, то goto a
s/\n/\\n/g - выполнить замену в текущем буфере, в котором, благодаря вышеописанному коду, находится не одна строка безо всяких переводов, а весь файл.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 19369
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: названия файлов

Сообщение Bizdelnick »

v4567 писал:
20.04.2019 14:19
здесь вот не понятно \n это два символа "\" плюс "n" или это символ перевода строки?
В левой части выражения s/// используется синтаксис регулярных выражений POSIX, в правой — простой текст с экранированными последовательностями. В обоих случаях \n озничает символ перевода строки, чтобы такая последовательность не интерпретировалась — перед \ добавляется ещё один \. То есть данная команда заменяет переводы строки на последовательность \n.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
v4567
Сообщения: 162
ОС: Devuan

Re: названия файлов

Сообщение v4567 »

Вы не подумайте, что я пытаюсь тролить или зафлудить форум, просто хочется разобраться до тонкостей.
Потому что, (вот как сейчас), придётся по серьёзному что то написать и начнут вылазить ошибки, найти которые будет очень трудно, из-за плохого знания материала. Может это обсуждение ещё кому нибудь кроме меня поможет разобраться в данном вопросе до тонкостей и в дальнейшем не совершать ошибок.
Bizdelnick писал:
20.04.2019 14:40
v4567 писал:
20.04.2019 14:19
здесь вот не понятно \n это два символа "\" плюс "n" или это символ перевода строки?
В левой части выражения s/// используется синтаксис регулярных выражений POSIX, в правой — простой текст с экранированными последовательностями. В обоих случаях \n озничает символ перевода строки, чтобы такая последовательность не интерпретировалась — перед \ добавляется ещё один \. То есть данная команда заменяет переводы строки на последовательность \n.
Если это так, то не понятно почему надо запихивать в буфер. Без буфера почему то не работает.

Вот пример.

Создаю директорию и в ней файл с переводом строки посередине. Всё делаю из командной строки, а не в скрипте.

Код: Выделить всё

mkdir /dir
touch $'/dir/11\n11'
ls /dir
11?11

ls вместо перевода строки подставил вопросительный знак, а может это и не ls сделал...., так как вот выводы командой find

Код: Выделить всё

find "/dir" -type f
/dir/11?11
find "/dir" -type f -print0
/dir/11
11
В первом случае find получается то же поставил вместо перевода строки вопросительный знак и в конце названия файла всё таки перевёл на новую строку.
А во второй строке с -print0 всё произошло наоборот, в середине файла сработал перевод строки, а в конце он был заменён на нулевой символ. -print0 получается ставит нулевой символ только в конце строки, а не меняет его в строке где бы он не встречался. В мане про -print0 сказано, что
Правда; выведите полное имя файла на стандартный вывод, за которым следует ноль символ (вместо символа новой строки, который использует -print). Это позволяет имена файлов, содержащие символы новой строки или другие типы пробелов, прямо интерпретируется программами, которые обрабатывают результаты поиска. Этот вариант соответствует опции -0 xargs.
Это перевод гугла, английского я не знаю, так что приходится пользоваться переводчиками. И из перевода я понял, что везде символ перевода строки должен был замениться на нулевой символ.

Едем дальше:

Код: Выделить всё

find "/dir" -type f | sed ':a;N;$!ba;s/\n/\\n/g'
/dir/11\n11
find "/dir" -type f | sed 's/\n/\\n/g'
/dir/11
11
find "/dir" -type f | sed ':a;N;$!ba'
/dir/11
11

В первом случае заменился, при этом в конце названия файла остался перевод строки.
Во втором случае не заменился и в середине названия файла и в конце, не понятно почему?
В третьем случае то же не заменился ни в середине ни в конце.

Не понятен второй случай. Получается что буфер нужен, но не понятно какую роль он играет?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5159
ОС: Gentoo

Re: названия файлов

Сообщение /dev/random »

v4567 писал:
20.04.2019 15:19
Не понятен второй случай. Получается что буфер нужен, но не понятно какую роль он играет?
Буфер не "нужен", а есть всегда: sed читает строку (без перевода строки) в буфер, выполняет скрипт, выводит содержимое буфера и перевод строки, очищает буфер, читает в него следующую строку, снова выполняет скрипт, и т.д. Только так sed и работает. Как вы видите, если ничего специально не сделать, то переводы строки в буфере не появляются никогда, и команде s/\n/\\n/g заменять просто нечего. Команда N читает следующую строку в буфер досрочно, отделяя от старого содержимого переводом строки, и этот перевод становится возможным заменить.
Спасибо сказали:
v4567
Сообщения: 162
ОС: Devuan

Re: названия файлов

Сообщение v4567 »

/dev/random писал:
20.04.2019 15:35
v4567 писал:
20.04.2019 15:19
Не понятен второй случай. Получается что буфер нужен, но не понятно какую роль он играет?
Буфер не "нужен", а есть всегда: sed читает строку (без перевода строки) в буфер, выполняет скрипт, выводит содержимое буфера и перевод строки, очищает буфер, читает в него следующую строку, снова выполняет скрипт, и т.д. Только так sed и работает. Как вы видите, если ничего специально не сделать, то переводы строки в буфере не появляются никогда, и команде s/\n/\\n/g заменять просто нечего. Команда N читает следующую строку в буфер досрочно, отделяя от старого содержимого переводом строки, и этот перевод становится возможным заменить.
Этого я не знал. Получается так, что если не писать этот кусок :a;N;$!ba; то в буфере будет всё без перевода строк где бы они не находились в середине строки, в какой то её части или в конце. А команда N сохраняет этот перевод строк в каждом месте где он был до помещения в буфер, а не только в конце. Если команда N читает следующую строку в буфер досрочно, отделяя от старого содержимого переводом строки, и этот перевод становится возможным заменить. То кто же тогда оставляет и вставляет этот перевод строки в другие места, а не только в конце?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5159
ОС: Gentoo

Re: названия файлов

Сообщение /dev/random »

v4567 писал:
20.04.2019 15:47
то в буфере будет всё без перевода строк где бы они не находились в середине строки, в какой то её части или в конце
Перевод строки означает конец строки. Он не может быть в середине. Если между двумя буквами есть перевод строки, то эти буквы находятся в разных строках.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 19369
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: названия файлов

Сообщение Bizdelnick »

v4567 писал:
20.04.2019 15:19
из перевода я понял, что везде символ перевода строки должен был замениться на нулевой символ.
Не должен. В первом случае у Вас символ перевода строки заменился, поскольку он совпадает с разделителем. Если в качестве разделителя используется нулевой символ, он заведомо не может совпасть ни с каким из символов в пути к файлу.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
v4567
Сообщения: 162
ОС: Devuan

Re: названия файлов

Сообщение v4567 »

Если sed помещает строки без переводов строки, то тогда можно просто прогнать через буфер не заменяя вообще ничего, в конце перевод строки поставить вот такой командой printf "%s\n" ..... Файл тогда называться будет не так как после замены
11\n11, а вот так 1111
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5159
ОС: Gentoo

Re: названия файлов

Сообщение /dev/random »

v4567 писал:
20.04.2019 15:54
Если sed помещает строки без переводов строки, то тогда можно просто прогнать через буфер не заменяя вообще ничего, в конце перевод строки поставить вот такой командой printf "%s\n" ..... Файл тогда называться будет не так как после замены
11\n11, а вот так 1111
Нет. После каждого вывода буфера, перед чтением следующей строки, sed выводит перевод строки. Перечитайте ещё раз описание его работы, которое я приводил.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 19369
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: названия файлов

Сообщение Bizdelnick »

v4567, sed — это не настолько простая штука, чтобы вот так вот сходу, на одних только примерах, в неё въехать. Выделите хотя бы пару часов на то, чтобы почитать что-то о нём, когда разберётесь в основах — всё станет проще.
На русском языке можно глянуть, например, это.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
v4567
Сообщения: 162
ОС: Devuan

Re: названия файлов

Сообщение v4567 »

Bizdelnick, спасибо! Пойду читать.
В принципе то что хотел узнать в этом посте узнал и неясные вопросы выяснил.
Я не найду как отметить тему, что она решённая?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5159
ОС: Gentoo

Re: названия файлов

Сообщение /dev/random »

v4567 писал:
20.04.2019 16:08
Я не найду как отметить тему, что она решённая?
Отредактировать первое сообщение, добавив в начало заголовка слово "Решено:"
Спасибо сказали: