คำสั่ง“ exec” ทำอะไร?


108

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


คุณคุ้นเคยกับกระบวนการที่เป็นอย่างไร
fkraiem

1
@fkraiem คุณหมายถึงอะไร
becko

ขอโทษฉันหมายถึง "อะไร" : p แต่คำตอบนั้นดูเหมือนจะไม่
fkraiem

แต่ที่จริงแล้วสคริปต์ของคุณใช้execวิธีพิเศษซึ่งสามารถอธิบายได้ง่ายกว่านี้ฉันจะเขียนคำตอบ
fkraiem

1
ที่เกี่ยวข้อง: unix.stackexchange.com/q/296838/85039
Sergiy Kolodyazhnyy

คำตอบ:


88

man bash พูดว่า:

exec [-cl] [-a name] [command [arguments]]
      If command is specified, it replaces the shell.  No new  process
      is  created.  The arguments become the arguments to command.  If
      the -l option is supplied,  the  shell  places  a  dash  at  the
      beginning  of  the  zeroth  argument passed to command.  This is
      what login(1) does.  The -c option causes command to be executed
      with  an empty environment.  If -a is supplied, the shell passes
      name as the zeroth argument to the executed command.  If command
      cannot  be  executed  for  some  reason, a non-interactive shell
      exits, unless the execfail shell option  is  enabled.   In  that
      case,  it returns failure.  An interactive shell returns failure
      if the file cannot be executed.  If command  is  not  specified,
      any  redirections  take  effect  in  the  current shell, and the
      return status is 0.  If there is a redirection error, the return
      status is 1.

สองบรรทัดสุดท้ายเป็นสิ่งสำคัญ: หากคุณรันexecด้วยตัวเองโดยไม่มีคำสั่งมันจะทำให้การเปลี่ยนเส้นทางใช้กับเชลล์ปัจจุบัน คุณอาจรู้ว่าเมื่อคุณรันcommand > fileเอาต์พุตของcommandถูกเขียนไปยังfileแทนที่จะไปยังเทอร์มินัลของคุณ (ซึ่งเรียกว่าการเปลี่ยนเส้นทาง ) หากคุณรันexec > fileแทนการเปลี่ยนทิศทางจะใช้กับเชลล์ทั้งหมด: เอาต์พุตใด ๆ ที่สร้างโดยเชลล์จะถูกเขียนไปยังfileแทนที่จะเป็นเทอร์มินัลของคุณ ตัวอย่างที่นี่

bash-3.2$ bash
bash-3.2$ exec > file
bash-3.2$ date
bash-3.2$ exit
bash-3.2$ cat file
Thu 18 Sep 2014 23:56:25 CEST

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


42
นี่เป็นเพียงคำอธิบายบางส่วนเท่านั้น execทำหน้าที่ในการแทนที่กระบวนการเชลล์ปัจจุบันด้วยคำสั่งเพื่อให้ผู้ปกครองไปทางและเด็กเป็นเจ้าของ pid สิ่งนี้ไม่เพียง แต่จะเปลี่ยนเส้นทาง กรุณาเพิ่มข้อมูลนี้
Sergiy Kolodyazhnyy

3
ติดตามความคิดเห็นของ @ SergiyKolodyazhnyy ตัวอย่างที่ผมเคยพบเพียงซึ่งทำให้ฉันหน้านี้คือ docker-entrypoint.sh ซึ่งหลังจากดำเนินการต่างๆในการตั้งค่า Nginx exec nginx <various nginx arguments>บรรทัดสุดท้ายของสคริปต์ ซึ่งหมายความว่า nginx รับช่วง pid ของสคริปต์ทุบตีและตอนนี้ nginx เป็นกระบวนการทำงานหลักของคอนเทนเนอร์ไม่ใช่สคริปต์ ฉันคิดว่านี่เป็นเพียงความสะอาดเว้นแต่มีคนอื่นรู้เหตุผลที่เป็นรูปธรรมมากกว่า
ลุคกริฟฟิ ธ ส์

