Apa yang dilakukan perintah “exec”?

107

Saya tidak mengerti perintah bash exec. Saya telah melihatnya digunakan di dalam skrip untuk mengarahkan semua output ke file (seperti yang terlihat dalam ini ). Tapi saya tidak mengerti cara kerjanya atau apa yang dilakukan secara umum. Saya telah membaca halaman manual tetapi saya tidak memahaminya.

becko
sumber
Apakah Anda terbiasa dengan proses itu?
fkraiem
1
@ fkraiem apa maksudmu?
becko
Maaf saya maksudkan "apa". : p Tapi jawabannya sepertinya tidak.
fkraiem
Tapi sebenarnya skrip Anda menggunakan execcara khusus yang bisa dijelaskan lebih sederhana, saya akan menulis jawaban.
fkraiem
1
Terkait: unix.stackexchange.com/q/296838/85039
Sergiy Kolodyazhnyy

Jawaban:

88

man bash mengatakan:

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.

Dua baris terakhir adalah yang penting: Jika Anda menjalankannya execsendiri, tanpa perintah, itu hanya akan membuat pengalihan berlaku untuk shell saat ini. Anda mungkin tahu bahwa ketika Anda menjalankan command > file, output dari commandditulis filebukan ke terminal Anda (ini disebut redirection ). Jika Anda menjalankannya exec > file, maka pengalihan berlaku untuk seluruh shell: Setiap output yang dihasilkan oleh shell ditulis untuk filebukannya ke terminal Anda. Sebagai contoh di sini

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

Saya pertama kali memulai bashshell baru . Kemudian, di shell baru ini saya jalankan exec > file, sehingga semua output dialihkan ke file. Memang, setelah itu saya jalankan datetetapi saya tidak mendapatkan output, karena output diarahkan ke file. Kemudian saya keluar dari shell saya (sehingga pengalihan tidak lagi berlaku) dan saya melihat bahwa filememang berisi output dari dateperintah yang saya jalankan sebelumnya.

fkraiem
sumber
42
Ini hanya sebagian penjelasan. execberfungsi juga untuk menggantikan proses shell saat ini dengan perintah, sehingga orang tua berjalan dan anak memiliki pid. Ini bukan hanya untuk pengalihan. Silakan tambahkan info ini
Sergiy Kolodyazhnyy
3
Menindaklanjuti komentar @ SergiyKolodyazhnyy, contoh yang baru saja saya temui yang membawa saya ke halaman ini adalah docker-entrypoint.sh, di mana setelah melakukan berbagai tindakan pada konfigurasi nginx, baris terakhir skrip adalah exec nginx <various nginx arguments>. Ini berarti bahwa nginx mengambil alih pid dari skrip bash dan sekarang nginx adalah proses menjalankan utama wadah, bukan skrip. Saya menganggap ini hanya untuk kebersihan, kecuali orang lain tahu alasan yang lebih konkret untuk itu?
Luke Griffiths
1
@ Lukas Ini disebut "skrip pembungkus". Contohnya juga gnome-terminal, yang setidaknya pada 14,04 memiliki skrip wrapper untuk mengatur argumen. Dan itulah satu-satunya tujuan mereka, benar-benar mengatur seni dan lingkungan. Kasus lain adalah membersihkan - membunuh instance sebelumnya dari suatu proses terlebih dahulu dan meluncurkan yang baru
Sergiy Kolodyazhnyy
execcontoh lain yang mirip dengan nginxcontoh yang diberikan oleh @LukeGriffiths adalah ~/.vnc/xstartupskrip yang vncserverdigunakan untuk mengkonfigurasi proses server VNC dan kemudian exec gnome-sessionatau exec startkdeseterusnya.
Trevor Boyd Smith
@LukeGriffiths, alasan utama execdalam skrip startup wadah adalah bahwa PID 1, ENTRYPOINT penampung, memiliki makna khusus di Docker. Ini adalah proses utama yang menerima sinyal, dan ketika ada, wadah juga keluar. exechanya cara untuk mengambil shdari rantai komando ini, dan menjadikan daemon proses utama dari wadah.
kkm
45

