Разрешено ли пространство в имени файла?

31

Говорят, что в Unix и Linux в целом вы должны избегать пробелов в имени файла (обычный файл, dir, ссылка, файл устройства, ...).

Но я делаю это все время. Для имени файла с пробелом внутри

  • В Nautilus символ пробела отображается как пробел.
  • В терминале Bash я либо использую \ для представления пробела, либо заключаю имя файла в пару двойных кавычек.
  • в файлах некоторых приложений (Наутилус, не уверен, будет ли это делать и ОС), имя файла записывается с заменой пробела на %20.

Действительно ли пробел в имени файла не разрешен?

Как правильно использовать пробел в имени файла?

Тим
источник
17
Это разрешено, но это действительно очень раздражает. Там нет причин для этого. Не делай этого.
Легкость гонки с Моникой
3
Вы также можете создать файлы с именем -rf ~(использовать touch -- "-rf ~"), но я бы не рекомендовал это делать.
Ян Д. Скотт
5
Вы можете сделать это, это разрешено, как создание сценария самоуничтожения с именем "cd", но вы не должны этого делать. Ваш файл уже выглядит по-разному в 3 разных инструментах, не так ли плохо?
Falco
7
Не все разделяют мнение, что это действительно очень раздражает. И «Нет причин для этого» настолько очевидно ложно, что не нуждается в опровержении. Я сдался и узнал, как правильно обращаться с пространствами много лет назад, и по большей части это действительно не имеет большого значения.
2
@snailboat Пробелы являются признаком реальной проблемы, которая заключается в отсутствии стандартизации. Файловые системы Unix позволяют именам файлов практически неограниченные двоичные двоичные объекты. Единственными недопустимыми байтами являются 0 и 47 ( /разделитель). Использование всех 254 оставшихся байтов открывает дверь ко всем способам неописуемых «имен». Очевидно, это безумие, но не все согласны с тем, что такое «вменяемый», и разные персонажи сломают разные инструменты. Пересечение здравомыслия каждого довольно мало .
jw013

Ответы:

48

Пробелы, и действительно каждый символ, кроме /и NUL, разрешены в именах файлов. Рекомендация не использовать пробелы в именах файлов исходит из опасности того, что они могут быть неправильно истолкованы программным обеспечением, которое их плохо поддерживает. Возможно, такое программное обеспечение глючит. Но также возможно, что языки программирования, такие как сценарии оболочки, делают слишком легким написание программного обеспечения, которое ломается при представлении имен файлов с пробелами в них, и эти ошибки имеют тенденцию проскальзывать, потому что сценарии оболочки не часто тестируются их разработчиками, использующими имена файлов с пробелами в их.

Замены пробелов %20не часто встречаются в именах файлов. Это в основном используется для (веб) URL. Хотя это правда, что% -кодирование из URL иногда попадает в имена файлов, часто случайно.

Celada
источник
6
Это «кодировка URL» или «кодировка процентов» en.wikipedia.org/wiki/URL_encoding. Поэтому наиболее подходящим названием, вероятно, является «кодировка URI», но люди находят URL-адрес легче сказать, чем URI , так что это распространенная форма неправильно. Обратите внимание, что набор зарезервированных символов в URI больше, чем для имен файлов * nix.
Златовласка
1
@ Я не знаю, что вы можете указать NUL-символ в любом аргументе командной строки в bash. Я попробовал несколько вещей, таких как цитирование с помощью Ctrl-V и что-то вроде этого, $(echo -e \\0)но это не сработало. Дело в том, что NUL не может использоваться в именах файлов, потому что он не может использоваться в строках C (потому что это терминатор строк), и все базовые API, а также практически все строки, обрабатываемые программами C, используют этот формат , Поскольку bashон написан на C, он может вообще не иметь поддержки для любых строк с NUL в них. Я могу ошибаться, может быть какой-то непонятный путь ...
Селада
1
Вроде как зависит от контекста. Строковые функции обычно не считают окончательный ноль (или, скорее, первый ноль - это конец строки, даже если после него есть что-то), поэтому в этом смысле он имеет нулевую длину и поэтому считается пустым.
Златовласка
3
@Celada, конечно, вы можете использовать NULи bash, вам нужно $'\0'. Например:find . -print0 | while read -d $'\0' f; do echo "$f"; done
Тердон
1
@goldilocks Люди действительно произносят URL как 'url', грубо рифмуясь с 'earl'?
Майлз Рут
17

