LINUX.ORG.RU

bash - список последних измененных файлов

 


0

3

Всем привет!

Я пытаюсь сделать небольшой скрипт, который должен вывести последние N измененных файлов определенного расширения из папки (включая файла из вложенных папок). Вывести в простом формате «Файл - дата изменения».

Столкнулся со следующей проблемой:

Если использую конструкцию pages=$(find "$OBSIDIAN_PATH" -type f -name '*.md' -exec stat --printf "%n = %y\n" '{}' ';') то как далее отсортировать файлы если в именах содержаться пробелы? т.е. в sort я не могу указать конкретный столбец

Если я использую конструкцию pages=$(find "$OBSIDIAN_PATH" -type f -name '*.md' -exec ls -t '{}' '+') то потом могу не понять как правильно обойти полученный результат

for line in $(echo "$pages"); do - имена файлов с пробелом переносятся на новую строку

for line in $pages; do - тут одна строчка вообще получается

Вопросы:

  1. как решить проблему с сортировкой?
  2. как решить проблему если я использую exec?
  3. как бы вы сделали?

Если я правильно понял:

find "$OBSIDIAN_PATH" -type f -name '*.md' -printf '%f = %TFT%TT\n' | sort --field-separator='=' --ignore-leading-blanks --key=2 --reverse | head --lines="$NUMBER_OF_FILES"

В именах файлов не должно быть «=».

anonymous
()
Ответ на: комментарий от anonymous

Вывести в простом формате «Файл - дата изменения».

Тогда ещё -l докинуть в ls.

Если прям хочется заморочиться с форматированием, то:

IFS='
'
find . -type f |
grep '\.go$' |
ls -tc $(cat) |
sed 10q |
for f in $(cat); do echo "$f $(stat -c %y "$f")"; done

Что касается IFS и $() — это идиомы, делающие шелл простым в работе. Шелл не должен быть масштабируемым.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 6)
Ответ на: комментарий от kaldeon

В чём вообще сакральный смысл такой неэффективности без выигрыша в читаемости? У тебя получается три(!) обращения к ФС за одним и тем же. grep не имеет смысла, потому что find нормально фильтрует по имени. Лаконичность не повышает читаемость, когда ты спустя год открываешь скрипт, а там короткие параметры, которые ты давно забыл. Собственно, чем это лучше, чем bash - список последних измененных файлов (комментарий)? В частности, если сравнить с коротким вариантом для интерактива, а не скрипта:

find . -type f -name '*.md' -printf '%f = %TFT%TT\n'
| sort -t '=' -b -k 2 -r
| head 10
anonymous
()
Ответ на: комментарий от anonymous

У тебя получается три(!) обращения к ФС за одним и тем же

ФС устала?

grep не имеет смысла, потому что find нормально фильтрует по имени

grep — общий инструмент поиска, find — специальный API. Выбирая grep мы можем перенести имеющиеся скиллы в новую задачу, а выбирая find мы можем сделать что-то особенное, трудновыразимое другими средствами, но потеряем в лёгкости восприятия (например, %TFT%TT не так сильно распространён как ls -lt).

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

-t распространённая опция, примерно как -l. Выбирать длинные есть смысл для особых, нераспространённых, неидиоматичных опций вроде –almost-all. -c %y менять на –format %y не имеет смысла, ибо %y сам по себе указывает на то, что это формат.

В целом, чтобы не думать, можно все опции без аргументов делать длинными. Опции с аргументами чаще всего понятны из контекста.

Собственно, чем это лучше

find — OK, если лично тебе так проще. grep позволяет отказаться от специального синтаксиса -name, поэтому лучше его использовать. %TFT%TT — OK, если лично тебе так проще. ls -t более распространён, поэтому лучше его использовать. И если хочется играться с форматом, то %TFT%TT плохо подходит. Тогда надо выводить секунды с 1970-01-01, чтобы было проще преобразовать.

ls -t $() vs sort — одно и то же, но с ls меньше приседаний.

Запрет на знак равно в имени файла — так себе. У меня хотя бы только перевод на новую строку нельзя, что редкость и всё равно сломает любой шелл, твой в том числе, а знак равно почаще встречается и шелл на нём не спотыкается. Можно поставить дату перед именем файла, если хочется использовать сортировку. Если это будут секунды с 1970-01-01, то переместить их в конец будет проще.

