Eu gostaria de executar um script gawk--re-interval
usando um shebang. A abordagem "ingênua" de
#!/usr/bin/gawk --re-interval -f
... awk script goes here
não funciona, uma vez que gawk é chamado com o primeiro argumento "--re-interval -f"
(não dividido em torno do espaço em branco), que ele não entende. Existe uma solução alternativa para isso?
Claro que você não pode chamar o gawk diretamente, mas envolvê-lo em um script de shell que divide o primeiro argumento ou fazer um script de shell que chama o gawk e coloca o script em outro arquivo, mas eu queria saber se havia alguma maneira de fazer isso dentro de um arquivo.
O comportamento das linhas shebang difere de sistema para sistema - pelo menos no Cygwin ele não divide os argumentos por espaços em branco. Eu só me preocupo em como fazer isso em um sistema que se comporta assim; o script não foi feito para ser portátil.
--re-interval
não é mais necessário (consulte [ gnu.org/software/gawk/manual/… ).Respostas:
Isso parece funcionar para mim com (g) awk.
Observe as
#!
execuções/bin/sh
, portanto, este script é primeiro interpretado como um script de shell.No início, eu simplesmente tentei
"exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"
, mas awk tratou isso como um comando e imprimiu todas as linhas de entrada incondicionalmente. É por isso que eu coloqueiarbitrary_long_name==0
- é para falhar o tempo todo. Você pode substituí-lo por algum barbante sem sentido. Basicamente, eu estava procurando por uma condição falsa no awk que não afetaria adversamente o script de shell.No script de shell, o
arbitrary_long_name==0
define uma variável chamadaarbitrary_long_name
e a define igual a=0
.fonte
bash
, ou funcionará com qualquer POSIXsh
? E não uso comawk
frequência, então não tenho certeza se meu truque na segunda linha é uma boa maneira de forçarawk
a ignorar a linha.arbitrary_long_name
não entre em conflito com uma variável usada no programa awk real, não vejo nenhum problema. Tem algo que estou perdendo?#!/bin/sh -
vez de#!/bin/sh
para proteger o script de possivelmente se comportar mal de maneira perigosa se invocado com um argumento zero que tem-
como primeiro caractere. Isso pode acontecer acidentalmente em linguagens de programação como C, onde é fácil bagunçar acidentalmente, esquecendo-se de passar o nome do programa invocado como parte da matriz do argumento paraexecve
funções semelhantes, e se as pessoas costumam esquecer de se proteger contra isso, também pode acabam sendo a última etapa em uma vulnerabilidade que pode ser explorada de forma mal-intencionada, permitindo que um invasor obtenha um shell interativo.A linha shebang nunca foi especificada como parte de POSIX, SUS, LSB ou qualquer outra especificação. AFAIK, nem mesmo foi devidamente documentado.
Há um consenso aproximado sobre o que ele faz: pegar tudo entre o
!
e o\n
eexec
isso. A suposição é que tudo entre o!
e o\n
é um caminho completo e absoluto para o intérprete. Não há consenso sobre o que acontece se contiver espaços em branco.Felizmente, 1. e 4. parecem ter morrido, mas 3. é bastante difundido, então você simplesmente não pode confiar em ser capaz de passar mais de um argumento.
E como a localização dos comandos também não é especificada em POSIX ou SUS, você geralmente usa esse único argumento passando o nome do executável para
env
para que ele possa determinar a localização do executável; por exemplo:[Obviamente, isso ainda pressupõe um caminho específico para
env
, mas existem apenas alguns sistemas onde ele vive/bin
, então geralmente é seguro. A localização deenv
é muito mais padronizada do que a localização degawk
ou, pior ainda, de algo comopython
ouruby
ouspidermonkey
.]O que significa que você não pode realmente usar quaisquer argumentos em tudo .
fonte
-S
switch que ajuda aqui, mas ele não está presente no meu Linuxenv
, e suspeito que também não esteja disponível no gygwin. @hstoerr, outros usuários em diferentes situações podem ler suas perguntas mais tarde, portanto, em geral, respostas portáteis são preferíveis, mesmo se você não precisar de portabilidade agora.#!/bin/sh
e/usr/bin/env gawk --re-interval -f my-script.awk
. Isso está correto?#!
si não é portátil. Por exemplo, o Windows não reconhece essa convenção "nativamente" de forma alguma. Um argumento único é necessário no Unix tradicionalmente para ser capaz de fazer#!/usr/bin/awk -f
.#!/usr/bin/env ruby
ou outros semelhantes.Embora não seja exatamente portátil, a partir do coreutils 8.30 e de acordo com sua documentação, você poderá usar:
Dado assim:
você vai ter:
e caso você esteja curioso
showargs
é:Resposta original aqui .
fonte
Eu me deparei com o mesmo problema, sem solução aparente por causa da forma como os espaços em branco são tratados de uma forma simples (pelo menos no Linux).
No entanto, você pode passar várias opções de uma vez, desde que sejam opções curtas e possam ser concatenadas (do jeito GNU).
Por exemplo, você não pode ter
mas você pode ter
Obviamente, isso só funciona quando as opções têm equivalentes curtos e não aceitam argumentos.
fonte
No Cygwin e no Linux, tudo após o caminho do shebang é analisado no programa como um argumento.
É possível contornar isso usando outro
awk
script dentro do shebang:Isso será executado
{system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
no awk.E isso será executado
/usr/bin/gawk --re-interval -f path/to/your/script.awk
no shell do seu sistema.fonte
O truque do shell shebang acima é mais portátil do que
/usr/bin/env
.fonte
python
, mas esta questão é sobreawk
.No manual do gawk (http://www.gnu.org/manual/gawk/gawk.html), no final da seção 1.14, observe que você deve usar apenas um único argumento ao executar o gawk a partir de uma linha shebang. Ele diz que o sistema operacional tratará tudo após o caminho para gawk como um único argumento. Talvez haja outra maneira de especificar a
--re-interval
opção? Talvez o seu script possa referenciar seu shell na linha shebang, executargawk
como um comando e incluir o texto do seu script como um "documento aqui".fonte
gawk
, mas você ainda pode ser capaz de canalizar algo em stderr (isto é, redirecionar stdout para stderr antes de canalizar para este script). Na verdade, nunca tentei fazer isso, mas desde que o primeiro processo não emita nada no stderr, pode funcionar. Você também pode criar um pipe nomeado ( linuxjournal.com/content/using-named-pipes-fifos-bash ) se quiser ter certeza de que nada mais o está usando.Por que não usar
bash
egawk
ele mesmo, para pular o shebang, ler o script e passá-lo como um arquivo para uma segunda instância degawk [--with-whatever-number-of-params-you-need]
?(-a mesma poderia naturalmente também ser realizado com por exemplo,
sed
outail
, mas eu acho que há algum tipo de beleza dependendo apenasbash
egawk
em si;)fonte
Apenas por diversão: existe a seguinte solução bastante estranha que redireciona stdin e o programa através dos descritores de arquivo 3 e 4. Você também pode criar um arquivo temporário para o script.
Uma coisa é irritante sobre isso: o shell faz expansão de variável no script, então você precisa citar cada $ (como feito na segunda linha do script) e provavelmente mais do que isso.
fonte
Para uma solução portátil, use em
awk
vez degawk
invocar o shell BOURNE padrão (/bin/sh
) com seu shebang e invoqueawk
diretamente, passando o programa na linha de comando como um documento here em vez de via stdin:Nota: nenhum
-f
argumento paraawk
. Isso deixastdin
disponível paraawk
ler a entrada de. Supondo que você tenhagawk
instalado e no seuPATH
, isso atinge tudo que eu acho que você estava tentando fazer com seu exemplo original (supondo que você queria que o conteúdo do arquivo fosse o script awk e não a entrada, o que eu acho que sua abordagem shebang teria tratado como )fonte