1
@Luke สิ่งนี้เรียกว่า "wrapper script" ตัวอย่างของสิ่งนั้นคือgnome-terminalอย่างน้อย 14.04 ซึ่งมีสคริปต์ตัวตัดเพื่อตั้งค่าอาร์กิวเมนต์ และนั่นคือจุดประสงค์เพียงอย่างเดียวของพวกเขา - กำหนดศิลปะและสิ่งแวดล้อม อีกกรณีหนึ่งคือการล้างข้อมูล - กำจัดอินสแตนซ์ก่อนหน้าของกระบวนการก่อนและเปิดตัวใหม่
Sergiy Kolodyazhnyy

อีกexecตัวอย่างที่คล้ายกับnginxตัวอย่างที่กำหนดโดย @LukeGriffiths เป็น~/.vnc/xstartupสคริปต์ที่vncserverใช้ในการกำหนดค่ากระบวนการเซิร์ฟเวอร์ VNC แล้วexec gnome-sessionหรือexec startkdeและอื่น ๆ
เทรเวอร์บอยด์สมิ ธ

@LukeGriffiths เหตุผลหลักexecในสคริปต์เริ่มต้นคอนเทนเนอร์คือ PID 1 ซึ่งเป็น ENTRYPOINT ของคอนเทนเนอร์มีความสำคัญเป็นพิเศษใน Docker เป็นกระบวนการหลักที่รับสัญญาณและเมื่อมีอยู่คอนเทนเนอร์จะออกจากด้วย execเพียงวิธีที่จะนำshออกจากสายการบังคับบัญชานี้และทำให้ daemon เป็นกระบวนการหลักของคอนเทนเนอร์
kkm

46

exec เป็นคำสั่งที่มีพฤติกรรมที่แตกต่างกันสองอย่างขึ้นอยู่กับว่ามีอย่างน้อยหนึ่งอาร์กิวเมนต์ที่ใช้กับมันหรือไม่มีการใช้อาร์กิวเมนต์เลย

  • หากมีการส่งผ่านอาร์กิวเมนต์อย่างน้อยหนึ่งรายการจะมีการใช้ชื่อแรกเป็นชื่อคำสั่งและexecพยายามเรียกใช้งานเป็นคำสั่งที่ส่งผ่านอาร์กิวเมนต์ที่เหลือหากมีไปยังคำสั่งนั้นและจัดการการเปลี่ยนเส้นทางหากมี

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

  • หากคำสั่งนั้นมีอยู่และสามารถใช้งานได้มันจะแทนที่เชลล์ปัจจุบัน นั่นหมายความว่าหากexecปรากฏในสคริปต์คำแนะนำในการเรียกการเรียกใช้จะไม่ถูกดำเนินการ (เว้นแต่execจะอยู่ในเชลล์ย่อย) execไม่กลับมา กับดักหอยเช่น "EXIT" จะไม่ถูกเรียกเช่นกัน

  • หากไม่มีการส่งผ่านอาร์กิวเมนต์จะexecใช้เพื่อกำหนดตัวอธิบายไฟล์เชลล์ปัจจุบันเท่านั้น เชลล์ดำเนินการต่อหลังจากexecไม่เหมือนกับเคสก่อนหน้านี้ แต่อินพุตมาตรฐานเอาต์พุตข้อผิดพลาดหรือตัวอธิบายไฟล์ใด ๆ ที่ถูกเปลี่ยนทิศทางจะมีผล

  • หากการเปลี่ยนเส้นทางบางอย่างใช้/dev/nullอินพุตใด ๆ จากมันจะส่งคืน EOF และเอาต์พุตใด ๆ ไปยังมันจะถูกยกเลิก

  • คุณสามารถปิดอธิบายไฟล์โดยใช้เป็นแหล่งที่มาหรือปลายทางเช่น- exec <&-การอ่านหรือเขียนครั้งต่อมาจะล้มเหลว

นี่คือสองตัวอย่าง:

echo foo > /tmp/bar
exec < /tmp/bar # exec has no arguments, will only affect current shell descriptors, here stdin
cat # simple command that read stdin and write it to stdout

สคริปต์นี้จะแสดงผล "foo" เป็นคำสั่ง cat แทนที่จะรออินพุตของผู้ใช้อย่างที่ควรทำในกรณีปกติจะรับอินพุตจากไฟล์ / tmp / bar ซึ่งมี foo