Nitpicking, но head — бесполезная команда.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 11)
Ответ на: комментарий от kaldeon

ФС устала?

Не плодить лишние операции ввода/вывода мне кажется универсально хорошей практикой, особенно, когда нет выигрыша в простоте/читаемости.

например, %TFT%TT не так сильно распространён как ls -lt

Я (почти) произвольно выбрал формат в стиле ISO8601, там можно и локалезависимый одной буквой (%t).

Тогда надо выводить секунды с 1970-01-01, чтобы было проще преобразовать.

В данном случае выигрыша не будет нигде. Формат ISO и сортируется, и удовлетворительно читается. Но если хочется и сортировать по дате, и выводить в каком-то плохо сортируемом формате, то действительно unix time будет одним из простых вариантов, хотя date и другие распарсит. В общем, тут скорее вкусовщина и косметические требования, которые в ОП не озвучены.

ls -t $() vs sort — одно и то же, но с ls меньше приседаний.

ls означает дисковый I/O, это не одно и то же. Диск может быть и медленным HDD, и где-то в интернете с огромной латентностью.

Запрет на знак равно в имени файла — так себе.

Формат задан в ОП. Можно этого избежать, используя дополнительные шаги и \0 как разделитель (проблему с переводом строки в именах тоже так надо решать), но это пусть останется упражнением для автора темы.

Можно поставить дату перед именем файла, если хочется использовать сортировку. Если это будут секунды с 1970-01-01, то переместить их в конец будет не сложно.

Если имя файла не начинается с цифры? :) Тут действительно головная боль с разделителями, но, поскольку нужно вроде только имя файла без пути, можно применять как промежуточный символ «/».

Nitpicking, но head — бесполезная команда.

Я не очень владею sed, и в целом нахожу этот язык трудночитаемым. Хотя команду для вывода n первых строк знаю, иногда она встречается в скриптах.

anonymous
()
Ответ на: комментарий от superuser

Где-то тут рядом есть обсуждение такого же рода проблем, там хотят в названии файла дать тело войны и мир а в содержимом автора и название книги.

sin_a ★★★★★
()
Ответ на: комментарий от superuser

Вот вам решение, лишнего IO не расходует, перевод на новую строку обрабатывает. Чтобы не ломать красоту я положил дату в отдельный элемент массива.

readarray -d '' files < <(
	find . -type f -printf '%C@\n%f\0' |
	sort --reverse --zero-terminated '--field-separator= ' --key=1 |
	head --zero-terminated --lines=2 |
	awk '
		BEGIN {
			FS = OFS = "\n"
			RS = ORS = "\0"
		}

		{
			first = $1
			for (i = 1; i < NF; i++)
				$i = $(i+1)
			NF = NF - 1

			cmd = "date --date=@"first" \"+%F %T\" |tr -d \"\\n\""
			cmd | getline info
			close(cmd)

			printf "%s\0%s\0", $0, info
		}
	'
)

for i in "${files[@]}"; do
	echo "item: $i"
done

Чтобы такого п5а не было придумали IFS= и $().

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 5)
Ответ на: комментарий от kaldeon

На более чистом баше:

readarray -d '' files < <(
	find . -type f -printf '%C@\n%f\0' |
	sort --reverse --zero-terminated '--field-separator= ' --key=1 |
	head --zero-terminated --lines=2 |
	while read -r -d $'\0' s; do
		IFS=$'\n' read -r -d '' -a arr <<<"$s"
		(IFS=$'\n'; printf '%s' "${arr[*]:1}")
		printf '\0'
		date "--date=@${arr[0]}" '+%F %T' |tr -d '\n'
		printf '\0'
	done
)

for i in "${files[@]}"; do
	echo "item: $i"
done
kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 1)

Здравствуйте, найдётся ли у вас минутка поговорить о нашем господине и повелителе бабашке?

