Разрешено ли оболочке оптимизировать бесполезные завершающие команды?

27

Если оболочку просят выполнить, вероятно, бесполезную ( или частично бесполезную ) команду, о которой известно, что она завершается, например cat hugeregularfile.txt > /dev/null, может ли она пропустить выполнение этой команды ( или выполнить, скажем, более дешевый эквивалент touch -a hugeregularfile.txt )?

В более общем смысле, похожа ли оболочка на компиляторы C в том, что она может выполнять любое преобразование исходного кода, если наблюдаемое извне поведение выглядит так, как если бы его анализировала абстрактная машина?

РЕДАКТИРОВАТЬ

Nota Bene: У моего вопроса, который был задан изначально, был заголовок, в котором спрашивалось, разрешена ли оболочка для выполнения этих оптимизаций, а не должна ли она или даже существуют ли реализации, которые могут их выполнять. Я интересуюсь теорией больше, чем практикой, хотя оба приветствуются.

Ивилнотексист Идонотексист
источник
Нет, оболочка не такая умная, как современные компиляторы. На самом деле, это довольно глупо. Это не оптимизирует бесполезный код.
devnull
12
Догадываться о намерениях пользователя - это не то, что должна делать оболочка. Пользователь может пытаться сделать с этой командой почти все, оптимизировать ее было бы неправильно, даже если бы это было возможно.
Крис Даун
1
Неважно, что если файл был устройством, то catон имеет большое значение. Оболочка может узнать, что файл является устройством, но он не обязательно должен быть надежным.
лет»
3
@StephaneChazelas C компиляторам не нужно «запрашивать разрешение у кого-либо» для оптимизации своих скомпилированных программ; В стандарте C есть правило « как будто», которое позволяет им делать это. Стандарт POSIX, по-видимому, стандартизировал по крайней мере одну оболочку ( pubs.opengroup.org/onlinepubs/009695399/utilities/… ), а также множество других утилит ( pubs.opengroup.org/onlinepubs/009604499/utilities/wc.html для wc, например). Но, насколько мне известно, POSIX не занимает позицию по оптимизации оболочки; Или это?
Iwillnotexist Idonotexist
2
Оптимизация повышает производительность с помощью ярлыков, не влияя на функциональность. Пока функциональность гарантирована, я не вижу возражений POSIX. Однако предложенная вами оптимизация нарушит спецификацию кошек . В спецификации POSIX есть конкретные формулировки, которые соответствуют типу оптимизации, выполняемой ksh. Как будто они говорят не отдельный процесс, а среду оболочки, позволяющую оптимизировать сохранение ветвлений.
Стефан Шазелас

Ответы:

26

Нет, это была бы плохая идея.

cat hugeregularfile.txt > /dev/nullи touch -a hugeregularfile.txtне одинаковы. catпрочитает весь файл, даже если вы перенаправите вывод в /dev/null. И чтение всего файла может быть именно тем, что вы хотите. Например, для того, чтобы кэшировать его, чтобы последующее чтение было значительно быстрее. Снаряд не может знать ваше намерение.

Точно так же компилятор C никогда не оптимизирует чтение файла, даже если вы не смотрите на то, что читаете.

SCAI
источник
2
@Iwillnotexist: У каждой полезной команды (кроме, возможно, trueи false) есть потенциальные побочные эффекты, и побочные эффекты - почти всегда точка вызова команды. Оболочка не может знать эти побочные эффекты заранее (например, для внешних программ cat) без решения проблемы остановки. Так что это по праву не пытается, и предполагает, что вы имели в виду то, что сказали.
Chao
5
@IwillnotexistIdonotexist Нет, оболочка не может видеть все, что должно произойти. Он понятия не имеет о cat. На самом деле, catможно сделать что угодно, от форматирования жесткого диска до загрузки Интернета.
Scai
5
«Unix не был разработан, чтобы мешать своим пользователям делать глупости, так как это также мешало бы им делать умные вещи». - Дуг Гвин
Agi Hammerthief
7
@cHao И ещё trueи falseпоставил $?.
Кайл Стрэнд,
3
Как @scai указывались выше, исполняемые файлы не похожи на ключевые слова языка: catи /dev/nullимеют типичные значения , но они не гарантированы вести себя таким образом. Чтобы выполнить оптимизацию, гарантируя отсутствие изменений в ожидаемом поведении, оптимизация может быть разрешена только с использованием конструкций, реализованных в самой оболочке, а не вещей, найденных в среде выполнения ... независимо от того, насколько интуитивно понятны их имена.
Эндибакли
20

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

Таким образом, оболочка (или любая другая программа) понятия не имеет, основываясь на названии, является ли файл который она пишет, что-то «по-настоящему» с данными. Есть AFAIK, также нет системных вызовов, которые может выполнить программа оболочки, чтобы определить, что, например, дескриптор файла на самом деле ничего не делает.

Ваше сравнение с оптимизацией удаленного кода в программе на C не работает, поскольку у оболочки нет общего обзора, который есть у компилятора C над частью исходного кода. Оболочка не знает достаточно о том, /dev/nullчтобы оптимизировать ваш пример, больше похоже на то, что компилятор C не знает достаточно о коде в вызове функции, на который он динамически ссылается, чтобы не делать вызов.

