มี 2 ​​วิธีในการตั้งค่า awk vars ผ่านบรรทัดคำสั่งหรือไม่


10

ฉันสังเกตเห็นawkตัวอย่างO'Reilly (1997) ซึ่งกำหนดตัวแปร awk โดยการตั้งค่าบนบรรทัดคำสั่งหลังจากโปรแกรม - ข้อความ มันไม่ทำงาน แต่ฉันไม่สามารถหารูปแบบนี้ในมนุษย์ / ข้อมูล awk ฉันเพิ่งพลาดมันไป มันลดค่า ... ไวยากรณ์เดียวที่ฉันเห็นในคู่มือเป็น-vตัวเลือก

awk '/home/{print foo, bar}' foo="cat" bar="dog" /proc/$$/cmdline

เอาท์พุท: cat dog

คำตอบ:


11

เป็นจริงใน POSIX awk(ลิงก์ไปยัง POSIX 2008 เวอร์ชันก่อนหน้ามีเหมือนกันฉันเชื่อ) -vอธิบายไว้ในส่วนตัวเลือกวิธีอื่น ๆ ในส่วนของตัวถูกดำเนินการ

มีความแตกต่างระหว่าง-vและผ่านการมอบหมายในตอนท้ายด้วยชื่อไฟล์:

  • ด้วย-v:

แอปพลิเคชันจะต้องทำให้แน่ใจว่าอาร์กิวเมนต์การมอบหมายนั้นอยู่ในรูปแบบเดียวกับตัวถูกดำเนินการที่ได้รับมอบหมาย การกำหนดตัวแปรที่ระบุจะเกิดขึ้นก่อนที่จะดำเนินการโปรแกรม awk รวมถึงการกระทำที่เกี่ยวข้องกับรูปแบบ BEGIN (ถ้ามี) สามารถระบุได้หลายครั้งของตัวเลือกนี้

  • ผสมกับชื่อไฟล์:

[... ] การกำหนดตัวแปรแต่ละตัวนั้นจะเกิดขึ้นก่อนการประมวลผลของไฟล์ต่อไปนี้ถ้ามี ดังนั้นการกำหนดค่าก่อนอาร์กิวเมนต์ไฟล์แรกจะถูกดำเนินการหลังจากการกระทำ BEGIN (ถ้ามี) ในขณะที่การกำหนดค่าหลังจากอาร์กิวเมนต์ไฟล์สุดท้ายจะเกิดขึ้นก่อนการดำเนินการ END (ถ้ามี) หากไม่มีข้อโต้แย้งไฟล์จะต้องดำเนินการกำหนดค่าก่อนประมวลผลอินพุตมาตรฐาน

ตัวอย่าง:

$ cat input 
hello
hello
$ awk -v var=one 'BEGIN{print var} /hello/{print var} END{print var}' \
    var=two input var=three input var=four
one
two
two
three
three
four

ว้าว! นั่นเป็นการเพิ่มจุดควบคุมที่น่าสนใจ ... มันมีประโยชน์มาก ขอบคุณ ...
Peter.O

1
"ว้าว!" เริ่มแรกของฉัน ยังคงมีอยู่ แต่มันก็ค่อนข้างจะอารมณ์โดยการมองหาคำตอบของ Arcegeต่อไป ... ฉันทดสอบด้วยไฟล์จริงชื่อ "var = สาม" ... awkให้ความสำคัญกับการกำหนดตัวแปร ... นี่เป็นข้อพิสูจน์ที่สำคัญ เช่น ในทุกกรณีเมื่อชื่อไฟล์มีรูปแบบนี้จะถูกละเว้นและตัวแปรจะถูกตั้งค่า ... ดูเหมือนว่าวิธีเดียวที่จะหลีกเลี่ยงการปะทะกันนี้คือการทำให้มั่นใจว่าชื่อไฟล์สำหรับไดเรกทอรีการทำงานปัจจุบันจะต้องนำหน้าเสมอกับเส้นทางญาติของพวกเขา:./var=three
Peter.O

@ Peter.O ใช่นั่นเป็นสาเหตุที่ทำให้มีการ-vใช้ไวยากรณ์ คุณควรนึกถึง-vไวยากรณ์ว่าเป็นวิธีที่เหมาะสมในการทำงานที่ได้รับมอบหมายไปข้างหน้า
dubiousjim

@ Peter.O จุดที่ยอดเยี่ยมเกี่ยวกับ "gotcha" ถ้าชื่อไฟล์เป็นการกำหนดตัวแปรที่ถูกต้อง หากคุณใช้ตัวแปรเชลล์ที่มีชื่อไฟล์และส่งผ่านเป็นอาร์กิวเมนต์awkคุณสามารถใช้การจับต่อไปนี้:[ "$myfile" == "${myfile#/}" ] && myfile="./$myfile"
Wildcard

4

awkนี้เป็นแบบเก่าของตัวแปรภายนอกการตั้งค่าใน มันคลุมเครือ (เกิดอะไรขึ้นถ้าคุณมีชื่อไฟล์foo=cat) ดังนั้นรุ่นที่ใหม่กว่าจึงเพิ่ม-vตัวเลือก มันอาจจะทำงานได้กับความเข้ากันได้แบบย้อนหลัง แต่คุณไม่สามารถรับประกันได้ และอย่างที่ฉันบอกว่า-vตัวเลือกนั้นใหม่กว่าดังนั้นบางเวอร์ชั่นawkอาจไม่รองรับ


ความคิดเห็นของคุณเกี่ยวกับความเป็นไปได้ของการปะทะชื่อไฟล์นั้นดี ... ฉันได้ทำการทดสอบแล้วและมันก็เป็นปัญหาอย่างแน่นอน ฉันได้เขียนเพิ่มอีกเล็กน้อยในความคิดเห็นต่อคำตอบของ Mat .. Thansk สำหรับการเน้นปัญหานี้ (+1)
Peter.O

2
ที่จริงตามที่อธิบายไว้ใน [Mat s answer](http://unix.stackexchange.com/a/34258/9537), -v` และการกำหนดอาร์กิวเมนต์จะแตกต่างกันเมื่อพวกเขามีผลบังคับใช้ ยัง-vอยู่ใน POSIX และควรมีอยู่ในทุกส่วนยกเว้นการawkใช้งานที่เก่าแก่ที่สุด การใช้./หรือทำให้แน่ใจว่าชื่อไฟล์มีอักขระที่ไม่ใช่ตัวระบุน่าจะเป็นวิธีที่เชื่อถือได้ที่สุดในการแก้ปัญหา
jw013
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.