(->> (fs/match "." "regex:.*\\.yaml" {:recursive true}) 
          (sort  (fn [f1 f2 ] 
                   (> 
                    (-> f1 fs/last-modified-time fs/file-time->millis)
                    (-> f2 fs/last-modified-time fs/file-time->millis))))
          (map #(println (-> %1 .toString) (-> %1 fs/last-modified-time fs/file-time->instant .toString))))
ugoday ★★★★★
()

Забудь про ...=$(...). Это не для тебя придумано.

-exec stat ... {} не так чтобы очень нужен, встроенный в find printf умеет печатать много интересного.

Делай find ... -printf '....\0' | sort -z

Дальше ... | xargs -0 ...., забудь про for, это тебе не питон. Печатать для юзера через ... | xargs -0 printf '%s\n'

legolegs ★★★★★
()
Ответ на: комментарий от mx__

Ему вроде не надо выводить содержимое файлов. Впрочем, я не вчитывался. Когда я вижу как на баше пишут как будто это бейсик мне плохо становится.

legolegs ★★★★★
()
Последнее исправление: legolegs (всего исправлений: 1)

Этой конструкцией:

--printf «%n = %y\n»

вы вобще безобразие делаете. Если у вас разделитель «=», то никаких пробелов между именем файла и разделителем. И вам нужно определиться, каким символом в файле вы будете разделять «ИМЯ» и «ДАТА», тогда sort'у можно указать этот символ. Тут уже предложили «/», но, если вам потом захочется вывод с указанием подкаталогов, то «Ой».

если я использую exec?

Не использовать exec, find умеет печатать кучу всего.

как бы вы сделали?

Отказался бы от пробелов, переводов строк и пр. в именах файлов. find'ом бы в начале скрипта искал, что таких файлов нет...

mky ★★★★★
()
Ответ на: комментарий от mky

Удивительно то, что все не прошли элементарный тест на программиста. Казалось бы, ведь стандартный приём, такие вещи делаются по шаблону, который должен тут же возникать в качестве решения: закодировать вначале данные имеющие строгую форму (ну скажем время в секундах), потом разделитель и потом уже имя файла с любыми символами какими угодно до недопустимого символа \0. Ну или более универсальное решение, которое я тут привел - получить имена с любыми символами в массив однострочником и потом уже делать с ним что угодно. Но увы и ах...

vodz ★★★★★
()
Ответ на: комментарий от kaldeon

grep — общий инструмент поиска, find — специальный API. Выбирая grep мы можем перенести имеющиеся скиллы в новую задачу, а выбирая find мы можем сделать что-то особенное, трудновыразимое другими средствами, но потеряем в лёгкости восприятия (например, %TFT%TT не так сильно распространён как ls -lt).

Пользуясь случаем, поддерживаю этого оратора.

ugoday ★★★★★
()
Ответ на: комментарий от mky

Отказался бы от пробелов, переводов строк и пр. в именах файлов.

А может лучше отказаться от баша? Ну, серьёзно, компьютер должен помогать человеку и его обслуживать, а не человек подстраиваться под ограничения калечных инструментов из 70-х. Это даже как-то и унизительно. Всё равно, что писатель писал бы не так чтобы было интереснее читателю, а чтоб ворду было проще проверять грамматику.

ugoday ★★★★★
()
Ответ на: комментарий от vodz

Тест на программиста — это чувство абстракции. В баше абстракция — это линия. Если её использовать, код получится выразительным. Кто бы мог подумать, что, например, ls -t позволит в одно касание отсортировать список файлов?

Пример того, что получится, если следовать вашим советам — вот. Моим — вот. Разница на глаза.

Шелл создавался не как язык программирования, а как оболочка, способ взаимодействия с компьютером. IFS, $(), разделение на пробелы, возможность легко превратить текст в нечто полезное — это идиомы, специально сделанные такими, потому что они эффективно решают самый частый случай, но вы от них заставляется отказаться во имя какой-то высшей миссии.

То, что в файле может оказаться \n — вообще не аргумент. Тебе нужно hello.txt\nworld.txt\n превратить в набор аргументов прямо сейчас. Чей код будет проще написать и прочесть другому человеку: $(ls) или всё та вакханалия выше?

Если хочешь обработать \n в названиях файлов, просто используй другой язык программирования, который не придаёт особого значения линиям. Си, Пхп, Джаву, что угодно может это сделать гораздо проще и надёжнее.

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

Там один уже предложил от for отказаться, теперь вот предлагают от пайпов отказаться. От пайпов! Что тогда останется от баша? Настолько плохих языков не было даже до эпохи фортрана.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 6)
Ответ на: комментарий от kaldeon

просто используй другой язык программирования

Тут можно и остановиться. bash — хорошая диалоговая оболочка. Если подобралось несколько полезных команд и однострочников, то их можно сохранить в файл, чтобы не перепечатывать каждый раз. Всё. Этим хорошие способы использования bash исчерпываются.

Если нужно нечто сверх этого — просто используй настоящий язык программирования, без приколов вида «выхлоп find это строка, которая может быть проинтерпретирована как список имён файлов, т.е. это и строка и список строк одновременно, результат зависит от именования файлов, содержимого IFS, фазы луны и толики удачи».

ugoday ★★★★★
()
Ответ на: комментарий от kaldeon

теперь вот предлагают от пайпов отказаться. От пайпов! Что тогда останется от баша? Настолько плохих языков не было даже до эпохи фортрана.

Вы не только bash не знаете, но и юникс не понимаете. Конструкция <() - это и есть pipe, которое совершенно симметричное по сути. То что до bash не использовалась возможность создать читателя в текущем процессе, а писателя в новом - вот эта самая закорузлось как с обожествлением Фортрана.

vodz ★★★★★
()
Ответ на: комментарий от vodz

ТС сказал вывод в файл. Файл подразумевает работу в редакторе. Подразумевает возможность копи-пасты имени файла из строк в командуную строку и т.д. Давайте, поредактируйте файл, у которого строки разделены \0.

mky ★★★★★
()
Ответ на: комментарий от ugoday

Мне лично нравится шелл. Если поменять стандартный IFS на \n в скриптах, а в шелле не думать о нём так часто, то шелл позволяет довольно выразительно выполнять некоторые действия (самый частый кейс у меня — поиск по файлам), решать простенькую автоматизацию и писать прототипы.

Проблема в том, что bash тоже пытается одновременно быть шеллом, языком программирования и чем-то очень гибким. Результат — ~7,500 строк мана с отборными хаками на все случаи жизни, уменьшенная копия перла. Если бы баш предлагал ограниченный набор идиом и не делал вид, что может больше, то людям было бы проще понять как его использовать и они бы не пытались подражать этим readline -d '' < <(find -print0 |xargs -0).

Такой шелл, к счастью, был создан: rc. Всё самое лучшее из bourne и ничего лишнего. Помогает освободиться от этой перловской установки «а что если я могу использовать более изощрённый механизм, чтобы дополнительно покрыть 0.1 особых случаев». Просто принимаешь ограничения и пишешь выразительный код.

Но этот проект не так распространён, поэтому из вежливости к другим пользователям можно дальше писать на баше, но перенимать опыт.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 4)
Ответ на: комментарий от mky

