ใช้เคส / ตัวอย่างการปฏิบัติสำหรับ Bash 'builtin exec


12

พิจารณาจากเอกสารของ Bash 'builtin exec:

exec แทนที่เชลล์โดยไม่ต้องสร้างกระบวนการใหม่

โปรดระบุกรณีการใช้งาน / ตัวอย่างการปฏิบัติ ฉันไม่เข้าใจว่าสิ่งนี้สมเหตุสมผลหรือไม่

ฉัน googled และพบเกี่ยวกับI / O เปลี่ยนเส้นทาง คุณช่วยอธิบายให้ดีขึ้นได้ไหม?


unix.stackexchange.com/search?q=exec+shell+-findสำหรับตัวอย่างบางอย่าง
Stéphane Chazelas

คำตอบ:


18

execมักจะใช้ในเชลล์สคริปต์ซึ่งส่วนใหญ่ทำหน้าที่เป็น wrappers สำหรับการเริ่มไบนารีอื่น ๆ ตัวอย่างเช่น:

#!/bin/sh

if stuff;
    EXTRA_OPTIONS="-x -y -z"
else
    EXTRA_OPTIONS="-a foo"
fi

exec /usr/local/bin/the.real.binary $EXTRA_OPTIONS "$@"

ดังนั้นหลังจากที่ wrapper รันเสร็จแล้วไบนารี "ของจริง" จะเข้ามาแทนที่และจะไม่มีการติดตามของสคริปต์ตัวตัดคำที่ครอบครองสล็อตเดียวกันชั่วคราวในตารางกระบวนการอีกต่อไป ไบนารี "ของจริง" เป็นลูกโดยตรงของอะไรก็ตามที่เปิดตัวแทนที่จะเป็นหลาน

คุณพูดถึงการเปลี่ยนเส้นทาง I / O ในคำถามของคุณด้วย นั่นเป็นกรณีการใช้งานที่แตกต่างออกไปexecและไม่มีอะไรเกี่ยวข้องกับการแทนที่เชลล์ด้วยกระบวนการอื่น เมื่อexecไม่มีข้อโต้แย้งเช่นนั้น:

exec 3>>/tmp/logfile

ดังนั้นการเปลี่ยนทิศทาง I / O บนบรรทัดคำสั่งจะมีผลในกระบวนการเชลล์ปัจจุบัน แต่กระบวนการเชลล์ปัจจุบันยังคงทำงานอยู่และย้ายไปยังคำสั่งถัดไปในสคริปต์


1
คุณอาจพูดได้ว่าทั้งสองกรณีเกี่ยวข้องกันทั้งสองกรณีexecบอกให้เชลล์ไม่ทำการกระทำ (ดำเนินการคำสั่งหรือทำการเปลี่ยนเส้นทาง) ในกระบวนการลูก แต่อยู่ในกระบวนการเดียวกัน
Stéphane Chazelas

5

ฉันใช้ shell execbuiltin เพื่อรับรหัสกระบวนการ (PID) ไปยังโปรแกรม Java อาจมีวิธีรับ PID จากภายใน Java ตอนนี้ แต่เมื่อหลายปีก่อนไม่มี เมื่อกระบวนการมี PID ของตัวเองก็สามารถเขียนออกไปที่ไฟล์ PID (ค้นหา/var/run/ชื่อไฟล์ด้วยคำต่อท้าย '.pid') เพื่อให้โปรแกรมการจัดการทราบ PID ของกระบวนการทำงานและเพื่อป้องกันอินสแตนซ์ที่สอง ของเซิร์ฟเวอร์เดียวกันไม่ให้ทำงาน มันใช้งานได้เช่นนี้:

exec java -cp=YourServer.jar StartClass -p $$

รหัสในmain()วิธีการเรียนStartClassจัดการแยกวิเคราะห์อาร์กิวเมนต์และสามารถหา ID กระบวนการของตัวเอง


2

เพื่อความสนุกสนานให้เรียกใช้โปรแกรมต่อไปนี้ (แปลเป็นภาษาที่คุณเลือกใช้งาน) ในพื้นหลังในระบบที่มีการบัญชีและข้อ จำกัด ของกระบวนการผู้ใช้

