Как использовать несколько аргументов для awk с shebang (т.е. #!)?
Я хотел бы выполнить 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
Это, похоже, работает для меня с (g) awk.
#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "[email protected]"
# The real awk program starts here
{ print $0 }
Обратите внимание, что #!
работает /bin/sh
, поэтому этот script сначала интерпретируется как оболочка script.
Сначала я просто попробовал "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "[email protected]"
, но awk обработал это как команду и безоговорочно распечатал каждую строку ввода. Вот почему я ввел arbitrary_long_name==0
- он должен был терпеть неудачу все время. Вы можете заменить его на какую-то строку тарабарщины. В основном, я искал ложное условие в awk, которое не отрицательно повлияло бы на оболочку script.
В оболочке script arbitrary_long_name==0
определяет переменную с именем arbitrary_long_name
и устанавливает ее равной =0
.
Ответ 2
Строка 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
.]
Это означает, что вы вообще не можете использовать какие-либо аргументы.
Ответ 3
Я столкнулся с одной и той же проблемой, без видимого решения из-за того, как обрабатываются пробелы в shebang (по крайней мере, в Linux).
Однако вы можете передать несколько опций в shebang, если они короткие, и они могут быть объединены (путь GNU).
Например, вы не можете
#!/usr/bin/foo -i -f
но вы можете иметь
#!/usr/bin/foo -if
Очевидно, что это работает только тогда, когда параметры имеют короткие эквиваленты и не принимают аргументов.
Ответ 4
В 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
в вашей системной оболочке.
Ответ 5
Хотя и не совсем переносимый, начиная с 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 "[email protected]"; do
echo "\$$i is '$arg'"
i=$((i+1))
done
Оригинальный ответ здесь.
Ответ 6
#!/bin/sh
''':'
exec YourProg -some_options "$0" "[email protected]"
'''
Вышеупомянутый трюк с оболочкой shebang более переносим, чем /usr/bin/env
.
Ответ 7
В руководстве gawk (http://www.gnu.org/manual/gawk/gawk.html) в конце раздела 1.14 обратите внимание, что вы должны использовать только один аргумент при запуске gawk из строки shebang. В нем говорится, что ОС будет обрабатывать все после того, как путь к gawk станет единственным аргументом. Возможно, есть еще один способ указать параметр --re-interval
? Возможно, ваш script может ссылаться на вашу оболочку в строке shebang, запустите gawk
в качестве команды и включите текст вашего script в качестве "здесь документа".
Ответ 8
Почему бы не использовать 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
себя;)
Ответ 9
Просто для удовольствия: существует следующее довольно странное решение, которое перенаправляет 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) и, вероятно, больше этого.
Ответ 10
Для портативного решения используйте 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 мог бы обработать его как).