Що робить команда "exec"?


108

Я не розумію команду bash exec. Я бачив, як він використовувався всередині скриптів для перенаправлення всіх результатів у файл (як це бачиться в цьому ). Але я не розумію, як це працює або що він робить взагалі. Я читав сторінки чоловіків, але не розумію їх.


Чи знайомі ви з процесом ?
fkraiem

1
@fkraiem, що ти маєш на увазі?
бекко

Вибачте, я мав на увазі "що". : p Але, здається, відповідь ні.
fkraiem

Але насправді ваш сценарій використовує execособливий спосіб, який можна пояснити набагато простіше, я напишу відповідь.
fkraiem

Відповіді:


88

man bash каже:

exec [-cl] [-a name] [command [arguments]]
      If command is specified, it replaces the shell.  No new  process
      is  created.  The arguments become the arguments to command.  If
      the -l option is supplied,  the  shell  places  a  dash  at  the
      beginning  of  the  zeroth  argument passed to command.  This is
      what login(1) does.  The -c option causes command to be executed
      with  an empty environment.  If -a is supplied, the shell passes
      name as the zeroth argument to the executed command.  If command
      cannot  be  executed  for  some  reason, a non-interactive shell
      exits, unless the execfail shell option  is  enabled.   In  that
      case,  it returns failure.  An interactive shell returns failure
      if the file cannot be executed.  If command  is  not  specified,
      any  redirections  take  effect  in  the  current shell, and the
      return status is 0.  If there is a redirection error, the return
      status is 1.

Останні два рядки є найважливішим: якщо ви запускаєтесь execсамостійно, без команди, це просто змусить перенаправлення застосувати до поточної оболонки. Ви, напевно, знаєте, що при запуску command > fileвихідний запис commandзаписується в fileтермінал (це називається перенаправлення ). Якщо ви exec > fileзамість цього запустите , то перенаправлення застосовується до всієї оболонки: Будь-який вихід, отриманий оболонкою, записується fileна ваш термінал. Наприклад тут

bash-3.2$ bash
bash-3.2$ exec > file
bash-3.2$ date
bash-3.2$ exit
bash-3.2$ cat file
Thu 18 Sep 2014 23:56:25 CEST

Я спочатку запускаю нову bashоболонку. Потім у цій новій оболонці я запускаю exec > file, так що весь вихід перенаправляється на file. Дійсно, після цього я запускаю, dateале не отримую виводу, тому що вихід перенаправлений на file. Потім я виходжу з своєї оболонки (так що перенаправлення більше не застосовується) і бачу, що fileдійсно містить результат dateкоманди, яку я запустив раніше.


42
Це лише часткове пояснення. execслужить також для заміни поточного процесу оболонки командою, так що батько йде шляхом і дитині належить pid. Це стосується не лише перенаправлення. Будь ласка, додайте цю інформацію
Сергій Колодяжний

3
Слідом за коментарем @ SergiyKolodyazhnyy, приклад, з яким я щойно стикався, і який привів мене на цю сторінку, є docker-entrypoint.sh, де після виконання різних дій по конфігурації nginx є заключним рядком сценарію exec nginx <various nginx arguments>. Це означає, що nginx переймає pid bash-скрипту, і тепер nginx є основним запущеним процесом контейнера, а не скриптом. Я припускаю, що це лише для чистоти, хіба хто інший не знає конкретнішої причини для цього?
Люк Гріффітс

1
@Luke Це називається "скриптом обгортки". Прикладом цього є також те gnome-terminal, що принаймні 14.04 мав обгортковий сценарій для встановлення аргументів. І це їхнє єдине призначення, насправді - встановити мистецтво та оточення. Інший випадок - це очищення - спочатку вбити попередній екземпляр процесу та запустити новий
Сергій Колодяжний

інший execприклад схожий на nginxприклад , наведений @LukeGriffiths є ~/.vnc/xstartupсценарій , який vncserverвикористовує для настройки процесу сервера VNC , а потім exec gnome-sessionабо exec startkdeі так далі.
Тревор Бойд Сміт

@LukeGriffiths, основною причиною execсценарію запуску контейнера є те, що PID 1, ENTRYPOINT контейнера, має особливе значення у Docker. Це основний процес, який приймає сигнали, і коли він існує, контейнер також виходить. execпросто спосіб вийняти shцю ланцюжок командування і зробити демона основним процесом контейнера.
ккм

46

