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

101

Я хотел бы выполнить gawk script с помощью --re-interval с помощью shebang. "Наивный" подход

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

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

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

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

  • 1
    Глупый эксперимент, который я только что провел, был с одним сценарием, использующим другой сценарий в строке shebang, который правильно разделил аргументы.
  • 0
    @Hasturkun, это поднимает еще одну проблему, что поведение линий Шебанга также отличается от системы к системе относительно того, может ли вызываемая программа сама по себе быть скриптом.
Показать ещё 2 комментария
Теги:
awk
shebang
gawk

10 ответов

20
Лучший ответ

Это, похоже, работает для меня с (g) awk.

#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"


# The real awk program starts here
{ print $0 }

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

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

В оболочке script arbitrary_long_name==0 определяет переменную с именем arbitrary_long_name и устанавливает ее равной =0.

  • 0
    Это мой ответ, но мне интересно, достаточно ли он портативный и надежный. Зависит ли это конкретно от bash или будет работать с любым POSIX sh ? И я не часто использую awk , поэтому я не уверен, что мой трюк во второй строке - хороший способ заставить awk игнорировать строку.
  • 0
    Просто то, что мне было интересно, +1, но, вероятно, нецелесообразно (отсюда и относительные голоса).
Показать ещё 1 комментарий
146

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

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

  • Некоторые операционные системы просто рассматривают всю вещь как путь. В конце концов, в большинстве операционных систем пробелы или тире являются законными в пути.
  • Некоторые операционные системы разбиваются на пробелы и обрабатывают первую часть как путь к интерпретатору, а остальные - как отдельные аргументы.
  • Некоторые операционные системы разбиваются на первые пробелы и обрабатывают переднюю часть как путь к интерпретатору, а остальные - как один аргумент (это то, что вы видите).
  • Некоторые даже не поддерживают линии shebang вообще.

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

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

#!/usr/bin/env gawk

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

Это означает, что вы вообще не можете использовать какие-либо аргументы.

  • 0
    Большое спасибо за проницательный комментарий! Но в этом случае меня не волнует переносимость, поэтому я прояснил свой вопрос по этому поводу.
  • 1
    Конверт FreeBSD имеет ключ -S который помогает здесь, но его нет в моем Linux env , и я подозреваю, что он недоступен и в gygwin. @hstoerr, другие пользователи, находящиеся в разных ситуациях, могут читать ваши вопросы позже, поэтому в целом переносимые ответы предпочтительнее, даже если вам сейчас не требуется переносимость.
Показать ещё 7 комментариев
11

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

Это можно взломать, используя другой awk script внутри 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 в вашей системной оболочке.

  • 1
    это не сработает, если вы передали аргументы скрипту
11

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

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

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

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

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

#!/usr/bin/foo -if

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

5
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''

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

  • 0
    '' ':' Является задержкой, потому что мое первоначальное решение было для скрипта на python, поэтому '' ':' говорит интерпретатору python игнорировать часть exec.
  • 2
    Я думаю, что вас опускают, потому что ваше решение для python , но этот вопрос о awk .
Показать ещё 2 комментария
3

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

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

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

3

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

  • 0
    Кажется, нет другого способа указать опцию. Вы правы: gawk -f - << EOF, несколько строк скриптов, EOF работает, но это мешает мне читать стандартный ввод с помощью gawk.
  • 0
    Здесь документ съедает стандартный поток ввода для gawk , но вы все равно можете передать что-то через stderr (то есть перенаправить stdout в stderr перед передачей в этот скрипт). Я на самом деле никогда не пробовал этого, но пока первый процесс ничего не генерирует на stderr, он может работать. Вы также можете создать именованный канал ( linuxjournal.com/content/using-named-pipes-fifos-bash ), если хотите убедиться, что больше ничего его не использует.
2

Хотя и не совсем переносимый, начиная с coreutils 8.30 и в соответствии с его документацией вы сможете использовать:

#!/usr/bin/env -S command arg1 arg2 ...

Итак, учитывая:

$ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e "this and that " too

ты получишь:

% ./test.sh 
$0 is '/usr/local/bin/showargs'
$1 is 'here'
$2 is 'is another'
$3 is 'long'
$4 is 'arg'
$5 is '-e'
$6 is 'this and that '
$7 is 'too'
$8 is './test.sh'

и в случае, если вы любопытно, showargs:

#!/usr/bin/env sh
echo "\$0 is '$0'"

i=1
for arg in "$@"; do
    echo "\$$i is '$arg'"
    i=$((i+1))
done

Оригинальный ответ здесь.

  • 0
    К вашему сведению, FreeBSD имеет -S в течение многих лет (с 6.0). Это долгожданное добавление переносимости в coreutils.
0

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

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

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

-2

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

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

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

  • 3
    Это не сработало для меня. Человек говорит, что <<< блабла кладет блаблу на стандартный ввод. Вы имели в виду << - EOF? В любом случае, это также ставит программу на стандартный ввод.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню