[SHELL] Execution Type

Posted by babygoat on 2019-06-04

前言

最近開發常需要測試環境變數去overwrite default的設定檔

1
~> var1=env1 go run server.go

但如果要覆寫的環境變數一多,直接打在command line上就顯得過於冗長

這時就想到可以用env檔的方式(e.g., dev.env)創造出需要的環境

1
2
3
4
5
6
7
8
9
~> cat dev.env
#!/bin/bash
var1=env1
var2=env2
var3=env3
...

~>source dev.env
~>go run server.go

但觀念不清楚的狀況下常會,source | bash(sh) | . | ./[script]混用

可能造成環境變數設定不當

本篇為筆記整理

Execution Type

在LINUX/UNIX執行環境下,可分為三種exectuion type

  • Fork (default)
  • Source
  • Exec

最主要的差異性在於執行後的結果,是否影響當前shell的環境

底下一一來探討

Fork

預設的執行模式,顧名思義就是在執行script時會fork出一個child process來運行

故當script執行完畢時,即回到parent process(原本的shell),而不改變環境

底下為常見的fork模式

  • 使用shell interpreter
1
2
3
4
5
6

~> sh ./script

or

~> bash ./script
  • 直接使用script filename
1
2

~>./script

若以script filename執行時,需有"+x" (execution的權限)

Source

Source執行模式則是直接在目前的Shell下運行,如執行中有改變環境時,

則會保留更動

底下為常見的Source模式使用

  • 使用source builtin
1
2

~> source ./script
  • 使用 .(period) builtin
1
2

~> . ./script

Exec

Exec的執行模式跟Source一樣,都是在當前的Shell運行,故也會保留過程中的環境更動

但不同的是,執行後會結束當前的Shell

且script需有可執行(+x)的權限

底下為常見的Exec模式使用

  • 使用exec builtin
1
~> exec ./script

驗證

為了驗證剛剛的理論,可以使用pstree來觀察三種不同模式的樹狀圖

透過tmux或開啟兩個terminal,一個執行script,另外一個透過process樹狀圖觀察

底下是準備的script.sh的snippet

1
2
3
#!/bin/bash
read -p "Please input a number:" number
echo "Your number is:${number}"

為了方便觀測,用read builtin command,等待輸入,可以比較明顯的看出執行時process的變化

Fork

首先是fork

window 1

1
2
3
4
5
~> bash script.sh
Please input a number:2
Your number is: 2
~> echo "After script:${number}"
After script:

window 2

1
2
3
4
~> pstree -s bash
...
\-+= 13902 babygoat bash
\--= 14357 babygoat bash script.sh

明顯可以看出在fork下,bash script.sh的執行是由shell fork出的child process所執行,故回到原本shell執行echo指令時,$number的值仍為空

Source

window 1

1
2
3
4
5
~> source script.sh
Please input a number: 2
Your number is: 2
~> echo "After script:${number}"
After script: 2

window 2

1
2
3
~> pstree -s bash
...
\--= 13902 babygoat bash

可以看出在source模式下,並沒有fork出child process來運行script,故只能看到bash shell的process,且變數$number被保留在執行script的環境

Exec

window 1

1
2
3
4
5
6
# 要先將script.sh的權限增加可執行
~> chmod +x script.sh
~> exec script.sh
Please input number:2
Your number is: 2
# Shell關閉

window 2

1
2
3
~> pstree -s bash
...
\--= 13902 babygoat /bin/bash /Users/babygoat/script.sh

發現執行shell的process context被替換成執行script.sh了,也沒有生出額外的process,執行完畢後process即結束

也驗證了bash manual裡有關exec 的說明

If command is supplied, it replaces the shell without creating a new process.

Reference

  1. Bourne Shell Builtins
  2. linux里source、sh、bash、./有什么区别
  3. Bash Shell – source script, sh script, ./script (2)