AWK: pourquoi $ (cat) fonctionne-t-il pour stdin, mais $ * ne fonctionne pas?

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

La syntaxe ci-dessus fonctionne très bien avec le résultat calculé '1337'.

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

Mais la syntaxe ci-dessus ne fonctionne pas, bien qu'il n'y ait pas d'erreur.

Plz conseille.

user58029
la source

Réponses:

13

La $(command)syntaxe renverra la sortie de command. Ici, vous utilisez le catprogramme très simple dont le seul travail est de tout copier de l'entrée standard (stdin) vers la sortie standard (stdout). Puisque vous exécutez le awkscript entre guillemets doubles, le $(cat)est développé par le shell avant l' awkexécution du script, il lit donc la echosortie dans son stdin et le copie dûment dans sa stdout. Ceci est ensuite transmis au awkscript. Vous pouvez le voir en action avec 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

Donc, awkest en cours d'exécution BEGIN{ print ((3+(2^3)) * 34^2 / 9)-75.89 }'qui renvoie 1337.

Maintenant, $*c'est une variable shell spéciale qui s'étend à tous les paramètres positionnels donnés à un script shell (voir 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.

Cependant, cette variable est vide ici. Par conséquent, le awkscript devient:

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

Le se $*développe en une chaîne vide et awkest invité à imprimer une chaîne vide, et c'est pourquoi vous n'obtenez aucune sortie.


Vous voudrez peut-être simplement utiliser à la bcplace:

$ echo '((3+(2^3)) * 34^2 / 9)-75.89' | bc
1336.11
terdon
la source
Devrait probablement être utilisé bc -l, sinon vous obtiendrez la différence que vous avez publiée ci-dessus (où le résultat de la division a été tronqué).
cmbuckley
@cmbuckley J'essayais de le faire imprimer 1337 en jouant avec scale=(je suppose que l'OP veut jouer avec leetspeak) mais je n'ai pas trouvé de moyen. bc -lrevient 1336.99888888888888888888sur mon système.
terdon