ТС сказал вывод в файл. Файл подразумевает работу в редакторе.

Во-первых, вывод не ввод. Во-вторых, если универсальное решение не обременяет дополнительными телодвижениями, но способно лечь в качестве основы при необходимости с любым набором данных без ошибок и без незаявленных ограничений «в редакторе» - есть несомненный плюс. В-третьих, количество символов, от которых редакторам поплохеет не ограничивается только \0. Ну и в четвёртых, даже если всё дело только в пробелах, то это не отменяет факта, что способ, когда перед именем файла вначале идёт фиксированные данные всё равно облегчает написание и понимание потом кем-то кода, он короче/нагляднее/менее подвержен вносимыми ошибками.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Вы не только bash не знаете, но и юникс не понимаете

Универсальный ответ, когда речь заходит о чём-то сложном. C++ тоже знает только Строуструп, поэтому только он может критиковать свой язык.

Я имел ввиду концепцию, а не внутрянку. ls |grep |sort — это самый настоящий юникс, от него нет смысла отказываться в пользу ручной работы с массивами как в обычных языках. Против <() ничего не имею.

Но если говорить про readarray arr < <(cmd), то я бы предпочёл:

IFS='
' # newline
arr=($(cmd))
kaldeon
()
Ответ на: комментарий от kaldeon

то я бы предпочёл:

Я вижу типичную идиосинкразию. Так на всякий случай: если вы собрались эмулировать язык без конструкции <(), что таки можно сделать на bourne-like шеллах в виде

read << EOF
$(cmd)
EOF
то вдруг обнаружится, что и массивов то нету.

vodz ★★★★★
()
Ответ на: комментарий от ugoday

Дак не от bash, а от командной строки. Давайте, сделайте 10 файлов с названиями из разного числа проблеов и табуляций. А потом отличайте их один от другого. У всяких файловых менджеров тоже кривое отображение имён с переводами строк.

