การใช้คำสั่ง exec ในเชลล์สคริปต์คืออะไร?


250

ทุกคนสามารถอธิบายการใช้คำสั่ง exec ในเชลล์สคริปต์ด้วยตัวอย่างง่ายๆได้อย่างไร?


31
ลิงค์ไปยัง linux.about.com ไม่เป็นประโยชน์ พวกเขาไม่ได้ทำให้ชัดเจนจากระยะไกลว่าการดำเนินการคำสั่งหรือขั้นตอนของคำสั่งโดยใช้ 'exec' แตกต่างจากเพียงแค่การดำเนินการตามปกติ ดังนั้นคำถามของ OP "การใช้ exec คืออะไร"
Jonathan Hartley

2
Stack Overflow เป็นเว็บไซต์สำหรับคำถามการเขียนโปรแกรมและการพัฒนา คำถามนี้ดูเหมือนจะไม่ได้อยู่ที่หัวข้อเพราะมันไม่เกี่ยวกับการเขียนโปรแกรมหรือการพัฒนา ดูหัวข้อใดบ้างที่ฉันสามารถถามเกี่ยวกับที่นี่ในศูนย์ช่วยเหลือ บางทีผู้ใช้ระดับสูงหรือUnix & Linux Stack Exchangeอาจเป็นที่ที่ดีกว่าสำหรับการถาม
jww

คำตอบ:


281

execฟังก์ชั่นในตัวกระจกคำสั่งใน kernel มีครอบครัวของพวกเขาอยู่บนพื้นฐานexecveซึ่งมักจะถูกเรียกจากซี

execแทนที่โปรแกรมปัจจุบันในกระบวนการปัจจุบันโดยไม่ต้องforkใช้กระบวนการใหม่ ไม่ใช่สิ่งที่คุณจะใช้ในทุกสคริปต์ที่คุณเขียน แต่มันมีประโยชน์ในบางโอกาส นี่คือบางสถานการณ์ที่ฉันใช้

  1. เราต้องการให้ผู้ใช้เรียกใช้โปรแกรมแอปพลิเคชันเฉพาะโดยไม่ต้องเข้าถึงเชลล์ เราสามารถเปลี่ยนโปรแกรมลงชื่อเข้าใช้ใน / etc / passwd แต่บางทีเราต้องการให้การตั้งค่าสภาพแวดล้อมถูกใช้จากไฟล์เริ่มต้น ดังนั้นใน (พูด) .profileคำสั่งสุดท้ายพูดว่า:

     exec appln-program

    ดังนั้นตอนนี้ไม่มีกระสุนให้กลับไป แม้ว่าจะappln-programขัดข้องผู้ใช้ปลายทางก็ไม่สามารถไปถึงเชลล์ได้เพราะมันไม่ได้อยู่ที่นั่น - execมันถูกแทนที่

  2. เราต้องการใช้เชลล์ที่แตกต่างกับหนึ่งใน / etc / passwd โง่อย่างที่เห็นบางเว็บไซต์ไม่อนุญาตให้ผู้ใช้เปลี่ยนเชลล์การลงชื่อเข้าใช้ เว็บไซต์หนึ่งฉันรู้ว่ามีการเริ่มต้นทุกคนที่มีcshและทุกคนก็ใส่ลงไปในของพวกเขา.login(ไฟล์เริ่มต้นขึ้น csh) kshเรียกร้องให้ ในขณะที่ทำงานมันออกจากcshกระบวนการหลงทางที่ทำงานและออกจากระบบเป็นสองขั้นตอนซึ่งอาจทำให้เกิดความสับสน ดังนั้นเราจึงเปลี่ยนเป็นโปรแกรมexec kshที่แทนที่ c-shell ด้วย korn เชลล์และทำให้ทุกอย่างง่ายขึ้น (มีปัญหาอื่น ๆ เช่นสิ่งkshนี้ไม่ใช่ความจริงว่าlogin-shell)

  3. เพียงเพื่อบันทึกกระบวนการ หากเราโทรหาprog1 -> prog2 -> prog3 -> prog4ฯลฯ และไม่ย้อนกลับไปให้ทำการเรียก exec ทุกครั้ง มันช่วยประหยัดทรัพยากร (ไม่มากยอมรับได้เว้นแต่จะทำซ้ำ) และทำให้การปิดเครื่องง่ายขึ้น

เห็นได้ชัดว่าคุณเคยเห็นมีการexecใช้งานที่ไหนสักแห่งบางทีถ้าคุณแสดงรหัสที่คุณใช้เราก็สามารถพิสูจน์ได้ว่าเป็นการใช้งาน

