[ Content | View menu ]

Разделение аргументов в shebang

Опубликовано 28.12.2009

В комментариях к прошлогоднему переводу Bash Pitfalls внимательный flavi задался вопросом, почему при попытке выполнить скрипт, в начале которого написано

#!/bin/bash --posix --verbose

выдаётся ошибка

/bin/bash: --posix --verbose: invalid option

в то время как в интерактивном режиме bash нормально запускается с такой комбинацией опций; более того, если в shebang’е оставить только одну из этих опций, то скрипт также запускается без ошибок.

Поначалу я предположил, что --posix запрещает опции, не определённые стандартом POSIX на sh. Но тогда попытка выполнить bash --posix --norc также приводила бы к ошибке, и конструкция #!/bin/bash --verbose --norc работала бы нормально, а это не так.

Пришлось разбираться более плотно. В bash (1) я вычитал следующее (выделение — моё):

If the program is a file beginning with #!, the remainder of the first line specifies an interpreter for the program. The shell executes the specified interpreter on operating systems that do not handle this executable format themselves. The arguments to the interpreter consist of a single optional argument following the interpreter name on the first line of the program, followed by the name of the program, followed by the command arguments, if any.

Т.е. в shebang можно задавать только один аргумент; кроме того, bash самостоятельно анализирует shebang и вызывает указанный интерпретатор только в случае, если система сама не может выполнить этот скрипт.

Сам файл передаётся на выполнение с помощью системного вызова execve (2) (это я вычитал в файле execute_cmd.c в исходном коде bash), в man-странице которого и разъясняется политика партии по поводу разбиения аргументов интерпретатора:

On Linux, the entire string following the interpreter name is passed as a single argument to the interpreter, and this string can include white space.

Таким образом, в самом первом примере у bash в argv оказывается не два аргумента --verbose и --norc, а один --verbose --norc, что и приводит к ошибке, и вина bash лишь в том, что он не разбивает свои аргументы на части, как это делает, например, Perl.

Причина такого странного поведения операционной системы (казалось бы, что сложного в том, чтобы просто разбить строку на части по пробелам или символам табуляции) описана, например, в этой дискуссии LKML или, более подробно, в письме Garance A Drosihn в рассылку freebsd-arch. Вкратце, если бы механизм механизм обработки shebang (в Linux — linux/fs/binfmt_script.c) передавал все аргументы интерпретатору, то для некоторых из них было бы затруднительно отделить аругменты интерпретатора от собственно аргументов вызываемого скрипта. По крайней мере, так было еще на заре развития Unix и с тех пор большая часть Unix-систем передаёт все аргументы как единую строку.

«
»

3 комментария

Write a comment - TrackBack - RSS Comments

  1. Comment by Konstantin Khomoutov:

    Это плохой стиль программирования в любом случае.
    Разумнее использовать примитив set (help set в баше для выяснения подробностей).

    Одна из главных причин использовать set — вменяемое поведение в случае, когда скрипт читается из другого скрипта (командами . или source).

    28.12.2009 @ 04:28
  2. Comment by Maxim:

    А если попробовать:
    #!/usr/bin/env “/bin/bash –posix –verbose”

    29.12.2009 @ 01:57
  3. Comment by bappoy:

    скажет, что исполняемый файл с именем "bash --posix --verbose" отсутствует

    29.12.2009 @ 13:16
Write comment

Я не робот.