Вот, допустим, создали файл 'ddd '. ″ls -l″ его так и отобразит. Движок ЛОР'а покажет, что там один пробел, хотя я в кавычки ставил 3 пробела. А ″mc″ никак не покажет, сколько в нём пробелов. И он будет не отличим от 'ddd ' (4 пробела в конце), копи-паситить его имя из панели mc будет неудобно. Перевод строки ″ls″ отобразит как $'\n', а ″mc″ как точку...

под ограничения калечных инструментов из 70-х

Компы он такие, тупые, калечные. Калечнее только смартфоны.

а чтоб ворду

А если через Ворд имя файла распечатывать на бумажке ещё веселее потом будет угадывать сколько там пробелов между буквами и сколько в конце. Он отформатирует, растянет.

mky ★★★★★
()
Ответ на: комментарий от mky

Дак не от bash, а от командной строки.

С командной строкой всё хорошо. В том числе и с bash. Плохо, когда на нём программировать пытаются.

Давайте, сделайте 10 файлов с названиями из разного числа проблеов и табуляций. А потом отличайте их один от другого.

➜  a ls -lh                                                                                                                                                                                                     
итого 0
-rw-r--r-- 1 XXXXXXX YYYYYYYYY 0 Jul 11 13:30 ''$'\t'
-rw-r--r-- 1 XXXXXXX YYYYYYYYY 0 Jul 11 13:28 ' '
-rw-r--r-- 1 XXXXXXX YYYYYYYYY 0 Jul 11 13:28 '  '
-rw-r--r-- 1 XXXXXXX YYYYYYYYY 0 Jul 11 13:28 '   '

Компы он такие, тупые, калечные.

Компы хорошие. Только нужно правильными инструментами пользоваться. Например, такими, которые не смешивают данные и метаданные.

ugoday ★★★★★
()
Ответ на: комментарий от kaldeon

шелл позволяет довольно выразительно выполнять некоторые действия

Соглашусь с уточнением, если срезать все возможные углы: забить на удобную обработку аргументов командной строки, вообще проверку данных от пользователя, обработку ошибок и т.п. Т.е сделать нечто одноразовое, по принципу «я уверен, что у меня среди этих фалов не используются имена на арабском, а если будет какая ошибка, пусть напишет в STDERR, я глазами прочитаю».

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

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Жульничаете. Я написал, что в гнутом ls пробелы будут видны. А то, что мир не ограничен гнутым ls, и там, допустим есть mc, ls из busybox, «find -print», sftp, http-сервер вы просто игнорируете. Всё, кроме новых версий гнутого ls не отобразит файл с пробелами/табуляциями, так, чтобы его можно было скопи-пастить в командную строку/редактор или отличить один файл от другого в выводе.

И про бумажку я не зря написал. В книгах и прочем спокойно изменяют размер пробела и это не влияет на смысл. А калечный комп отличает один и два подряд идущих пробела в имени файла.

mky ★★★★★
()
Ответ на: комментарий от mky

Жульничаете.

Сказал человек, который с невинным видом передёрнул «имена с пробелами» на «имена только из пробелов».

есть mc

Если mc не умеет отображать допустимые имена файлов, чтож печально, но его место на помоечке. Используйте хорошие файловые менеджеры. Например, emacs, где, естественно, такой проблемы нету. http-серверы, естественно, умеют работать с файлами правильно, тут всё хорошо, find -print — костыль для башескриптоты, отправляется в музей вслед за bash’em и т.д, и т.п.

И про бумажку я не зря написал.

Вообще не понял эту вашу мысль.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Опять вы читаете выборочно.

имена только из пробелов

из разного числа проблеов и табуляций

Я писал про сложность различия табуляции и пробелов. В имени файла табуляция вобще не понятно какой смысла имеет, но она зачем-то может там быть. И вносить путаницу. Её туда, может, засунули, чтобы между словами был большой пробел, а выводе ls эти два слова наооборот склеятся через $'\t'. Аналогично с переводом строки. Может какой файловый менеджер будет отображать файл в две строки таблицы, как-бы выделяя его, а ls аналогично склеет слова через $'\n'.

emacs, где, естественно, такой проблемы нету.

И как emacs отображает файлы с пробелами, с переводами строк? Одиночные кавычки ставит?

но его место на помоечке

Вы из своей системы из initramfs выкорчевали busybox? Там ls тоже криво отображает.