exec adalah perintah dengan dua perilaku yang sangat berbeda, tergantung pada apakah setidaknya satu argumen digunakan dengannya, atau tidak ada argumen yang digunakan sama sekali.

  • Jika setidaknya satu argumen dilewati, yang pertama diambil sebagai nama perintah dan execmencoba untuk mengeksekusinya sebagai perintah yang melewati argumen yang tersisa, jika ada, untuk perintah itu dan mengelola pengalihan, jika ada.

  • Jika perintah yang dilewati sebagai argumen pertama tidak ada, shell saat ini, tidak hanya perintah exec, yang keluar karena kesalahan.

  • Jika perintah ada dan dapat dieksekusi, itu menggantikan shell saat ini. Itu berarti bahwa jika execmuncul dalam skrip, instruksi yang mengikuti panggilan exec tidak akan pernah dieksekusi (kecuali jika execitu sendiri dalam sebuah subkulit). exectidak pernah kembali. Perangkap shell seperti "EXIT" juga tidak akan terpicu.

  • Jika tidak ada argumen yang diteruskan, exechanya digunakan untuk mendefinisikan kembali deskriptor file shell saat ini. Shell melanjutkan setelah exec, tidak seperti kasus sebelumnya, tetapi input standar, output, kesalahan atau deskriptor file apa pun yang telah dialihkan berpengaruh.

  • Jika beberapa pengalihan digunakan /dev/null, input apa pun darinya akan mengembalikan EOF dan output apa pun ke sana akan dibuang.

  • Anda dapat menutup deskriptor file dengan menggunakan -sebagai sumber atau tujuan, misalnya exec <&-. Membaca atau menulis selanjutnya akan gagal.

Berikut ini dua contoh:

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

Script ini akan menampilkan "foo" sebagai perintah cat, alih-alih menunggu input pengguna seperti yang akan dilakukan dalam kasus biasa akan mengambil inputnya dari file / tmp / bar yang berisi foo.

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

Script ini akan menampilkan 4(jumlah byte di / tmp / bar) dan segera berakhir. The catperintah tidak akan dieksekusi.

Jlliagre
sumber
4
`Beberapa posting lama tidak pernah benar-benar menjadi tua ... +1.
Cbhihe
3
Jika beberapa pengalihan menggunakan / dev / null, deskriptor file yang terkait ditutup. Tidak, itu benar-benar mengarahkan ulang ke / dari /dev/null, jadi menulis masih berhasil dan membaca pengembalian EOF. close(2)pada fd akan menyebabkan panggilan sistem baca / tulis untuk mengembalikan kesalahan, dan Anda melakukannya dengan exec 2>&-misalnya.
Peter Cordes
2
Coba sendiri:: exec 3</dev/null; ls -l /proc/self/fdperhatikan bahwa fd 3 akan terbuka hanya baca di / dev / null. Kemudian tutup kembali dengan exec 3<&-, dan Anda dapat melihat (dengan ls -l /proc/$$/fdlagi) bahwa proses shell Anda tidak memiliki fd 3 lagi. (menutup stdin dengan exec <&-dapat berguna dalam skrip, tetapi secara interaktif itu adalah logout.)
Peter Cordes
@PeterCordes Anda benar sekali. Jawaban diperbarui. Terima kasih!
jlliagre
1
Jawaban ini sangat bagus karena menjelaskan dua kasus penggunaan dari execjawaban yang paling banyak dipilih saat ini hanya berbicara tentang satu kasus penggunaan dan jawaban lainnya oleh g_p hanya berbicara tentang kasus penggunaan lainnya. Dan jawaban ini bagus dan ringkas / mudah dibaca untuk masalah subjek yang kompleks.
Trevor Boyd Smith
33

Untuk memahami execAnda harus terlebih dahulu mengerti fork. Saya mencoba untuk membuatnya singkat.

  • Ketika Anda sampai di pertigaan jalan, Anda biasanya memiliki dua pilihan. Program Linux mencapai pertigaan ini di jalan ketika mereka menekan fork()system call.

  • Program normal adalah perintah sistem yang ada dalam formulir yang dikompilasi di sistem Anda. Ketika program seperti itu dijalankan, proses baru dibuat. Proses anak ini memiliki lingkungan yang sama dengan induknya, hanya nomor ID proses yang berbeda. Prosedur ini disebut forking .

  • Forking menyediakan cara bagi proses yang ada untuk memulai yang baru. Namun, mungkin ada situasi di mana proses anak bukan bagian dari program yang sama dengan proses orang tua. Dalam hal execini digunakan. exec akan mengganti konten dari proses yang sedang berjalan dengan informasi dari program biner.
  • Setelah proses forking, ruang alamat dari proses anak ditimpa dengan data proses baru. Ini dilakukan melalui panggilan exec ke sistem.
g_p
sumber
3
dapatkah Anda menjelaskan mengapa execredirect dapat menghasilkan skrip, seperti pada tautan yang saya posting?
becko
1
Saya menemukan ini tidak jelas "Namun, mungkin ada situasi di mana proses anak bukan bagian dari program yang sama dengan proses orang tua"
cdosborn
6

Di bash, jika Anda melakukannya 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.

Bit yang relevan:

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

execadalah shell builtin , yang merupakan shell yang setara dengan execkeluarga pemanggilan sistem yang dibicarakan G_P (dan halaman manual yang tampaknya Anda baca). Itu hanya memiliki fungsi mandat POSIX mempengaruhi shell saat ini jika tidak ada perintah yang ditentukan.

muru
sumber