Почему `sort <“ $ f1 ”` предпочтительнее, чем `sort -“ $ f1 ”`, и почему это предпочтительнее `sort“ $ f1 ”`?

29

С /unix//a/458074/674

Не забудьте использовать -- при передаче произвольных аргументов командам (или использовать перенаправления, где это возможно). Так sort -- "$f1"или лучшеsort < "$f1" вместо sort "$f1".

Почему это предпочтительно использовать -- и перенаправление?

Почему sort < "$f1" предпочтительнее sort -- "$f1"?

Почему sort -- "$f1" предпочтительнее sort "$f1"?

Спасибо.

Тим
источник

Ответы:

55
sort "$f1"

терпит неудачу для значений $f1этого начала с -или здесь для случая, sortкоторый начинается с +(может иметь серьезные последствия для файла, называемого, -o/etc/passwdнапример).

sort -- "$f1"

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

sort < "$f1"

Не имеет этих проблем.

Здесь это оболочка, которая открывает файл. Это также означает, что если файл не может быть открыт, вы также получите потенциально более полезное сообщение об ошибке (например, большинство оболочек будет указывать номер строки в скрипте), и сообщение об ошибке будет согласованным, если вы используете перенаправления, где это возможно, чтобы открыть файлы.

И в

sort < "$f1" > out

(вопреки sort -- "$f1" > out), если "$f1"не может быть открыт, outне будет создан / усечен и sortдаже не запущен.

Чтобы устранить возможную путаницу (следуя комментариям ниже), это не мешает команде mmap()вводить файл или lseek()вставлять в него (а это sortне так), если сам файл доступен для поиска. Единственное отличие состоит в том, что файл открывается ранее и в дескрипторе файла 0 оболочкой, а не позже командой, возможно, в другом дескрипторе файла. Команда все еще может искать / mmap, что fd 0, как ей угодно. Это не следует путать с тем, cat file | cmdгде cmdstdin на этот раз является каналом, который не может быть преобразован / найден.

Стефан Шазелас
источник
4
Просто помните, что использование перенаправления заставляет sortпоследовательно читать данные, и вы не можете mmapфайл. Хотя sortпроблем с этим может не быть, рассмотрим производительность less <fileи less file. В первом случае lessнеобходимо сохранить все содержимое файла в памяти, во втором - разрешено читать только те части, которые ему нужны. А теперь представьте, что fileэто файл журнала объемом 100 ГБ ...
пенополистирол, летите
7
@styrofoamfly: это правильно, что less <fileвсе файлы хранятся в памяти, но это не обязательно, это недостаток меньше. Только cat file | lessвынужден. Проверьте less /dev/fd/0 <f, что не хранит файл в памяти, даже если он получает его на стандартный ввод. Это распространенное заблуждение, что стандартный ввод в Unix не поддается поиску. Фактически, это может быть доступно для поиска, в зависимости от типа файла.
оч
@styrofoamfly Вы имеете в виду, что read()считываете данные последовательно из файла, одновременно считывая mmap()весь файл в память сразу?
Тим
1
@JohnBollinger Нет. Это восходит, по крайней мере, к тому же, как getopt от SysIII в 1980 году до запуска проекта GNU, и его необходимо поддерживать для большинства стандартных утилит, в том числе sortPOSIX. Но это правда, что это не всегда поддерживается.
Стефан Шазелас
2
Мои извинения, @ StéphaneChazelas, вы правы относительно происхождения соглашения, и я дополнительно оговорю, что спецификация POSIX для getopt()функции C признает это значение аргумента --. Но главное, что вы принимаете: обработка аргументов - это область отдельных программ, и не все относятся к ним --особо.
Джон Боллинджер
17

Проблема заключается в именах файлов, начинающихся с тире. sort "$f1"не работает, если значение f1начинается с, -потому что команда будет интерпретировать значение как опцию. Обычно это приводит к ошибке, но может даже привести к дыре в безопасности . С sort -- "$f1", двойной тир аргумент --среднее «без вариантов за пределами этой точки» , поэтому значение f1не будет интерпретироваться как вариант. Но есть еще один крайний случай: если значение f1- тире и ничего больше, тогда это не опция, а аргумент -, который означает «стандартный ввод» (потому что аргумент является входным файлом; для выходного файла это будет означать «стандартный вывод»).

Использование перенаправления позволяет избежать всех этих ловушек.

Это относится к большинству команд, а не только sort.

Жиль "ТАК - перестань быть злым"
источник
Вы говорите, что sort < "$f1"будет работать, если значение было равно -? Это не в любой оболочке, которую я пробовал.
grawity
@ grawity, сравните seq 10 > -; sort -с seq 10 > -; sort < -.
Стефан Шазелас