Пространства будут разрешены в именах файлов, как вы заметили.

Если вы посмотрите на запись «большинство файловых систем UNIX» в этой таблице в википедии , вы заметите:

  • Разрешен любой 8-битный набор символов. Под этим зонтиком мы также можем включить 7-битный ASCII, поскольку он является подмножеством различных 8-битных наборов и всегда реализуется с использованием 8-битных байтов.

  • Единственными запрещенными символами являются /и «ноль». «Нуль» относится к нулевому байту, но они все равно не разрешены в текстовых данных.

Однако , если вы используете какую-либо оболочку, вы, возможно, поймете, что есть некоторые символы, которые, в первую очередь *, создадут неприятности, а именно оператор глобализации POSIX.

В зависимости от того, как вы хотите определить «хлопот», вы можете включить туда пробелы (пробелы, табуляции, новые строки и т. Д.), Так как это создает необходимость в кавычках "". Но это неизбежно, так как пробелы разрешены, так что ...

Как правильно использовать пробел в имени файла?

В контексте оболочки / командной строки, оберните имя файла в одинарные или двойные кавычки (но обратите внимание, что они не совпадают с другими проблемами WRT) или экранируйте пробелы \, например:

> foo my\ file\ with\ spaces\ in\ the\ name
лютик золотистый
источник
1
Как указать NUL-символ в bash? Я хочу проверить это в имени файла.
Тим
1
Ты не можешь «Семантика execve» относится к тому факту, что в C (и любом другом языке, который я знаю) текстовые строки заканчиваются нулем. Оболочка реализована на языке C. Самая хитрая вещь, о которой я могу подумать, touch $(echo -e "foo\00bar")- это -eпроцесс \0Nкак восьмеричное значение, но он все равно где-то теряется, так как он просто создает файл с именем foobar. Конечно, NULL не может быть напечатан, но я гарантирую, что он пропал оттуда из-за ограничения строки C.
Златовласка
"текстовые строки заканчиваются нулем" -> Чтобы объяснить далее: строки всегда хранятся с нулевым байтом в конце, поэтому это "не разрешено" в тексте: если вы вставите один, вы фактически прервали строку в таком случае. Например, foo[NULL]barв конечном итоге, как fooдля большинства намерений и целей. Тот факт, что этого не происходит, echo -eпоказывает, что NULL где-то был удален.
Златовласка
5
Подавляющее большинство языков программирования допускают нулевые символы в строках. Просто так получается, что основным языком, который не является C, является язык, на котором построен Unix - и большинство оболочек Unix также не допускают нулевые символы в строках. В любом случае, @Tim, все интерфейсы Unix используют строки с нулевым символом в конце, поэтому нулевой байт - это то, что вы никогда не можете иметь в имени файла (плюс, /который является разделителем каталогов и не может быть заключен в кавычки, поэтому может быть в пути но не в имени файла).
Жиль "ТАК - перестань быть злым"
1
... но [уже неважно]. Во всяком случае, не то, что я бы делал слишком часто. На мой взгляд, нет причин для них в текстовых данных. Я бы исправил это, но это комментарий.
Златовласка
3

Причина в значительной степени историческая - WAY назад в тумане пространств времени не было разрешено в именах файлов, поэтому пробелы использовались в качестве разделителей ключевых слов / имен файлов. Будущие интерпретаторы оболочки должны были быть обратно совместимы со старыми сценариями, и поэтому мы застряли на головной боли, которую мы испытываем сегодня.