while(true) fork();

ตอนนี้ทุกสล็อตในตารางกระบวนการที่คุณได้รับอนุญาตให้ใช้นั้นเต็มไปด้วยสำเนาของโปรแกรมที่รันอยู่คุณตั้งใจจะฆ่ามันอย่างไร การเปิดตัว kill (1) ต้องใช้สล็อตกระบวนการอื่นซึ่งคุณไม่มี มันจะเป็นประโยชน์หากมีเชลล์ที่จะแทนที่ตัวเองด้วยคำสั่ง kill ...

exec /bin/kill -9 -1

(สมมติว่าระบบของคุณมีการฆ่า (1) ที่ / bin / kill "exec` ซึ่ง kill` -9 -1 "อาจปลอดภัยกว่า) ซึ่งจะส่ง SIGKILL ไปยังทุกกระบวนการที่คุณทำได้

(หมายเหตุ: อย่าล็อกเอาต์จากเชลล์เรียกใช้งานของคุณเว้นแต่ว่าข้อ จำกัด ของกระบวนการจะอนุญาตให้ล็อกอินสล็อตใหม่สำหรับเชลล์ของกระบวนการซึ่งจะเป็นการยากมากขึ้นในการล้างหากคุณทำฉันไม่ได้ทำเช่นนี้ใน ต้นยุค 90 ไม่)


3
(1) คำตอบนี้จะดีขึ้นเล็กน้อยถ้าคุณแสดงexecคำสั่งที่เป็นประโยชน์ในสถานการณ์นี้ (2) คำตอบนี้ค่อนข้างล้าสมัย killคำสั่งที่ได้รับคำสั่ง builtin ในทุบตีเป็นเวลาหลายปีที่ผ่านมาส่วนใหญ่เนื่องจากความกังวลนี้
G-Man กล่าวว่า 'Reinstate Monica'

@ G-Man: คุณเข้าใจว่ารายการของคุณ (2) ทำให้คำตอบนี้เป็นคำตอบที่แม่นยำสำหรับ OP หรือไม่
Eric Towers

ไม่ฉันไม่เข้าใจสิ่งนั้น กรุณาอธิบายให้ฉัน
G-Man กล่าวว่า 'Reinstate Monica'

4
ฉันไม่ได้ติดตามคุณ คำถามที่ไม่ได้ขอตัวอย่างการปฏิบัติของทุกทุบตีในตัวคำสั่ง; มันขอตัวอย่างของexec- และความจริงที่ว่าkillบิลท์อินนั้นไม่มีส่วนเกี่ยวข้องกับexecบิลด์
G-Man กล่าวว่า 'Reinstate Monica'

1
ฉันเพิ่งอ่านการอัปเดตของคุณสำหรับคำตอบของคุณ (1) เดาอะไร หากตารางกระบวนการเต็มการทดแทนคำสั่ง (เช่น`which kill`) จะไม่ทำงานเช่นกัน (2) BTW $(…)แนะนำให้ใช้`…`แบบฟอร์มเหนือแบบฟอร์ม (3) แต่ไม่มีอันตรายใด ๆ เกี่ยวกับการคาดเดาที่ไดเรกทอรี หากคุณพิมพ์โดยไม่ตั้งใจexec /binn/killคุณจะได้รับข้อความแสดงข้อผิดพลาดและเปลือกของคุณจะไม่หายไป (4) แต่คุณไม่จำเป็นต้องกังวลว่าkillจะ  execใช้ไดเร็กตอ$PATHรี่อะไรเหมือนคำสั่งปกติ, ใช้exec kill …งานได้ (สมมติว่าคุณมี/binในพา ธ การค้นหา)
G-Man กล่าวว่า 'Reinstate Monica'

