จะพิมพ์ชื่อสคริปต์ของตัวเองใน mawk ได้อย่างไร?


13

ใน bash $0มีชื่อของสคริปต์ แต่ใน awk ถ้าฉันทำสคริปต์ชื่อ myscript.awk ด้วยเนื้อหาต่อไปนี้:

#!/usr/bin/awk -f
BEGIN{ print ARGV[0] }

และเรียกใช้มันจะพิมพ์ "awk" เท่านั้น นอกจากนี้ ARGV [i] กับ i> 0 ยังใช้สำหรับอาร์กิวเมนต์ของสคริปต์ในบรรทัดคำสั่งเท่านั้น ดังนั้นวิธีที่จะทำให้มันพิมพ์ชื่อของสคริปต์ในกรณีนี้ "myscript.awk"?


ฉันเปลี่ยนชื่อจาก awk เป็น mawk เพราะโซลูชันทั้งหมดต้องการ gawk และไม่ทำงานกับ awk ทั่วไปและโดยเฉพาะอย่างยิ่งกับ mawk ที่ใช้กันอย่างแพร่หลาย (เช่นค่าเริ่มต้นบน Ubuntu)
cipper

อะไรที่ทำให้คุณคิดว่าmawkเป็นค่าเริ่มต้นบน Ubuntu เมื่อวันที่ 15.04 VM ของฉันเริ่มต้นคือawk gawkในขณะที่ติดตั้ง mawk มันไม่ได้เป็นค่าเริ่มต้น
terdon

1
มันเป็นสคริปต์ awk awk -f myscript.awkถ้าคุณเรียกมันว่าโดย อย่างไรก็ตามสิ่งนี้ไม่เกี่ยวข้องกับปัญหาที่เป็นปัญหา
cipper

1
@EdMorton มันเป็นสคริปต์เพราะมันเริ่มต้นด้วยawk #!/usr/bin/awk -fเชลล์สคริปต์เริ่มต้นด้วย#!/bin/sh(หรือสิ่งที่คล้ายกัน)
Barmar

1
ฉันได้พูดคุยกับผู้เชี่ยวชาญเชลล์หลายคนและพยายามหาคำตอบที่ชัดเจนว่าเป็นเชลล์หรือสคริปต์ awk และประหลาดใจตาม POSIX การตีความไฟล์ที่ขึ้นต้นด้วย #! ไม่ได้กำหนดและไม่มีชื่อประเภทเฉพาะ ในขณะที่บางคนเรียกมันว่า "hash bang interpreter script" แทนที่จะเป็น shell หรือ awk script, ฉันทามติดูเหมือนว่าควรได้รับการพิจารณาว่าเป็นสคริปต์ awk แม้ว่าเคอร์เนล (ไม่ใช่เชลล์) ตีความบรรทัดแรกเพราะ awk ยังคง จะต้องมีความสามารถที่จะแยกว่าบรรทัดแรกเกินไป (เป็นความคิดเห็น) awk -f fileและคุณสามารถดำเนินการได้โดยใช้
Ed Morton

คำตอบ:


5

ด้วย GNU awk 4.1.3 ในการทุบตีบน cygwin:

$ cat tst.sh
#!/bin/awk -f
BEGIN { print "Executing:", ENVIRON["_"] }

$ ./tst.sh
Executing: ./tst.sh

ฉันไม่รู้ว่าพกพาไปได้อย่างไร แม้ว่าเช่นเคยฉันจะไม่เรียกใช้สคริปต์ awk โดยใช้ shebang ในเชลล์สคริปต์เพราะมันจะทำให้คุณไม่สามารถใช้งานได้ ทำให้มันง่ายและเพียงทำแทน:

$ cat tst2.sh
awk -v cmd="$0" '
BEGIN { print "Executing:", cmd }
' "$@"

$ ./tst2.sh
Executing: ./tst2.sh

สุดท้ายนี้จะทำงานร่วมกับ awk ที่ทันสมัยในเชลล์ใด ๆ บนแพลตฟอร์มใด ๆ


