Как использовать несколько аргументов для awk с shebang (т. е. #!)?


Я хотел бы выполнить поглазеть скрипт --re-interval С помощью shebang. "Наивный" подход

#!/usr/bin/gawk --re-interval -f
... awk script goes here

не работает, так как gawk вызывается с первым аргументом "--re-interval -f" (не рассыпается вокруг пробела), который он не понимает. Есть ли обходной путь для этого?

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

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

9   100   2010-11-29 14:04:21

9 ответов:

это, кажется, работает для меня с (g)awk.

#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "" "[email protected]"


# The real awk program starts here
{ print  }

Примечание #! работает /bin/sh, поэтому этот скрипт сначала интерпретируется как сценарий оболочки.

сначала я просто пробовал "exec" "/usr/bin/gawk" "--re-interval" "-f" "" "[email protected]", но awk рассматривал это как команду и распечатывал каждую строку ввода безоговорочно. Вот почему я поставил в arbitrary_long_name==0 - он должен все время терпеть неудачу. Вы можете заменить его какой-нибудь тарабарщиной. В принципе, я искал ложное условие в awk, которое не будет негативно влияет на сценарий оболочки.

в shell-скрипт, тег arbitrary_long_name==0 определяет переменную с именем arbitrary_long_name и устанавливает его равным =0.

линия shebang никогда не была указана как часть POSIX, SUS, LSB или любой другой спецификации. АФАИК, это даже не было должным образом задокументировано.

существует грубый консенсус о том, что он делает: возьмите все между ! и \n и exec его. Предполагается, что все между ! и \n - это полный путь к интерпретатору. Нет единого мнения о том, что произойдет, если он содержит пробел.

  1. некоторые операционные системы просто рассматривать все это как путь. В конце концов, в большинстве операционных систем пробелы или тире являются законными в пути.
  2. некоторые операционные системы разделяются на пробелы и рассматривают первую часть как путь к интерпретатору, а остальные-как отдельные аргументы.
  3. некоторые операционные системы разделены на первый пробелы и лечить передняя часть как путь к интерпретатором и остальные как single аргумент (который является то, что вы видите).
  4. некоторые даже не поддерживают shebang линии на всех.

к счастью, 1. и 4. вроде бы вымерли, но 3. довольно распространена, поэтому вы просто не можете полагаться на возможность передать более одного аргумента.

и поскольку расположение команд также не указано в POSIX или SUS, вы обычно используете этот единственный аргумент, передавая исполняемый файл имя до env, так что это можно определить местоположение исполняемого файла; например:

#!/usr/bin/env gawk

[очевидно, это еще предполагает определенный путь для env, но есть только очень мало систем, где он живет в /bin, так что это вполне безопасно. Расположение env является гораздо более стандартизированным, чем расположение gawk или еще хуже что-то вроде python или ruby или spidermonkey.]

что означает, что вы не можете использовать любой аргументы на всех.

я столкнулся с той же проблемой, без видимого решения из-за того, как пробелы обрабатываются в shebang (по крайней мере, на Linux).

тем не менее, вы можете передать несколько вариантов в shebang, пока они короткие варианты и они могут быть сцепленные (путь GNU).

например, вы не можете иметь

#!/usr/bin/foo -i -f

но вы можете иметь

#!/usr/bin/foo -if

очевидно, что это работает только тогда, когда параметры имеют короткие эквиваленты и не принимают никаких аргументов.

в Cygwin и Linux все После пути shebang анализируется в программе как один аргумент.

Это можно взломать вокруг этого с помощью другого awk скрипт внутри shebang:

#!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}

это будет выполняться {system("/usr/bin/gawk --re-interval -f " FILENAME); exit} в awk.
И это будет исполнять /usr/bin/gawk --re-interval -f path/to/your/script.awk в вашей системной оболочке.

#!/bin/sh
''':'
exec YourProg -some_options "" "[email protected]"
'''

вышеупомянутый трюк shebang shell является более портативным, чем /usr/bin/env.

в руководстве gawk (http://www.gnu.org/manual/gawk/gawk.html), конец раздела 1.14 обратите внимание, что вы должны использовать только один аргумент при запуске gawk из линии shebang. В нем говорится, что ОС будет рассматривать все После пути к gawk как один аргумент. Возможно, есть другой способ указать ? Возможно, ваш скрипт может ссылаться на вашу оболочку в строке shebang, run gawk как команда, и включить текст вашего скрипта в качестве "здесь документа".

почему бы не использовать bash и gawk сам, чтобы пропустить мимо shebang, прочитайте скрипт и передайте его как файл во второй экземпляр gawk [--with-whatever-number-of-params-you-need]?

#!/bin/bash
gawk --re-interval -f <(gawk 'NR>3'  )
exit
{
  print "Program body goes here"
  print 
}

(- то же самое, естественно, может быть выполнено, например, с sed или tail, но я думаю, что есть какая-то красота зависит только от bash и ;)

просто для удовольствия: есть следующее довольно странное решение, которое перенаправляет stdin и программу через файловые дескрипторы 3 и 4. Вы также можете создать временный файл для скрипта.

#!/bin/bash
exec 3>&0
exec <<-EOF 4>&0
BEGIN {print "HALLO"}
{print $1}
EOF
gawk --re-interval -f <(cat 0>&4) 0>&3

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

для портативного решения, использовать awk, а не gawk, вызовите стандартную оболочку Борна (/bin/sh) С вашим shebang, и вызвать awk непосредственно, передавая программу в командной строке как документ here, а не через stdin:

#!/bin/sh
gawk --re-interval <<<EOF
PROGRAM HERE
EOF

Примечание: нет до awk. Вот и выходит stdin доступно для awk для чтения входных данных. Если у вас есть gawk установлен и на вашем PATH, это достигает всего, что я думаю, что вы были пытаясь сделать с вашим оригинальным примером (предполагая, что вы хотите, чтобы содержимое файла было сценарием awk, а не входным сигналом, который, я думаю, ваш подход shebang рассматривал бы его как).