AWK: ¿por qué $ (cat) funciona para stdin, pero $ * no?

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

La sintaxis anterior funciona bien con el resultado calculado '1337'.

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

Pero la sintaxis anterior no funciona, aunque no hay error.

Por favor aconsejar.

usuario58029
fuente

Respuestas:

13

La $(command)sintaxis devolverá la salida de command. Aquí, está utilizando el catprograma muy simple cuyo único trabajo es copiar todo desde la entrada estándar (stdin) a la salida estándar (stdout). Como está ejecutando el awkscript entre comillas dobles, el $(cat)shell lo expande antes deawk ejecutar el script, por lo que lee el echoresultado en su stdin y lo copia debidamente en su stdout. Esto luego se pasa al awkscript. Puedes ver esto en acción con 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

Entonces, en awkrealidad se está ejecutando BEGIN{ print ((3+(2^3)) * 34^2 / 9)-75.89 }'y devuelve 1337.

Ahora, $*es una variable de shell especial que se expande a todos los parámetros posicionales dados a un script de shell (ver 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.

Sin embargo, esta variable está vacía aquí. Por lo tanto, el awkguión se convierte en:

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

El se $*expande a una cadena vacía, y awkse le dice que imprima una cadena vacía, y es por eso que no obtiene salida.


Es posible que desee usar bcen su lugar:

$ echo '((3+(2^3)) * 34^2 / 9)-75.89' | bc
1336.11
terdon
fuente
Probablemente debería usar bc -l, de lo contrario obtendrá la discrepancia que ha publicado anteriormente (donde el resultado de la división se ha truncado).
cmbuckley
@cmbuckley Estaba tratando de imprimir 1337 jugando scale=(supongo que el OP quiere jugar con leetspeak) pero no pude encontrar una manera. bc -lvuelve 1336.99888888888888888888a mi sistema
terdon el