โปรดทราบว่าคนแรกทำงานเฉพาะในทุบตี zsh หรือ ksh ต่อมาเป็นเรื่องเกี่ยวกับเชลล์สคริปต์ไม่ใช่สคริปต์ awk
cuonglm

2
ขอขอบคุณ! ENVIRON["_"]ทำงานได้อย่างสมบูรณ์และไม่เรียกโปรแกรมภายนอกใด ๆ ตัวเลือกที่สองawk -v ...ขึ้นอยู่กับวิธีการเรียกใช้สคริปต์ ฉันไม่ต้องการสิ่งนี้
cipper

1
การโทรหาสคริปต์ของคุณtst.shทำให้เข้าใจผิด มันเป็นawkสคริปต์ไม่ใช่สคริปต์ของเชลล์ BEGINไม่ใช่คำสั่งเชลล์ที่ถูกต้อง
Barmar

1
ใช่ แต่คำถามเกี่ยวกับการพกพาไม่ใช่ "คือ ENVIRON [] พกพา" เป็น "จะENVIRON["_"]สร้างเส้นทางเชลล์สคริปต์การโทรเมื่อพิมพ์จากทุก awk ที่เรียกผ่านทาง shebang จากทุกเชลล์"? ฉันไม่เคยเรียกสคริปต์ awk จาก shebang มาหาฉันโดยส่วนตัวแล้วไม่สนใจคำตอบ แต่แค่คิดว่าฉันจะพูดถึงมัน .... โอ้ฉันเห็นความคิดเห็นข้างต้นที่ @cuonglm ตอบว่ามันรองรับเฉพาะบางเชลล์เท่านั้น .
Ed Morton

1
จุดดี @Ed ตรวจสอบว่าเป็นความล้มเหลวในเส้นประ (ซึ่งจะส่งกลับคำสั่งก่อนหน้า (หรือเปลือกตัวเอง) มากกว่าคำสั่งปัจจุบัน) ksh93 น่าสนใจคำนำหน้า PID *12345*/tmp/test.awkในเครื่องหมายดอกจันเช่น ARGV[0]มีความน่าเชื่อถือawkในการประ, ทุบตี, zsh และ ksh93 เสมอ
Adam Katz

5

ฉันไม่คิดว่ามันเป็นไปได้ตามgawk เอกสาร :

ในที่สุดค่าของARGV[0](ดูหัวข้อ 7.5 ตัวแปรในตัว) จะแตกต่างกันไปขึ้นอยู่กับระบบปฏิบัติการของคุณ บางระบบวางไว้ที่awkนั่นบางชื่อพา ธ เต็มของ awk (เช่น/bin/awk) และบางระบบใส่ชื่อสคริปต์ของคุณ ('คำแนะนำ') อย่าพึ่งพาค่าของARGV[0]การให้ชื่อสคริปต์ของคุณ

ในวันที่linuxคุณสามารถลองใช้ชนิดของสับสกปรกและเป็นชี้ไปในการแสดงความคิดเห็นโดยStéphane Chazelasมันเป็นไปได้ถ้าการดำเนินการawkสนับสนุน NUL ไบต์:

#!/usr/bin/awk -f

BEGIN { getline t < "/proc/self/cmdline"; split(t, a, "\0"); print a[3]; }

ดูเหมือนว่าสคริปต์ของคุณจะไม่ทำงาน มันพิมพ์ "k" ถ้าเรียกด้วย "awk -f script.awk" และพิมพ์ "s" ถ้าเรียกโดย "./script.awk"
cipper

@cipper: ที่นี่จะทำงานร่วมกับgawkและล้มเหลว (เช่นคำอธิบายของคุณ) mawkกับ ! ที่น่าสนใจ

มันใช้งานได้สำหรับฉันใน linux awk- 4.0.2 ใน FreeBSD ด้วย/proc/curpoc/cmdlineและawkผลเป็นเหมือนคุณ gawkแต่ทำงานร่วมกับ
taliezin

ในอูบุนตูเริ่มต้นมันไม่ทำงาน มันจะดีที่จะหาทางออกแบบพกพา
cipper