Энтон
источник
4
Оказывается, кш93 будет лечить /dev/nullспециально, иногда. Встроенная команда , которая имеет свой стандартный вывод направлена /dev/null, например echo foo >/dev/null, не приведет ни запись делаются для /dev/null. Он не делает ничего особенного, если он вызывает не встроенную команду (например, cat file >/dev/null).
Марк Плотник
На самом деле, catможет быть и что-то еще. Все остальное на самом деле.
Орион
3
На самом деле /dev/nullэто одна из очень немногих стандартных путей , а также /dev/tty, /dev/console, /tmp, /dev/и /.
Жиль "ТАК - перестань быть злым"
2
@MarkPlotnick На самом деле cat является встроенным ksh93 (не включен, если вы не вставили /opt/ast/binранее /bin(или там, где catэто доступно) в $PATH). И да, хотя cat file > /dev/nullс помощью этого встроенного readсодержимого выполняется его содержимое file, оно не записывает его в / dev / null (хотя оно открывается и создает его).
Стефан Шазелас
14

Он не будет оптимизировать выполнение команд (и вы уже получили несколько хороших ответов, объясняющих, почему не следует), но в некоторых случаях он может оптимизировать разветвления, трубу / пары сокетов, чтение. Вид оптимизаций, которые он может сделать:

  • В большинстве современных оболочек последняя команда в сценарии, как правило, будет выполняться в процессе оболочки, если trapне были заданы некоторые s. Например , в sh -c ls, большинство shреализаций ( bash, mksh, ksh, zsh, yash, некоторые версии ash) не раскошелиться процессом для запускаls .
  • в ksh93, подстановка команд не будет создавать канал или ветвь процесса, пока не будет вызвана внешняя команда ($(echo foo) например, будет расширена до fooбез трубы / пары сокетов или разветвления).
  • readвстроенная в некоторых оболочках ( bash, AT & T ksh) не будет делать однобайтный читает , если они обнаруживают STDIN является доступным для поиска (в этом случае они будут делать большие чтения и искать назад до конца , что они предназначены для чтения).
Стефан Шазелас
источник
Мне нравится этот ответ, но неясно, является ли это оригинальной причиной, или информация взята из некоторой ссылки (в которую я хотел бы углубиться)
yoniLavi
3
@yoniYalovitsky, это оригинальная причина . ksh93является ли оболочка ведущей на переднем крае оптимизации, поскольку ее цель / должна рассматриваться как находящаяся на одном уровне с такими языками программирования, как perl. Так что вы можете посмотреть kshдокументацию, код (удачи) и список рассылки для получения дополнительной информации.
Стефан Шазелас
1
@HenkLangeveld, да, вы можете проверить то, sh -c 'ps -p "$$"'что вам даст, psа не shс этими shреализациями, или с помощью strace / truss / tusc ...
Стефан Шазелас
1
Разница между ksh -c 'ps; ps'и bash -c 'ps; ps' интересна. Ksh93 идет дальше в своей оптимизации.
Хенк Лангевельд,
1
@HenkLangeveld, зависит от того, о какой реализации kshмы говорим здесь. mkshведет себя как bash. Такое поведение в основном предназначено для оптимизации таких вещей, как system("some command"). Обратите внимание, что есть побочный эффект этой оптимизации, когда дело доходит до состояния выхода процессов, завершенных сигналом (в некоторых оболочках). ksh93имел обыкновение иметь ошибку в том, что он делал оптимизацию, даже когда были установлены ловушки.
Стефан Шазелас
7

При взгляде cat hugeregularfile.txt > /dev/nullна оболочку не позволяют поверить, что действие бесполезно - catне является частью оболочки и может вообще что-то делать в теории, а также на практике.

Например, пользователь, возможно, переименовал исполняемый файл rmв cat, и внезапно строка выполняет наблюдаемое извне поведение, то есть удаляет файл.

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

Кто-то, возможно, установил версию, catкоторая работает как задумано, но с дополнительным побочным эффектом установки руткита, если он когда-либо запускается с соответствующими привилегиями - опять же, оболочка должна должным образом выполнить его.

Петерис
источник
2
На самом деле, mkshна самом деле оптимизировать V=$(cat file), сделав его встроенным. Таким образом, оболочка может оптимизировать его, но не превратить в просто touch -a.
Стив Шнепп
1
@SteveSchnepp, cat это является встроенной в mksh, но что BUILTIN прибегает к системы , catесли он принят какой - либо вариант, поэтому с GNU cat, mksh -c 'cat /dev/null --help'не дает такой же результат , как bash -c 'cat /dev/null --help', но mksh -c 'cat --help /dev/null'это даст вам то же самое bash -c 'cat --help /dev/null'(как mkshкошки встроено разбирает опций POSIX Кстати, в то время как кошка GNU разбирает их по пути GNU).
Стефан Шазелас
В bash и ksh93 V=$(cat file)можно оптимизировать с помощью V=$(< file). Это ускоряет работу даже без встроенной функции cat.
Хенк Лангевельд,