AWK: por que $ (cat) funciona para stdin, mas $ * não?

9
echo '((3+(2^3)) * 34^2 / 9)-75.89' | awk "BEGIN{ print $(cat) }"

A sintaxe acima funciona bem com o resultado calculado '1337'.

echo '((3+(2^3)) * 34^2 / 9)-75.89' | awk "BEGIN{ print $* }"

Mas a sintaxe acima não funciona, embora não haja erro.

Plz aconselhar.

user58029
fonte

Respostas:

13

A $(command)sintaxe retornará a saída de command. Aqui, você está usando o catprograma muito simples , cuja única tarefa é copiar tudo, desde a entrada padrão (stdin) até a saída padrão (stdout). Como você está executando o awkscript entre aspas duplas, ele $(cat)é expandido pelo shell antes da awkexecução do script, para que ele leia a echosaída em seu stdin e o copie adequadamente para seu stdout. Isso é passado para o awkscript. Você pode ver isso em ação com set -x:

$ set -x
$ echo '((3+(2^3)) * 34^2 / 9)-75.89' | awk "BEGIN{ print $(cat) }"
+ echo '((3+(2^3)) * 34^2 / 9)-75.89'
++ cat
+ awk 'BEGIN{ print ((3+(2^3)) * 34^2 / 9)-75.89 }'
1337

Então, awkestá realmente em execução, BEGIN{ print ((3+(2^3)) * 34^2 / 9)-75.89 }'que retorna 1337.

Agora, $*é uma variável especial do shell que se expande para todos os parâmetros posicionais fornecidos a um script de shell (consulte man bash):

   *      Expands to the positional parameters, starting from one.  When the expan
          sion  is not within double quotes, each positional parameter expands to a
          separate word.  In contexts where it is performed, those words  are  sub
          ject  to  further word splitting and pathname expansion.  When the expan
          sion occurs within double quotes, it expands to a single  word  with  the
          value  of each parameter separated by the first character of the IFS spe
          cial variable.  That is, "$*" is equivalent to "$1c$2c...",  where  c  is
          the  first  character of the value of the IFS variable.  If IFS is unset,
          the parameters are separated by spaces.  If IFS is null,  the  parameters
          are joined without intervening separators.

No entanto, essa variável está vazia aqui. Portanto, o awkscript se torna:

$ echo '((3+(2^3)) * 34^2 / 9)-75.89' | awk "BEGIN{ print $* }"
+ awk 'BEGIN{ print  }'
+ echo '((3+(2^3)) * 34^2 / 9)-75.89'

O $*expande para uma sequência vazia e awké solicitado que imprima uma sequência vazia, e é por isso que você não obtém saída.


Você pode usar apenas bc:

$ echo '((3+(2^3)) * 34^2 / 9)-75.89' | bc
1336.11
Terdon
fonte
Provavelmente deve usar bc -l, caso contrário, você terá a discrepância postada acima (onde o resultado da divisão foi truncado).
precisa saber é o seguinte
@cmbuckley Eu estava tentando imprimir 1337 brincando scale=(presumo que o OP queira brincar com o leetspeak), mas não consegui encontrar uma maneira. bc -lretorna 1336.99888888888888888888no meu sistema.
terdon