AWK: dlaczego $ (cat) działa dla standardowego wejścia, a $ * nie?


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

Powyższa składnia działa dobrze z obliczonym wynikiem „1337”.

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

Ale powyższa składnia nie działa, chociaż nie ma błędu.

Proszę doradzić.

Odpowiedzi:


13

$(command)Składnia powróci wyjście command. Tutaj używasz bardzo prostego catprogramu, którego jedynym zadaniem jest skopiowanie wszystkiego ze standardowego wejścia (stdin) na standardowe wyjście (stdout). Ponieważ awkskrypt jest uruchamiany w podwójnych cudzysłowach, $(cat)jest on rozszerzany przez powłokę przed uruchomieniem awkskryptu, więc odczytuje dane echowyjściowe do standardowego wejścia i odpowiednio kopiuje je na standardowe wyjście. To jest następnie przekazywane do awkskryptu. Możesz to zobaczyć w akcji z 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

Tak awknaprawdę działa, BEGIN{ print ((3+(2^3)) * 34^2 / 9)-75.89 }'co zwraca 1337.

Teraz $*jest to specjalna zmienna powłoki, która rozwija się do wszystkich parametrów pozycyjnych podanych w skrypcie powłoki (patrz 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.

Jednak ta zmienna jest tutaj pusta. Dlatego awkskrypt staje się:

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

$*Rozwija do pustego łańcucha, i awkdowiaduje się, aby wydrukować pusty ciąg, i dlatego nie masz wyjścia.


Zamiast tego możesz po prostu użyć bc:

$ echo '((3+(2^3)) * 34^2 / 9)-75.89' | bc
1336.11

Powinieneś prawdopodobnie użyć bc -l, w przeciwnym razie otrzymasz rozbieżność, którą opublikowałeś powyżej (w której wynik podziału został obcięty).
cmbuckley,

@cmbuckley Próbowałem zmusić go do wydrukowania 1337, grając z scale=(zakładam, że OP chce grać z leetspeak), ale nie mogłem znaleźć sposobu. bc -lpowraca 1336.99888888888888888888w moim systemie.
terdon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.