Я хотел бы выполнить 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 не предназначен для переноски.
Это, похоже, работает для меня с (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
.
bash
или будет работать с любым POSIX sh
? И я не часто использую awk
, поэтому я не уверен, что мой трюк во второй строке - хороший способ заставить awk
игнорировать строку.
Строка shebang никогда не указывалась как часть POSIX, SUS, LSB или любой другой спецификации. AFAIK, он даже не был должным образом задокументирован.
Существует приблизительное мнение о том, что он делает: возьмите все между !
и \n
и exec
. Предполагается, что все между !
и \n
является полным абсолютным путем к интерпретатору. Не существует единого мнения о том, что произойдет, если оно содержит пробелы.
К счастью, 1. и 4. похоже, вымерли, но 3. довольно широко распространены, поэтому вы просто не можете полагаться на возможность передать более одного аргумента.
И поскольку расположение команд также не указано в POSIX или SUS, вы обычно используете этот единственный аргумент, передавая исполняемое имя env
, чтобы он мог определить исполняемое местоположение; например:.
#!/usr/bin/env gawk
[Очевидно, что это все еще предполагает определенный путь для env
, но существует только очень мало систем, где он живет в /bin
, поэтому это в целом безопасно. Расположение env
намного стандартизировано, чем расположение gawk
или даже хуже, чем python
или ruby
или spidermonkey
.]
Это означает, что вы вообще не можете использовать какие-либо аргументы.
-S
который помогает здесь, но его нет в моем Linux env
, и я подозреваю, что он недоступен и в gygwin. @hstoerr, другие пользователи, находящиеся в разных ситуациях, могут читать ваши вопросы позже, поэтому в целом переносимые ответы предпочтительнее, даже если вам сейчас не требуется переносимость.
В 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
в вашей системной оболочке.
Я столкнулся с одной и той же проблемой, без видимого решения из-за того, как обрабатываются пробелы в shebang (по крайней мере, в Linux).
Однако вы можете передать несколько опций в shebang, если они короткие, и они могут быть объединены (путь GNU).
Например, вы не можете
#!/usr/bin/foo -i -f
но вы можете иметь
#!/usr/bin/foo -if
Очевидно, что это работает только тогда, когда параметры имеют короткие эквиваленты и не принимают аргументов.
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''
Вышеупомянутый трюк с оболочкой shebang более переносим, чем /usr/bin/env
.
python
, но этот вопрос о awk
.
Почему бы не использовать 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
себя;)
В руководстве gawk (http://www.gnu.org/manual/gawk/gawk.html) в конце раздела 1.14 обратите внимание, что вы должны использовать только один аргумент при запуске gawk из строки shebang. В нем говорится, что ОС будет обрабатывать все после того, как путь к gawk станет единственным аргументом. Возможно, есть еще один способ указать параметр --re-interval
? Возможно, ваш script может ссылаться на вашу оболочку в строке shebang, запустите gawk
в качестве команды и включите текст вашего script в качестве "здесь документа".
gawk
, но вы все равно можете передать что-то через stderr (то есть перенаправить stdout в stderr перед передачей в этот скрипт). Я на самом деле никогда не пробовал этого, но пока первый процесс ничего не генерирует на stderr, он может работать. Вы также можете создать именованный канал ( linuxjournal.com/content/using-named-pipes-fifos-bash ), если хотите убедиться, что больше ничего его не использует.
Хотя и не совсем переносимый, начиная с 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
Оригинальный ответ здесь.
Просто для удовольствия: существует следующее довольно странное решение, которое перенаправляет 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) и, вероятно, больше этого.
Для портативного решения используйте 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 мог бы обработать его как).