1
@taliezin: คำตอบโดย cuonglm ไม่ใช่วิธีการแก้ปัญหาเนื่องจากต้องการให้ฟีดสคริปต์ด้วยชื่อของมันเอง มันเหมือนกับการโทรawk -vNAME="myscript.awk" ./myscript.awkแล้วพิมพ์ NAME ภายในสคริปต์ ไม่ใช่ทางออก
cipper

5

ฉันไม่ทราบวิธีการรับชื่อคำสั่งโดยตรงจากภายใน awk อย่างไรก็ตามคุณสามารถค้นหาผ่านเชลล์ย่อย

เพ่งพิศ

ด้วย GNU awk และpsคำสั่งคุณสามารถใช้ ID กระบวนการจากPROCINFO["PID"]เพื่อดึงชื่อคำสั่งเป็นวิธีแก้ปัญหา ตัวอย่างเช่น:

cmdname.awk

#!/usr/bin/gawk -f

BEGIN {
  ("ps -p " PROCINFO["pid"] " -o comm=") | getline CMDNAME
  print CMDNAME
}

เหยี่ยวและนกเหยี่ยว

คุณสามารถใช้วิธีการเดียวกันได้ แต่รับawkPID จาก$PPIDตัวแปรเชลล์พิเศษ (PID ของพาเรนต์):

cmdname.awk

#!/usr/bin/mawk -f

BEGIN { 
  ("ps -p $PPID -o comm=") | getline CMDNAME
  print CMDNAME
}

การทดสอบ

เรียกใช้สคริปต์เช่นนี้:

./cmdname.awk

เอาต์พุตในทั้งสองกรณี:

cmdname.awk

ฉันพบข้อผิดพลาด: / bin / sh: 1: -o: ไม่พบ
cipper

@cipper: ใช้งานได้กับ GNU awk เท่านั้นฉันเพิ่มบรรทัด shebang ที่หายไป
Thor

จากgawk manual : ตาม POSIX, 'expression | getline 'ไม่ชัดเจนหากนิพจน์มีตัวดำเนินการที่ไม่ยึดติดที่ไม่ใช่' $ '- ตัวอย่างเช่น' "echo" "date" | getline 'ไม่ชัดเจนเนื่องจากโอเปอเรเตอร์การต่อข้อมูลไม่ได้อยู่ในวงเล็บ คุณควรเขียนเป็น '("echo" "date") | getline 'ถ้าคุณต้องการให้โปรแกรมของคุณพกพาไปได้ทุกที่
cipper

1
ถ้ามันต้องการgawkมันเป็นgawkวิธีการแก้ปัญหาแทนการawkแก้ปัญหา ฉันคิดว่า @cipper ควรเพิ่มความปรารถนาในการ "แก้ปัญหาแบบพกพา" ให้กับคำถาม

1
@Thor: คำตอบโดย cuonglm ไม่ใช่วิธีการแก้ปัญหาเนื่องจากต้องการให้ฟีดสคริปต์ด้วยชื่อของมันเอง มันเหมือนกับการโทรawk -vNAME="myscript.awk" ./myscript.awkแล้วพิมพ์ NAME ภายในสคริปต์ ไม่ใช่ทางออก
cipper

4

ด้วย POSIX awk:

#!/usr/bin/awk -f

BEGIN {
    print ENVIRON["AWKSCRIPT"]
}

แล้ว:

AWKSCRIPT=test.awk ./test.awk
test.awk

5
คุณป้อนชื่อสคริปต์ด้วยตนเองนี่ไม่ใช่วิธีการพิมพ์ด้วยตัวเอง
cipper

@cipper: นั่นเป็นวิธีที่ง่ายและสะดวกในการพกพา
cuonglm

3
มันเหมือนกับการโทรawk -vNAME="myscript.awk" ./myscript.awkแล้วพิมพ์ตัวแปรNAMEภายในสคริปต์ ไม่ใช่ทางออก
cipper