1
  • นี่คล้ายกับตัวอย่างของ Bruce ที่ต้องการทราบ PID ของกระบวนการ:

    (cmdpid = $ BASHPID; (sleep 300; kill "$ cmdpid") & สั่งรันคำสั่งยาว )

    ที่คุณ

    1. เริ่ม subshell (ด้านนอก(และ))
    2. ค้นหา PID ของ subshell ( $$จะให้ PID ของเชลล์หลัก)
    3. แยกส่วนย่อยที่ฆ่ากระบวนการของคุณหลังจากหมดเวลาและ
    4. เรียกใช้คำสั่งในกระบวนการของเชลล์ย่อยที่คุณสร้างในขั้นตอนที่ 1

    สิ่งนี้จะทำงานlong-running-commandแต่สำหรับระยะเวลาที่กำหนดไว้ล่วงหน้าที่ จำกัด ไว้เท่านั้น 

  • นี้เป็นเล็ก ๆ น้อย ๆ เล็ก ๆ น้อย ๆ แต่ถ้าคุณตัดสินใจว่าคุณต้องการที่จะเป็นราก (หรือบางส่วนของผู้อื่น) exec suสำหรับส่วนที่เหลือของเซสชั่นการเข้าสู่ระบบของคุณคุณจะทำได้

    จริงๆแล้วฉันสามารถจินตนาการถึงสถานการณ์ที่สิ่งนี้จะมีประโยชน์จริงๆ สมมติว่าคุณเข้าสู่ระบบระยะไกลและด้วยเหตุผลบางประการมีปัญหาในการหยุดการเชื่อมต่อและเริ่มการเชื่อมต่อใหม่ ตัวอย่างเช่นสมมติว่าระบบรีโมตมีไฟร์วอลล์ที่ตามกำหนดการ คุณได้รับอนุญาตให้เชื่อมต่อเมื่อคุณทำและการเชื่อมต่อที่สร้างขึ้นไม่ได้ถูกปิด แต่ในเวลาปัจจุบันการเชื่อมต่อใหม่จะไม่ได้รับการยอมรับ

    คุณทำสิ่งที่คุณต้องการแล้วและคุณพร้อมที่จะออกจากระบบแล้ว Bob เพื่อนของคุณอยู่ในห้องกับคุณและเขาต้องการทำงานกับระบบระยะไกล - แต่เขาจะไม่สามารถเชื่อมต่อได้ ดังนั้นคุณพิมพ์exec su - bobและเมื่อพรอมต์รหัสผ่านปรากฏให้เปลี่ยนเวิร์กสเตชันไปหาเขา ขณะนี้ไม่มีโพรซีเดอร์กับ UID ของคุณ (เว้นแต่คุณจะรันบางอย่างในพื้นหลัง) ดังนั้น Bob จะไม่สามารถยุ่งกับไฟล์ของคุณ เขาจะเข้าควบคุมการเชื่อมต่อของคุณอย่างมีประสิทธิภาพ (ด้วยความยินยอมและความร่วมมือจากคุณ)

    หมายเหตุ:

    • suหลักสูตรนี้จะไม่ทำงานถ้าคุณไม่ได้รับอนุญาตให้ทำงาน
    • มันจะเข้าสู่ระบบดังนั้นคุณอาจต้องอธิบายแรงจูงใจของคุณให้ใครสักคน เนื่องจากคุณกำลังหลีกเลี่ยงนโยบาย (กำหนดเวลาไฟร์วอลล์) คุณอาจประสบปัญหา
    • ฉันไม่รับประกันว่าปลอดภัย 100% ตัวอย่างเช่นwhoอาจจะยังคงแสดงชื่อของคุณ เป็นไปได้ว่าบางโปรแกรม (เขียนไม่ดี) จะใช้สิ่งนั้นเพื่อคิดว่าบ็อบเป็นคุณและให้เขาเข้าถึงทรัพยากรของคุณ
    • หากระบบทำการตรวจสอบการกระทำของ Bob อาจถูกตรวจสอบภายใต้ชื่อของคุณ

โปรดสังเกตว่าในทางปฏิบัติในเชลล์ส่วนใหญ่(a;b)แล้วจะเหมือนกับ(a;exec b)เชลล์ที่ปรับส้อมสำหรับคำสั่งสุดท้ายในเชลล์ย่อยให้เหมาะสม ยกเว้นเพียงคนเดียวที่ดูเหมือนจะเป็นและbash mkshการใช้execช่วยรับประกันได้
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.