execコマンドはbashの組み込みコマンドでシェルを実行するコマンドで置き換えるコマンドになります。例えば、シェルスクリプト等で、あるコマンドを実行する場合、プロセス上では、実行したいコマンドが終わるまでそのコマンドを実行するシェルスクリプトのプロセスが残ることになります。実行できるプロセス数には限界があり、execコマンドで実行すると無駄にプロセスが実行することを防げます。
また、execコマンドを引数にコマンドなしで利用するとシェルのリダイレクトの設定を変更することもできます。
プロセスを置き換える
あるコマンドを実行させたいときに、シェルスクリプトを実行してコマンドを実行させる場合、プロセス上ではコマンドを実行させるために起動したシェルスクリプトのプロセスがそのコマンドが終了するまで残ります。例えば、sleepコマンドを起動させるシェルスクリプト実行させて、その後、すぐに実行を中断させ(Ctrl+z)、psコマンドで実行中のプロセスを確認すると、
noexec-sleep.sh
1 2 3 |
#!/bin/bash sleep 30 |
コマンド例と実行例
1 2 3 4 5 6 7 8 9 |
$ ./noexec-sleep.sh ^Z [1]+ Stopped ./noexec-sleep.sh $ ps PID TTY TIME CMD 2397 pts/18 00:00:03 bash 12337 pts/18 00:00:00 noexec-sleep.sh 12338 pts/18 00:00:00 sleep 12339 pts/18 00:00:00 ps |
上の例では、PIDが12338のsleepコマンドのほかに、PIDが12337のnoexec-sleep.shがあります。
上の例でのシェルスクリプトの実行を終了させた後で、execコマンドを使用したバージョンでのシェルスクリプトでsleepコマンドを実行させると、
exec-sleep.sh
1 2 3 |
#!/bin/bash exec sleep 30 |
コマンド例と実行結果
1 2 3 4 5 6 7 8 |
$ ./exec-sleep.sh ^Z [1]+ Stopped ./exec-sleep.sh $ ps PID TTY TIME CMD 2397 pts/18 00:00:03 bash 12398 pts/18 00:00:00 sleep 12399 pts/18 00:00:00 ps |
PIDが12398のsleepコマンドのみがプロセス上で確認できます。これはPIDが12398のシェルスクリプトの実行がsleepコマンドに置き換わったため、このように確認できます。
起動できるプロセス数には限界があるため、このようにexecコマンドを利用すると無駄にプロセスを起動しなくてもよくなります。
ラッパーコマンドを作成
execコマンドはラッパーコマンドを作成するのに利用できます。例えば、共有ライブラリを使用するプログラムを実行させる方法として、環境変数LD_LIBRARY_PATHに共有ライブラリのパスを追加する方法があります。
共有ライブラリが読み込めない状態でプログラムを起動させると以下のようにエラーメッセージが表示され、プログラムを実行できません。
1 2 |
$ ./prog ./prog: error while loading shared libraries: shared-libprog.so: cannot open shared object file: No such file or directory |
これをラッパーコマンドとして、例えば、exec-prog.shという名前のスクリプトを記述し、プログラムを実行させることができます。ただし、スクリプト(exec-prog.sh)・プログラム(prog)・共有ライブラリ(shared-libprog.so)がカレントディレクトリにあることを想定して使用されるとしています。
exec-prog.sh
1 2 3 4 5 6 |
#!/bin/bash LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH export LD_LIBRARY_PATH exec ./prog |
prog.c
1 2 3 4 5 6 |
void func1(void); int main(void){ func1(); return 0; } |
shared-libprog.c
1 2 3 4 5 |
#include <stdio.h> void func1(void){ printf("func1\n"); } |
コマンド例と実行結果
1 2 |
$ ./exec-prog.sh func1 |
このようにプログラムを起動させる前に環境変数を設定した後に、execコマンドで実行したいコマンドを起動することで必要な環境が整えられた状態で実行することができます。
また、grepコマンドに-Eオプションがついたegrepコマンドは以下のようにexecコマンドが使用されています。
1 2 |
#!/bin/sh exec grep -E "$@" |
変数$@はシェルスクリプトの変数がすべて展開される変数です。つまり、egrepコマンドはegrepコマンドの引数が-Eオプションのついたgrepコマンドにすべて渡されて、プロセスもgrepコマンドに置き換わって実行されるコマンドになります。
現在のシェルのリダイレクトを変更
execコマンドにコマンドを引数にせずにリダイレクトのみを指定すると現在のシェルのリダイレクト先を変更できます。
exec-redirection.sh
1 2 3 4 5 6 7 8 9 |
#!/bin/bash echo 'exec redirection' exec >> file.txt echo 'aaa' echo 'bbb' echo 'ccc' |
コマンド例と実行結果
1 2 3 4 5 6 |
$ ./exec-redirection.sh exec redirection $ cat file.txt aaa bbb ccc |
また、リダイレクト先を変更する際に指定しているリダイレクト先を別のファイルディスクリプタ(file descriptor, fd)にコピーした後に、リダイレクト先を元に戻す方法もあります。
exec-redirection2.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/bin/bash echo 'exec redirection begin' exec 3>&1 exec >> file.txt echo 'aaa' echo 'bbb' echo 'ccc' exec >&3 exec 3>&- echo 'exec redirection end' |
コマンド例と実行結果
1 2 3 4 5 6 7 |
$ ./exec-redirection2.sh exec redirection begin exec redirection end $ cat file.txt aaa bbb ccc |
上のexec-redirection2.shのexecコマンドの動作は
- 1つ目のexecコマンドでfd1をfd3へコピーし、
- 2つ目のexecコマンドでfd1のリダイレクト先をfile.txtへ変更します。
- そして、3つ目のexecコマンドでfd3をfd1へコピーし(元に戻し)、
- 4つ目のexecコマンドでfd3をクローズしています。
ひとつひとつのコマンドに何度も同じリダイレクトを指定している場合、execコマンドのリダイレクトの変更を用いると、何度もリダイレクトの記述をしなくてもよくなります。
参考記事:Linuxのリダイレクトについて確認する