find -print — костыль

Предлагаете emacs'ом файлы искать?

http-серверы, естественно, умеют работать с файлами правильно, тут всё хорошо

Проверяли? Вот я создал файл ″test file ″ (три пробела в конце). И что? Встроенный в lighttpd листинг каталога отображает его без кавычек, без пробелов в конце. А при попытке скачать этот файл предлагается сохранить его под именем ″test file _″. Да, можно сказать, что это проблема браузера, а не http-сервера. Последний просто генерит таблицу, честно вставляя туда хвостовые пробелы. А хромой не даёт эти пробелы копи-пастнуть. Но одиночные кавычки вокруг имени такого файла lighttpd не ставит. То есть его одним движением мышки в командную строку не скопировать.

Про бумажку. Вот, захотели на бумажки напечатать имя файла, чтобы его потом можно было в комп ввести и открыть. Как вы отпечатанном тексте определить, сколько там пробелов между словами?

Пока имена файлов без пробелов и прочего, их можно хоть распечатать, хоть потом с распечатки ввести в комп, можно копи-пастить хоть в командную строку, хоть в исходный код: open("ИмяФайла", ...). А иначе вылазят сложности, непонятно сколько пробелов в распечатке, а в Си-строках не обрабатываются конструкции вида $'\t'.

mky ★★★★★
()
Ответ на: комментарий от mky

Я писал про сложность различия табуляции и пробелов. В имени файла табуляция вобще не понятно какой смысла имеет, но она зачем-то может там быть

Да много чего может вносить путаницу: c и c, например, или 1, l, I при определённых шрифтах. Но вы же, я надеюсь, не станете запрещать использовать эти буквы в именах файлах? Инструмент должен, обязан корректно работать с любыми допустимыми файловыми именами. Ну, а если человек решил как-то сам себя запутать, то его проблемы.

И как emacs отображает файлы с пробелами, с переводами строк? Одиночные кавычки ставит?

Всё продумано: https://www.gnu.org/software/emacs/manual/html_node/emacs/Useless-Whitespace.html

из initramfs выкорчевали busybox? Там ls тоже криво отображает.

Это печально.

Предлагаете emacs’ом файлы искать?

Чтобы что? В диалоговом режиме недостатки find не проявляют себя, можно пользоваться. В программном — порождают долгие обсуждения с приколами вида «а что, если в имени файла будет символ =». Это позор.

Да, можно сказать, что это проблема браузера, а не http-сервера.

И скажу.

То есть его одним движением мышки в командную строку не скопировать.

Что, даже «скопировать ссылку» не работает? Ужасы какие.

Про бумажку. Вот, захотели на бумажки напечатать имя файла, чтобы его потом можно было в комп ввести и открыть.

Вы — странный человек. Впрочем, кто я такой, чтобы осуждать вас? Однако, в рамках той же логики, нужно запретить использовать те буквы, которые в кириллице и латинице выглядят одинаково, а также цифры 0 и 1.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Похожие символы — это проблема шрифта, можно найти шрифт, в котором 0 и O различаются, можно перебрать варианты. Одну цифру 0 меняет на одну буку O. А если в распечатаном имени файла Tab вместо пробела, то можно долго перебирать. Один пробел, два пробела, три пробела, один TAB, два TAB и т.д. Плюс ещё нужны выкрутасы, чтобы в командной строке набрать имя файла с табуляцией. И выглядеть это будет совсе не похоже. Там напечатано 'Привет Мир.txt', а в выводе ls будет 'Привет'$'\t"Мир.txt'.

Про emacs я не понял, я там не увидел, что он имена файлов с пробелами обрамляет в одиночные кавычки, как ls.

То есть его одним движением мышки в командную строку не скопировать.

Что, даже «скопировать ссылку» не работает? Ужасы какие.

А зачем мне «скопировать ссылку»? Мне, допустим, звонит пользователь, говорит, что такой-то файл не получается скачать. Я смотрю на web-страницу с листингом каталога и хочу в консоли посмотреть права, атрибуты и т.д. этого файла. Выделяю мышкой имя файла, набираю в консоли «ls -l», далее мне нужно делать лишнее действие — ставить открывающую кавычку, так как в имени файла есть пробел, потом нажимаю кнопочку на мышке, опять лишее действие — ставить закрывающую кавычку. Нажимаю Enter и получаю, что такого файла вобще нет, так как пробел в конце не копи-пастнулся. Да, тогда я могу посмотреть ссылку, увидеть что там есть «%20» в конце и нужно будет посчитать сколько там пробелов, добавить их в командную строку. Куча лишних действий, чтобы кто-то мог делать файлы с пробелами в именах.

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