แก้ไข : ฉันรู้ว่าคำตอบข้างต้นไม่สมบูรณ์ มีอยู่สองวิธีที่ใช้execในเชลล์เช่นkshและbash- ใช้สำหรับเปิดไฟล์ descriptors นี่คือตัวอย่างบางส่วน:

exec 3< thisfile          # open "thisfile" for reading on file descriptor 3
exec 4> thatfile          # open "thatfile" for writing on file descriptor 4
exec 8<> tother           # open "tother" for reading and writing on fd 8
exec 6>> other            # open "other" for appending on file descriptor 6
exec 5<&0                 # copy read file descriptor 0 onto file descriptor 5
exec 7>&4                 # copy write file descriptor 4 onto 7
exec 3<&-                 # close the read file descriptor 3
exec 6>&-                 # close the write file descriptor 6

โปรดทราบว่าระยะห่างมีความสำคัญมากที่นี่ หากคุณเว้นช่องว่างระหว่างหมายเลข fd และสัญลักษณ์การเปลี่ยนเส้นทางแล้วเปลี่ยนexecเป็นความหมายดั้งเดิม:

  exec 3 < thisfile       # oops, overwrite the current program with command "3"

มีหลายวิธีที่คุณสามารถใช้สิ่งเหล่านี้ในการใช้ ksh read -uหรือprint -uบนbashตัวอย่างเช่น:

read <&3
echo stuff >&4

22
นอกจากนี้ยังมีการใช้งานอีกผมพบว่าค่อนข้างมีประโยชน์และมูลค่าการกล่าวขวัญที่นี่เพราะมันเกี่ยวข้องกับการใช้งานเว็บหลามและดูเหมือนว่าสิ่งที่อยู่ในระหว่าง (น่ากลัว) ของคุณคำตอบที่ 2 และ 3 ผมมักจะเรียกใช้แอพพลิเค WSGI เว็บ (พูด Django หรือขวด) ผ่านผู้บังคับบัญชาเรียกgunicornแอพ: หลังที่ต้องการตัวแปรสภาพแวดล้อมค่อนข้างน้อยมันเป็นวิธีที่ง่ายกว่าและใช้งานได้ดีกว่าในการรัน gunicorn จากเชลล์สคริปต์ที่ตั้งค่าทุกอย่างและในที่สุดก็exec gunicornให้ pid ที่ถูกต้องกลับไปยังหัวหน้างาน
Gru

1
เอกสารไม่บอกว่าexecสามารถนำมาใช้สำหรับการเปลี่ยนเส้นทาง:> ถ้าคำสั่งไม่ได้ระบุการเปลี่ยนเส้นทางใด ๆ ที่มีผลบังคับใช้ในเปลือกปัจจุบันและสถานะการส่งกลับเป็น 0 หากมีข้อผิดพลาดการเปลี่ยนเส้นทางสถานะกลับเป็น 1 แต่วิธีการที่ไม่execใช้งานได้จริงเพื่อเปลี่ยน file descriptor? เหตุใดจึงเลือกคำสั่งนี้สำหรับงานนี้ (Markdown ล้มเหลวในขณะนี้?)
เรย์

@Ray: ดีที่สุดที่ฉันสามารถทำมันได้ pubs.opengroup.org/onlinepubs/009604599/utilities/exec.html หากคุณจำเป็นต้องรู้วิธีดูที่ซอร์สโค้ดเชลล์
cdarke

7
การใช้งานอื่น: เปลี่ยนเส้นทางเอาต์พุตทั้งหมดของสคริปต์ไปยังล็อกไฟล์exec >.\logfilename.log 2>&1
Hogan

1
@Carmageddon: &>เป็นbashส่วนขยาย (ดูman bash) exec >/var/log/userdata.log 2>&1และตัวอย่างของคุณจะเทียบเท่ากับ กล่าวอีกนัยหนึ่งมันเปลี่ยนเส้นทาง stdout และ stderr ไปยังไฟล์นั้น คำสั่งที่ตามมาจะสืบทอดการเปลี่ยนเส้นทางเหล่านั้นยกเว้นว่ามีการรีเซ็ต แต่จะถูกดำเนินการ
cdarke

41

เพียงเพื่อเพิ่มคำตอบที่ได้รับการยอมรับกับคำตอบสั้น ๆ สั้น ๆ execมือใหม่ง่ายคุณอาจไม่จำเป็นต้อง

หากคุณยังอยู่ที่นี่การสนทนาต่อไปนี้ควรจะเปิดเผยว่าทำไม เมื่อคุณวิ่งพูด

sh -c 'command'

คุณเรียกใช้shอินสแตนซ์จากนั้นเริ่มcommandเป็นลูกของshอินสแตนซ์นั้น เมื่อcommandเสร็จสิ้นshอินสแตนซ์ก็จะเสร็จสิ้น

