AWK: Warum funktioniert $ (cat) für stdin, $ * aber nicht?

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

Die obige Syntax funktioniert gut mit dem berechneten Ergebnis '1337'.

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

Die obige Syntax funktioniert jedoch nicht, obwohl kein Fehler vorliegt.

Bitte beraten.

user58029
quelle

Antworten:

13

Die $(command)Syntax gibt die Ausgabe von zurück command. Hier verwenden Sie das sehr einfache catProgramm, dessen einzige Aufgabe darin besteht, alles von der Standardeingabe (stdin) in die Standardausgabe (stdout) zu kopieren. Da Sie das awkSkript in doppelten Anführungszeichen ausführen, wird das Skript vor dem Ausführen des Skripts $(cat)von der Shell erweitert , sodass es die Ausgabe in sein stdin liest und es ordnungsgemäß in sein stdout kopiert. Dies wird dann an das Skript übergeben. Sie können dies in Aktion sehen mit :awkechoawkset -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

Läuft awkalso tatsächlich BEGIN{ print ((3+(2^3)) * 34^2 / 9)-75.89 }'was 1337 zurückgibt.

Jetzt ist das $*eine spezielle Shell-Variable, die auf alle Positionsparameter erweitert wird, die einem Shell-Skript zugewiesen wurden (siehe 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.

Diese Variable ist hier jedoch leer. Daher wird das awkSkript:

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

Das wird $*zu einer leeren Zeichenfolge erweitert und aufgefordert, eine leere Zeichenfolge awkzu drucken. Aus diesem Grund erhalten Sie keine Ausgabe.


Vielleicht möchten Sie bcstattdessen einfach Folgendes verwenden:

$ echo '((3+(2^3)) * 34^2 / 9)-75.89' | bc
1336.11
Terdon
quelle
Sollte wahrscheinlich verwenden bc -l, sonst erhalten Sie die Diskrepanz, die Sie oben gepostet haben (wo das Ergebnis der Teilung abgeschnitten wurde).
cmbuckley
@cmbuckley Ich habe versucht, 1337 durch Herumspielen zum Drucken zu bringen scale=(ich nehme an, das OP möchte mit leetspeak spielen), aber ich konnte keinen Weg finden. bc -lkehrt 1336.99888888888888888888auf meinem System zurück.
Terdon