Да ещё как проявляют. Если у find использовать -ls, то тогда табуляция будет отображаться как \t. Не совсем как у команды ls, но более-менее. Но, если мы захотели вывод каких-то других данных про файл и сделали вывод имени через -printf, то табуляция будет выведена знаком вопроса.

[/tmp] $ > tab$'\t'tab
[/tmp] $ ls -1 tab*
'tab'$'\t''tab'
[/tmp] $ find . -name 'tab*' -printf '%f\n'
tab?tab
[/tmp]$ find . -name 'tab*' -ls
   430267      0 -rw-r--r--   1 kostya   kostya          0 Jul 11 22:10 ./tab\ttab

И, в отличии от вывода команды ″ls″, вывод команды ″find -ls″ нелья просто мышкой копи-пастнуть в командную строку, нужно обрамление ″$"″.

У нас нет единого представления имени файла с табуляцией, чтобы его можно было копи-пастой и в исходник программы вставить (Си-строка) и в командную строку.

mky ★★★★★
()
Ответ на: комментарий от mky

Про emacs я не понял,

Сначала используете dired-mode, чтобы открыть интересующую директорию, потом whitespace-mode, чтобы получить информацию о пробелах-табах-чего-угодно.

Что до остального, вы ставите меня в неудобное положение. Я пытаюсь быть вежливым и культурным, но тут лучше, чем «дай невежде хрустальный нефритовый посох, он не только его поломает, но и порежет при этом руки» не скажешь. Вы атакуете нормальную технологию «разделять слова пробелами» с помощью дурацких примеров со смесью пробелов и табов, и значимыми концевыми пробелами в распечатанном на бумажке списке файлов. Так никто не делает, это раз.

Во-вторых, моей первой осью была Windows 98. И (проверять я это конечно же не буду) проводник в ней прекрасно справлялся с фалами с пробелами, в том числе с концевыми пробелами, если кто вдруг хотел создать такое извращение. Если линуксовые инструменты в 2025-м году уступают виндовым из 1998-го, то возникает вопрос: что из этого система, спроектированная профессионалами для профессионалов, а что исторически сложившаяся гора костылей.

Однако и в линуксе, если использовать нормальные инструменты, то всё отлично работает. Узрите же магию:

user> (fs/match "/tmp/a" "glob:*")
[#object[sun.nio.fs.UnixPath 0x54894481 "/tmp/a/  "]
 #object[sun.nio.fs.UnixPath 0x788d9605 "/tmp/a/   "]
 #object[sun.nio.fs.UnixPath 0x33d747e3 "/tmp/a/\t"]
 #object[sun.nio.fs.UnixPath 0x2bec077a "/tmp/a/ "]
 #object[sun.nio.fs.UnixPath 0x65dc7182 "/tmp/a/В авто\r\tнасажали\r\t\tразных армян,\rрванулись —\r\tи мы в пути.\rДорога до Ялты\r\tбудто роман:\rвсё время\r\tнадо крутить."]]
user> (-> (fs/match "/tmp/a" "glob:*")
          count)
5
user> (-> (fs/match "/tmp/a" "glob:*") (nth 4) fs/file-name .toString println)
В авто
	насажали
		разных армян,
рванулись —
	и мы в пути.
Дорога до Ялты
	будто роман:
всё время
	надо крутить.
nil
user> 

В директории пять файлов: у одного имя из пробела, у другого из двух, у третьего из трёх, у чётвёртого в качетве имени симво табуляции, а у пятого — стихи Маяковского в его фирменном стиле. И всё работает, файлы можно читать, считать, сортировать печатать. Вообще всё.

Потому как существует такая штука, как барьеры абстракции. API списка всё равно, на содержимое списка. А содержимому, в данном случае объекту типа sun.nio.fs.UnixPath всё равно, что оно является элементом коллекции. И уж тем боле обход коллекции невозможно поломать наличием пробела в одном из свойств объекта. Прямо магия. Технологии пришельцев не иначе.

ugoday ★★★★★
()