echo foo > /tmp/bar
exec wc -c < /tmp/bar # exec has two arguments, the control flow will switch to the wc command
cat

สคริปต์นี้จะแสดง4(จำนวนไบต์ใน / tmp / bar) และสิ้นสุดทันที catคำสั่งจะไม่ได้รับการดำเนินการ


4
`บางโพสต์เก่าไม่เคยแก่เลย ... +1
Cbhihe

3
หากการเปลี่ยนเส้นทางบางส่วนใช้ / dev / null ตัวอธิบายไฟล์ที่เกี่ยวข้องจะถูกปิด ไม่มันเปลี่ยนเส้นทางไป / จาก/dev/nullดังนั้นการเขียนยังคงสำเร็จและอ่านคืน EOF close(2)บน fd อาจทำให้เกิดการเรียกระบบการอ่าน / เขียนเพื่อส่งคืนข้อผิดพลาดและคุณทำexec 2>&-เช่นนั้น
Peter Cordes

2
ลองด้วยตัวคุณเอง:: exec 3</dev/null; ls -l /proc/self/fdโปรดทราบว่า fd 3 จะเปิดอ่านอย่างเดียวใน / dev / null จากนั้นให้ปิดอีกครั้งด้วยexec 3<&-และคุณจะเห็น ( ls -l /proc/$$/fdอีกครั้ง) ว่ากระบวนการเชลล์ของคุณไม่มี fd 3 อีกต่อไป (การปิด stdin ด้วยexec <&-จะมีประโยชน์ในสคริปต์ แต่เป็นการโต้ตอบกันโดยมีการออกจากระบบ)
Peter Cordes

@PeterCordes คุณพูดถูก อัปเดตคำตอบแล้ว ขอบคุณ!
jlliagre

1
คำตอบนี้ดีมากเพราะอธิบายทั้งสองกรณีการใช้งานของexecคำตอบที่ได้รับการโหวตมากที่สุดในปัจจุบันเท่านั้นที่พูดถึงเกี่ยวกับกรณีใช้หนึ่งและอีกคำตอบโดย g_p พูดถึงเกี่ยวกับกรณีใช้อื่น ๆ เท่านั้น และคำตอบนี้ดีและกระชับ / อ่านง่ายสำหรับเรื่องที่ซับซ้อน
เทรเวอร์บอยด์สมิ ธ

33

เพื่อให้เข้าใจexecคุณต้องเข้าใจforkก่อน ฉันพยายามที่จะทำให้มันสั้น

  • เมื่อคุณมาถึงทางแยกในถนนโดยทั่วไปคุณมีสองตัวเลือก โปรแกรม Linux มาถึงทางแยกนี้ในถนนเมื่อมีการ fork()เรียกระบบ

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

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

3
คุณอธิบายได้ไหมว่าทำไมexecสามารถเปลี่ยนเส้นทางสคริปต์ออกเช่นเดียวกับในลิงค์ที่ฉันโพสต์?
becko

1
ฉันพบสิ่งนี้ไม่ชัดเจน "อย่างไรก็ตามอาจมีสถานการณ์ที่กระบวนการลูกไม่ได้เป็นส่วนหนึ่งของโปรแกรมเดียวกับกระบวนการหลัก"
cdosborn

6

ในbashถ้าคุณทำhelp exec:

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

    Options:
      -a name   pass NAME as the zeroth argument to COMMAND
      -c        execute COMMAND with an empty environment
      -l        place a dash in the zeroth argument to COMMAND

    If the command cannot be executed, a non-interactive shell exits, unless
    the shell option `execfail' is set.

    Exit Status:
    Returns success unless COMMAND is not found or a redirection error occurs.

บิตที่เกี่ยวข้อง:

If COMMAND is not specified, any redirections take effect in the current shell.

execเป็นเชลล์บิวด์อินซึ่งเป็นเชลล์ที่เทียบเท่ากับexecตระกูลของระบบเรียกว่าG_P พูดถึง (และ manpages ที่คุณดูเหมือนว่าอ่านแล้ว) มีเพียงฟังก์ชันการทำงานที่ได้รับคำสั่งของPOSIX ซึ่งกระทบกับเชลล์ปัจจุบันหากไม่ได้ระบุคำสั่ง

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