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 $* }"

แต่ไวยากรณ์ข้างต้นไม่ทำงานแม้ว่าจะไม่มีข้อผิดพลาด

กรุณาให้คำแนะนำ

คำตอบ:


13

ไวยากรณ์จะกลับมาส่งออกของ$(command) commandที่นี่คุณกำลังใช้catโปรแกรมอย่างง่ายที่มีเพียงงานที่จะคัดลอกทุกอย่างจากอินพุตมาตรฐาน (stdin) ไปยังเอาต์พุตมาตรฐาน (stdout) เนื่องจากคุณกำลังรันawkสคริปต์ภายในเครื่องหมายคำพูดคู่คำสั่ง$(cat)จะถูกขยายโดยเชลล์ก่อนที่awkสคริปต์จะรันดังนั้นจึงอ่านechoเอาต์พุตลงใน stdin และคัดลอกสคริปต์ไปยัง stdout อย่างถูกต้อง สิ่งนี้จะถูกส่งผ่านไปยัง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 }'ซึ่งส่งกลับ 1,337

ตอนนี้$*เป็นตัวแปรเชลล์พิเศษที่ขยายไปยังพารามิเตอร์ตำแหน่งทั้งหมดที่กำหนดให้กับเชลล์สคริปต์ (ดู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

น่าจะใช้bc -lมิฉะนั้นคุณจะได้รับความคลาดเคลื่อนที่คุณโพสต์ไว้ด้านบน (ซึ่งผลลัพธ์ของการหารถูกตัดทอน)
cmbuckley

@ cmbuckley ฉันพยายามพิมพ์ 1337 โดยเล่นกับscale=(ฉันคิดว่า OP ต้องการเล่นกับ leetspeak) แต่ฉันหาทางไม่เจอ bc -lส่งคืน1336.99888888888888888888ในระบบของฉัน
terdon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.