Разработчики процессов, которым не нужно иметь дело с людьми, могут многое сделать намного проще, просто отбросив пробелы. Apple делает это, содержимое / System / Library / CoreServices / содержит очень мало пробелов, программы с пробелами открываются от имени пользователя иWouldLookStrangeIfCamelCased. Подобные пути только для Unix также избегают пробелов.

(отчасти связанный анекдот: в середине 90-х беспилотник Windows сказал «Назовите одну вещь, которую вы можете сделать на Mac, которую я не могу сделать в Windows» -> «Использовать 12 символов в имени файла». -> Тишина. Пробелы были также возможно в этих 12 символов)

Павел
источник
1
Раньше я использовал V6 Unix (c. 1978). Пространства были разрешены тогда. Одна из моих задач заключалась в написании программы для анализа файловой системы (с использованием прямого дискового ввода-вывода) и поиска файла, в названии которого были пробелы и символы возврата.
Wallyk
они вообще пропускают пробелы - или имена файлов содержат очень мало пробелов?
mikeserv
2

Так что да, как уже много раз говорилось в другом месте, имя файла может содержать практически любой символ. Но нужно сказать , что имя файла является не файл. Он имеет некоторый вес в качестве атрибута файла, поскольку для открытия файла обычно требуется имя файла, но имя файла указывает только на фактический файл. Это ссылка, которая хранится в каталоге, в котором она была записана, вместе с номером инода, что намного ближе к реальному файлу .

Итак, вы знаете, называйте это как хотите. Ядру все равно - все ссылки на файлы, которые оно будет обрабатывать, будут иметь дело с реальными номерами инодов. Имя файла предназначено для потребления человеком - если вы хотите сделать его сумасшедшим, это ваша файловая система. Здесь я сделаю некоторые сумасшедшие вещи:

Сначала я создам 20 файлов и назову их только пробелами, каждое имя файла будет на один пробел больше, чем последнее:

until [ $((i=$i+1)) -gt 20 ]
do  v=$v' ' && touch ./"$v"
done

Это довольно забавно. Посмотри на мои ls:

ls -d ./*
./      ./          ./              ./                  ./                 
./      ./          ./              ./                  ./                  
./      ./          ./              ./                  ./                   
./      ./          ./              ./                  ./     

Теперь я собираюсь отразить этот каталог:

set -- * ; mkdir ../mirror
ls -i1qdU -- "$@" |
sh -c 'while read inum na
    do  ln -T "$1" ../mirror/$inum
    shift ; done' -- "$@"
ls -d ../mirror/*

Вот ../mirror/содержание:

../mirror/423759  ../mirror/423764  ../mirror/423769  ../mirror/423774
../mirror/423760  ../mirror/423765  ../mirror/423770  ../mirror/423775
../mirror/423761  ../mirror/423766  ../mirror/423771  ../mirror/423776
../mirror/423762  ../mirror/423767  ../mirror/423772  ../mirror/423777
../mirror/423763  ../mirror/423768  ../mirror/423773  ../mirror/423778

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

Что ж...

echo "heyhey" >>./'    ' 
tgt=$(ls -id ./'    ')
cat ../mirror/${tgt%% .*} \
    $(ls -1td ../mirror/* | head -n1) 

ВЫХОД

heyhey
heyhey

Смотрите, и номер индекса, содержащийся в нем, ../mirror/"${tgt%% .*}"и номер ссылки, на который ссылается ссылка, ./' 'относятся к одному и тому же файлу Они описывают один и тот же файл. Они называют это, но не более того. На самом деле в этом нет ничего загадочного, только некоторые неудобства, которые вы могли бы причинить себе, но в конечном итоге это практически не повлияет на работу вашей файловой системы unix.

mikeserv
источник