AWK: почему $ (cat) работает на stdin, а $ * нет?

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

Приведенный выше синтаксис отлично работает с вычисленным результатом «1337».

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

Но приведенный выше синтаксис не работает, хотя ошибки нет.

Плз советую.

user58029
источник

Ответы:

13

$(command)Синтаксис возвращает вывод command. Здесь вы используете очень простую catпрограмму, единственной задачей которой является копирование всего из стандартного ввода (stdin) в стандартный вывод (stdout). Так как вы запускаете awkскрипт в двойных кавычках, то $(cat)расширяется оболочки передawk тем скрипт запускается, так что он читает echoвывод в его стандартный ввод и надлежащим образом копии его в стандартный вывод. Затем это передается в awkсценарий. Вы можете увидеть это в действии с 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

Итак, awkна самом деле работает, BEGIN{ print ((3+(2^3)) * 34^2 / 9)-75.89 }'который возвращает 1337.

Теперь $*это специальная переменная оболочки, которая распространяется на все позиционные параметры, заданные сценарию оболочки (см. 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.

Однако эта переменная здесь пуста. Следовательно, awkскрипт становится:

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

$*Расширяется пустой строкой, и awkсказал , чтобы напечатать пустую строку, и поэтому вы не получите никакого вывода.


Вы можете просто использовать bcвместо этого:

$ echo '((3+(2^3)) * 34^2 / 9)-75.89' | bc
1336.11
terdon
источник
Вероятно, следует использовать bc -l, в противном случае вы получите расхождение, которое вы разместили выше (где результат деления был усечен).
19
@ cmbuckley Я пытался заставить его напечатать 1337, играя с scale=(я предполагаю, что ОП хочет играть с leetspeak), но я не мог найти способ. bc -lвозвращается 1336.99888888888888888888в мою систему.
Terdon