sh -c 'exec command'

เรียกใช้shอินสแตนซ์จากนั้นแทนที่shอินสแตนซ์นั้นด้วยcommandไบนารีและเรียกใช้งานแทน

แน่นอนว่าสิ่งทั้งสองนี้ไร้ประโยชน์ในบริบทที่ จำกัด นี้ คุณเพียงแค่ต้องการ

command

commandมีบางสถานการณ์ที่ขอบที่คุณต้องการเปลือกในการอ่านแฟ้มการกำหนดค่าหรืออย่างใดอย่างอื่นตั้งค่าสภาพแวดล้อมเช่นการเตรียมความพร้อมสำหรับการทำงานที่มี นี่เป็นสถานการณ์เดียวที่exec commandค่อนข้างมีประโยชน์

#!/bin/sh
ENVIRONMENT=$(some complex task)
exec command

สิ่งนี้ทำบางสิ่งบางอย่างเพื่อเตรียมสภาพแวดล้อมเพื่อให้มีสิ่งที่จำเป็น เมื่อดำเนินการเสร็จสิ้นshอินสแตนซ์นั้นไม่จำเป็นอีกต่อไปดังนั้นจึงเป็นการเพิ่มประสิทธิภาพ (เล็กน้อย) เพื่อแทนที่shอินสแตนซ์ด้วยcommandกระบวนการแทนที่จะshเรียกใช้เป็นกระบวนการลูกและรอให้มันออกแล้วออกจากทันทีที่เสร็จสิ้น

ในทำนองเดียวกันถ้าคุณต้องการเพิ่มทรัพยากรให้มากที่สุดเท่าที่จะเป็นไปได้สำหรับคำสั่ง heavyish ที่ส่วนท้ายของเชลล์สคริปต์คุณอาจต้องการexecคำสั่งนั้นเป็นการปรับให้เหมาะสม

หากกองกำลังบางสิ่งบางอย่างให้คุณสามารถทำงานshแต่คุณอยากจะทำงานอย่างอื่นexec something elseเป็นของหลักสูตรการแก้ปัญหาที่จะเปลี่ยนที่ไม่พึงประสงค์shเช่น (อย่างเช่นถ้าคุณอยากจะทำงานเรียบร้อยของตัวเองgoshแทนshแต่คุณไม่ได้อยู่ใน/etc/shellsเพื่อให้คุณสามารถ ไม่ได้ระบุว่าเป็นเปลือกเข้าสู่ระบบของคุณ)

การใช้งานครั้งที่สองexecเพื่อจัดการไฟล์ descriptors เป็นหัวข้อแยกต่างหาก คำตอบที่ได้รับการยอมรับนั้นครอบคลุมอย่างดี เพื่อให้มีอยู่ในตัวเองฉันจะเพียงแค่เลื่อนไปที่คู่มือสำหรับสิ่งที่execตามด้วยการเปลี่ยนเส้นทางแทนชื่อคำสั่ง


2
bushต่อต้านการทดลองที่จะเรียกเปลือกสวยงามของคุณเอง แน่นอนว่าสิ่งนี้ใช้ได้กับbashUnix shell ที่เป็นที่นิยมเช่นกัน; แต่เป็น @anishsane บันทึกทุบตีแอบเพิ่มประสิทธิภาพโดยการทำจริงbash -c 'command' exec command
tripleee

1
รหัสทางออกของเชลล์โดยทั่วไปคือรหัสทางออกของคำสั่งสุดท้ายที่เรียกใช้งาน แน่นอนถ้าเชลล์ไม่สามารถรันหรือรันคำสั่งสถานะการออกของเชลล์จะสะท้อนให้เห็นว่ามีรหัสข้อผิดพลาดที่เหมาะสม
tripleee

2
@JanathanLeffler ฉันตั้งใจจัดทำ antipattern ซึ่งฉันเห็นในคำถามเกี่ยวกับมือใหม่ สำเนานี้ได้รับแจ้งจากสำเนานี้แต่ฉันเคยเห็นมาก่อนดังนั้นฉันจึงต้องการให้ครอบคลุม
tripleee

2
@ JonathanLeffler ถ้อยคำผู้เยาว์ปรับแต่ง; คุณคิดว่าเพียงพอหรือไม่ ขอบคุณสำหรับความคิดเห็น.
tripleee

2
ขอบคุณ - ฉันเพิ่มย่อหน้าสั้น ๆ เกี่ยวกับการเพิ่มประสิทธิภาพนี้ มันไม่ชัดเจนสำหรับฉันถ้าคุณมีการคัดค้านอื่น ๆ หรือถ้าคุณแค่อยากจะอธิบายสิ่งต่าง ๆ จากมุมที่แตกต่าง
tripleee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.