@cipper: mawkนั่นเป็นวิธีเดียวที่ถ้าคุณพูดถึง และยังมีการใช้ENVIRONไม่ได้เช่นเดียวกับการใช้-vNAME="myscript.awk"ตั้งแต่เมื่อจะขยายลำดับหนีในmawk NAME
cuonglm

4

ใช้ GNU awk

การตรวจสอบคู่มือผู้ใช้ GNU awk - 7.5.2 ตัวแปรในตัวที่ถ่ายทอดข้อมูลที่ฉันสะดุดเมื่อ:

PROCINFO #

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

PROCINFO [ "pid"]

ID กระบวนการของกระบวนการปัจจุบัน

ซึ่งหมายความว่าคุณสามารถทราบ PID ของโปรแกรมในระหว่างรันไทม์ จากนั้นจึงเป็นเรื่องของการใช้system()เพื่อค้นหากระบวนการด้วย PID ที่กำหนดนี้:

#!/usr/bin/gawk -f
BEGIN{ pid=PROCINFO["pid"]
       system("ps -ef | awk '$2==" pid " {print $NF}'")
}

ฉันใช้ps -efซึ่งจะแสดง PID ในคอลัมน์ที่ 2 สมมติว่าการดำเนินการเสร็จสิ้นแล้วawk -f <script>และไม่มีพารามิเตอร์อื่น ๆ เราสามารถสรุปฟิลด์สุดท้ายของบรรทัดที่มีข้อมูลที่เราต้องการ

ในกรณีที่เรามีพารามิเตอร์บางอย่างเราจะต้องแยกบรรทัดที่แตกต่างกัน - หรือดีกว่าใช้ตัวเลือกบางอย่างของการpsพิมพ์เพียงคอลัมน์ที่เราสนใจ

ทดสอบ

$ awk -f a.awk 
a.awk
$ cp a.awk hello.awk
$ awk -f hello.awk 
hello.awk

โปรดทราบว่าอีกบทหนึ่งของคู่มือผู้ใช้ GNU awk บอกเราว่า ARGV ไม่ใช่วิธีที่จะไป:

1.1.4 โปรแกรมปฏิบัติการ awk

ท้ายที่สุดค่าของ ARGV [0] (ดูตัวแปรในตัว) จะแตกต่างกันไปตามระบบปฏิบัติการของคุณ บางระบบใส่ 'awk' ไว้ที่นั่นบางระบบใส่ชื่อพา ธ แบบเต็มของ awk (เช่น / bin / awk) และบางระบบใส่ชื่อสคริปต์ของคุณ ('คำแนะนำ') (dc) อย่าพึ่งพาค่าของ ARGV [0] เพื่อระบุชื่อสคริปต์ของคุณ


น่าเสียดายที่ PROCINFO เป็นเพียงคุณสมบัติเพ่งพิศ ตัวอย่างเช่นมันไม่สามารถใช้ได้ใน mawk (ซึ่งติดตั้งโดยค่าเริ่มต้นในอูบุนตู)
cipper

ฉันรู้ ... ทำไมคุณติดแท็กคำถามด้วย [gawk]?
fedorqui

คุณถูก. เมื่อฉันโพสต์คำถามที่ฉันไม่ได้ตระหนักถึงความแตกต่างเหล่านี้ระหว่างเหยี่ยวและเพ่งพิศ แท็กเปลี่ยนเป็น mawk ทันที
cipper

@cipper ดี:) ฉันกำลังทดสอบกับจริงmawkและไม่สามารถใช้งานได้ดังนั้นฉันจึงติดตั้งgawkใน Ubuntu และใช้งานได้ ดังนั้นวิธีแก้ปัญหาสามารถใช้ได้gawk: D
fedorqui

1
@terdon gawkไม่ได้รับการติดตั้งเป็นค่าเริ่มต้นบน Ubuntu (หรืออย่างน้อย Ubuntu บางรุ่นซึ่งmawkเป็นawkการนำไปใช้งานเริ่มต้น) IIRC ฉันต้องติดตั้งเช่นกันบน Debian
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.