Почему один исполнитель должен «sh -c a.out» вместо самого a.out?

#c #process #popen #execl

#c #процесс #popen #execl

Вопрос:

Я изучаю реализацию Apple popen() at https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/popen.c.auto.html и заметил , что они делают execl(_PATH_BSHELL, "sh", "-c", command, NULL) вместо execl(_PATH_BSHELL, command, NULL) этого .

Почему вы хотите (или должны) выполнить исполняемый файл, например a.out , via sh -c , а не только сам исполняемый файл?

Если вы sh -c a.out выполняете вместо самого a.out себя, становится ли фактический a.out процесс в конечном итоге «внучатым» процессом, а не дочерним процессом?

Ответ №1:

Почему вы хотите (или должны) выполнить исполняемый файл, например a.out , via sh -c , а не только сам исполняемый файл?

popen() предназначен для выполнения команд оболочки, которые включают синтаксис оболочки, такой как > перенаправление, | каналы и amp;amp; цепочка команд. Ему необходимо передать строку, sh -c чтобы поддерживать эти конструкции. Если бы это было не так, эти синтаксические функции были бы переданы дословно рассматриваемой программе в качестве аргументов.

Например, popen("make clean amp;amp; make") должен вызвать два make вызова. Без sh -c него вызывался make бы один раз с тремя аргументами, как если бы кто-то набрал

 $ make clean 'amp;amp;' make
  

на терминале.

Если вы sh -c a.out выполняете вместо самого a.out себя, становится ли фактический a.out процесс в конечном итоге «внучатым» процессом, а не дочерним процессом?

Да, это правильно. Между sh текущим процессом и a.out .

Комментарии:

1. Это последнее зависит от того, что sh есть. Например, если это bash или zsh, он будет выполняться без разветвления (если команда достаточно проста), поэтому в конечном итоге он станет дочерним. Dash этого не делает, поэтому, если вы используете систему, где sh — это dash, она будет работать так, как вы укажете.

Ответ №2:

что они делают execl(_PATH_BSHELL, "sh", "-c", command, NULL) вместо execl(_PATH_BSHELL, command, NULL)

Последний НЕ выполнялся command бы напрямую, но _PATH_BSHELL ( /bin/sh ) с его $0 значением command и без аргументов, что приводит к тому, что оболочка ожидает команды от своего stdin.

Кроме того, этот синтаксис зависит от NULL определения явного указателя (например ((void*)0) , ), а не только 0 , что нигде не гарантируется. Хотя они могут делать это в своей реализации (потому что они контролируют все заголовки), это не то, что вы должны делать в коде приложения.

И нет, execl(command, command, (void*)NULL) он бы тоже не выполнялся command напрямую, если command только это не а) полный путь и б) в исполняемом формате (двоичный файл или скрипт, начинающийся с she-bang #! — последнее является нестандартным расширением). Если command нужно было искать простое имя команды PATH (например pwd , или a.out ) или исполняемый скрипт, не начинающийся с she-bang, вы должны были использовать execlp вместо execl .

exec[lv]p[e] Функции выполняют некоторые вещи, которые выполняет оболочка (например, просмотр PATH ), но не все из них (например, выполнение нескольких команд или расширение переменных): вот почему функции любят system(3) или popen(3) передают команду /bin/sh -c . Обратите внимание, что с обоими это /bin/sh , а не с оболочкой входа пользователя или $SHELL из используемой среды.

Если вы sh -c a.out выполняете вместо самого a.out себя, становится ли фактический a.out процесс в конечном итоге «внучатым» процессом, а не дочерним процессом?

Только с некоторыми оболочками, такими как dash . Не с bash помощью , ksh93 , mksh , zsh , yash , busybox , и т. Д., Который будет выполняться a.out напрямую, а не разветвляться и ждать его.