exec це команда з двома дуже чіткими поведінками, залежно від того, чи використовується принаймні один аргумент, або аргумент взагалі не використовується.

  • Якщо передається щонайменше один аргумент, перший береться за ім'я команди і execнамагається виконати його як команду, передаючи решта аргументів, якщо такі є, до цієї команди та керуючи перенаправленнями, якщо такі є.

  • Якщо команда, передана як перший аргумент, не існує, поточна оболонка, не тільки команда exec, виходить помилково.

  • Якщо команда існує і виконується, вона замінює поточну оболонку. Це означає, що якщо execз'явиться в скрипті, вказівки після виклику exec ніколи не будуть виконані (якщо тільки вони не execзнаходяться в нижній частині). execніколи не повертається. Оборонні пастки типу "EXIT" також не будуть спрацьовувати.

  • Якщо жодного аргументу не передано, execвін використовується лише для перевизначення поточних дескрипторів файлу оболонки. Оболонка продовжується і після exec, на відміну від попереднього випадку, але набирає чинності стандартний ввід, вихід, помилка чи будь-який дескриптор файлу.

  • Якщо використовуються деякі перенаправлення /dev/null, будь-який вхід з нього поверне EOF, а будь-який вихід до нього буде відкинутий.

  • Дескриптори файлів можна закрити, використовуючи -як джерело або призначення, наприклад exec <&-. Подальше читання чи запис потім не вдасться.

Ось два приклади:

echo foo > /tmp/bar
exec < /tmp/bar # exec has no arguments, will only affect current shell descriptors, here stdin
cat # simple command that read stdin and write it to stdout

Цей скрипт виводить "foo" як команда cat, замість того, щоб чекати введення користувача, як це було б зроблено у звичайному випадку, буде брати свій вхід з файлу / tmp / bar, який містить foo.

echo foo > /tmp/bar
exec wc -c < /tmp/bar # exec has two arguments, the control flow will switch to the wc command
cat

Цей скрипт відобразить 4(кількість байтів в / tmp / бар) і негайно закінчиться. catКоманда не буде виконана.


4
`Деякі старі пости ніколи не старіють ... +1.
Cbhihe

3
Якщо в деяких перенаправленнях використовується / dev / null, дескриптор пов'язаного файлу закритий. Ні, він дійсно переспрямовує на / з /dev/null, тому записи все-таки вдаються і читають повернення EOF. close(2)на fd викличе системні дзвінки читання / запису, щоб повернути помилки, і ви робите це, exec 2>&-наприклад, з.
Пітер Кордес

2
Спробуйте самостійно:: exec 3</dev/null; ls -l /proc/self/fdзауважте, що fd 3 буде відкритим лише для читання на / dev / null. Потім знову закрийте його exec 3<&-, і ви побачите ( ls -l /proc/$$/fdзнов), що у вашому процесі оболонки більше немає fd 3. (Закриття stdin з exec <&-може бути корисним у сценаріях, але в інтерактивному режимі це вихід.)
Пітер Кордес

@PeterCordes Ви абсолютно праві. Відповідь оновлено. Дякую!
jlliagre

1
Ця відповідь чудова тим, що вона пояснює два випадки використання execпоточної найбільш обґрунтованої відповіді лише про один випадок використання, а інша відповідь g_p лише про інший випадок використання. І ця відповідь є приємною і стислою / читаною для такого складного предмета.
Тревор Бойд Сміт

33

Щоб зрозуміти exec, потрібно спочатку зрозуміти fork. Я намагаюся тримати це коротко.

  • Коли ви доїжджаєте до роз’їзду в дорозі, у вас зазвичай два варіанти. Програми Linux досягають цього вилка в дорозі, коли вони потрапляють у fork()системний виклик.

  • Звичайні програми - це системні команди, які існують у складеній формі у вашій системі. Коли така програма виконується, створюється новий процес. Цей дочірній процес має те саме середовище, що і його батьківський, лише ідентифікаційний номер процесу інший. Ця процедура називається розщепленням .

  • Форкінг - це спосіб для існуючого процесу запустити новий. Однак можуть бути ситуації, коли дочірній процес не є частиною тієї ж програми, що і батьківський процес. У цьому випадку execвикористовується. exec замінить вміст поточного запущеного процесу інформацією з програмного двійкового файлу.
  • Після процесу розблокування адресний простір дочірнього процесу перезаписується новими даними процесу. Це робиться за допомогою виклику exec до системи.

3
Ви можете пояснити, чому execможна перенаправляти вихід скрипта, як у посиланні, яке я розмістив?
бекко

1
Я вважаю це незрозумілим "Однак, можуть бути ситуації, коли дочірній процес не є частиною тієї самої програми, що і батьківський процес"
cdosborn

6

В bash, якщо ви help exec:

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

    Options:
      -a name   pass NAME as the zeroth argument to COMMAND
      -c        execute COMMAND with an empty environment
      -l        place a dash in the zeroth argument to COMMAND

    If the command cannot be executed, a non-interactive shell exits, unless
    the shell option `execfail' is set.

    Exit Status:
    Returns success unless COMMAND is not found or a redirection error occurs.

Відповідний біт:

If COMMAND is not specified, any redirections take effect in the current shell.

execце вбудована оболонка , яка є еквівалентом оболонки з execсімейства системних викликів, про які говорить G_P (і про чиї вікна ви, здається, читали). Він просто має функцію POSIX, призначений для впливу на поточну оболонку, якщо жодна команда не вказана.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.