1. 程式人生 > >Linux中exec命令相關:

Linux中exec命令相關:

exec和source都屬於bash內部命令(builtins commands),在bash下輸入man exec或man source可以檢視所有的內部命令資訊。   bash shell的命令分為兩類:外部命令和內部命令。外部命令是通過系統呼叫或獨立的程式實現的,如sed、awk等等。內部

命令是由特殊的檔案格式(.def)所實現,如cd、history、exec等等。

  在說明exe和source的區別之前,先說明一下fork的概念。

  fork是linux的系統呼叫,用來建立子程序(child process)。子程序是父程序(parent process)的一個副本,從父程序那裡

獲得一定的資源分配以及繼承父程序的環境。子程序與父程序唯一不同的地方在於pid(process id)。

  環境變數(傳給子程序的變數,遺傳性是本地變數和環境變數的根本區別)只能單向從父程序傳給子程序。不管子程序的環境

變數如何變化,都不會影響父程序的環境變數。

  shell script:

  有兩種方法執行shell scripts,一種是新產生一個shell,然後執行相應的shell scripts;一種是在當前shell下執行,不

再啟用其他shell。

  新產生一個shell然後再執行scripts的方法是在scripts檔案開頭加入以下語句

  #!/bin/sh

  一般的script檔案(.sh)即是這種用法。這種方法先啟用新的sub-shell(新的子程序),然後在其下執行命令。

  另外一種方法就是上面說過的source命令,不再產生新的shell,而在當前shell下執行一切命令。

  source:

  source命令即點(.)命令。

  在bash下輸入man source,找到source命令解釋處,可以看到解釋”Read and execute commands from filename in the

current shell environment and …”。從中可以知道,source命令是在當前程序中執行引數檔案中的各個命令,而不是另起子

程序(或sub-shell)。

  exec:

  在bash下輸入man exec,找到exec命令解釋處,可以看到有”No new process is created.”這樣的解釋,這就是說exec命

令不產生新的子程序。那麼exec與source的區別是什麼呢?

  exec命令在執行時會把當前的shell process關閉,然後換到後面的命令繼續執行。

1. 系統呼叫exec是以新的程序去代替原來的程序,但程序的PID保持不變。因此,可以這樣認為,exec系統呼叫並沒有建立新的

程序,只是替換了原來程序上下文的內容。原程序的程式碼段,資料段,堆疊段被新的程序所代替。

  一個程序主要包括以下幾個方面的內容:

  (1)一個可以執行的程式

  (2) 與程序相關聯的全部資料(包括變數,記憶體,緩衝區)

  (3)程式上下文(程式計數器PC,儲存程式執行的位置)

  2. exec是一個函式簇,由6個函式組成,分別是以excl和execv打頭的。

  執行exec系統呼叫,一般都是這樣,用fork()函式新建立一個程序,然後讓程序去執行exec呼叫。我們知道,在fork()建立

新程序之後,父進各與子程序共享程式碼段,但資料空間是分開的,但父程序會把自己資料空間的內容copy到子程序中去,還有上

下文也會copy到子程序中去。而為了提高效率,採用一種寫時copy的策略,即建立子程序的時候,並不copy父程序的地址空間,

父子程序擁有共同的地址空間,只有當子程序需要寫入資料時(如向緩衝區寫入資料),這時候會複製地址空間,複製緩衝區到子

程序中去。從而父子程序擁有獨立的地址空間。而對於fork()之後執行exec後,這種策略能夠很好的提高效率,如果一開始就

copy,那麼exec之後,子程序的資料會被放棄,被新的程序所代替。

  3. exec與system的區別

  (1) exec是直接用新的程序去代替原來的程式執行,執行完畢之後不回到原先的程式中去。

  (2) system是呼叫shell執行你的命令,system=fork+exec+waitpid,執行完畢之後,回到原先的程式中去。繼續執行下面的

部分。

  總之,如果你用exec呼叫,首先應該fork一個新的程序,然後exec. 而system不需要你fork新程序,已經封裝好了。

  exec I/O重定向詳解及應用例項

  1、 基本概念(這是理解後面的知識的前提,請務必理解)

  a、 I/O重定向通常與 FD有關,shell的FD通常為10個,即 0~9;

  b、 常用FD有3個,為0(stdin,標準輸入)、1(stdout,標準輸出)、2(stderr,標準錯誤輸出),預設與keyboard、monitor

、monitor有關;

  c、 用 來改變送出的資料通道(stdout, stderr),使之輸出到指定的檔案;

  e、 0 是 與 1> 是一樣的;

  f、 在IO重定向 中,stdout 與 stderr 的管道會先準備好,才會從 stdin 讀進資料;

  g、 管道“|”(pipe line):上一個命令的 stdout 接到下一個命令的 stdin;

  h、 tee 命令是在不影響原本 I/O 的情況下,將 stdout 複製一份到檔案去;

  i、 bash(ksh)執行命令的過程:分析命令-變數求值-命令替代(``和$( ))-重定向-萬用字元展開-確定路徑-執行命令;

  j、 ( ) 將 command group 置於 sub-shell 去執行,也稱 nested sub-shell,它有一點非常重要的特性是:繼承父shell

的Standard input, output, and error plus any other open file descriptors。

  k、 exec 命令:常用來替代當前 shell 並重新啟動一個 shell,換句話說,並沒有啟動子 shell。使用這一命令時任何現

有環境都將會被清除。exec 在對檔案描述符進行操作的時候,也只有在這時,exec 不會覆蓋你當前的 shell 環境。

  2、cmd &n 使用系統呼叫 dup (2) 複製檔案描述符 n 並把結果用作標準輸出

  &- 關閉標準輸出

  n&- 表示將 n 號輸出關閉

  上述所有形式都可以前導一個數字,此時建立的檔案描述符由這個數字指定而不是預設的 0 或 1。如:

  ... 2>file 執行一個命令並把錯誤輸出(檔案描述符 2)定向到 file。

  ... 2>&1 執行一個命令並把它的標準輸出和輸出合併。(嚴格的說是通過複製檔案描述符 1 來建立檔案描述符 2 ,但效果

通常是合併了兩個流。)

  我們對 2>&1詳細說明一下 :2>&1 也就是 FD2=FD1 ,這裡並不是說FD2 的值 等於FD1的值,因為 > 是改變送出的資料信

道,也就是說把 FD2 的 “資料輸出通道” 改為 FD1 的 “資料輸出通道”。如果僅僅這樣,這個改變好像沒有什麼作用,因

為 FD2 的預設輸出和 FD1的預設輸出本來都是 monitor,一樣的!

  但是,當 FD1 是其他檔案,甚至是其他 FD 時,這個就具有特殊的用途了。請大家務必理解這一點。

  3、 如果 stdin, stdout, stderr 進行了重定向或關閉, 但沒有儲存原來的 FD, 可以將其恢復到 default 狀態嗎?

  *** 如果關閉了stdin,因為會導致退出,那肯定不能恢復。

  *** 如果重定向或關閉 stdout和stderr其中之一,可以恢復,因為他們預設均是送往monitor(但不知會否有其他影響)。如

恢復重定向或關閉的 stdout: exec 1>&2 ,恢復重定向或關閉的stderr:exec 2>&1。

  *** 如果stdout和stderr全部都關閉了,又沒有儲存原來的FD,可以用:exec 1>/dev/tty 恢復。

  4、 cmd >a 2>a 和 cmd >a 2>&1 為什麼不同?

  cmd >a 2>a :stdout和stderr都直接送往檔案 a ,a檔案會被開啟兩遍,由此導致stdout和stderr互相覆蓋。

  cmd >a 2>&1 :stdout直接送往檔案a ,stderr是繼承了FD1的管道之後,再被送往檔案a 。a檔案只被開啟一遍,就是FD1

將其開啟。

  我想:他們的不同點在於:

  cmd >a 2>a 相當於使用了兩個互相競爭使用檔案a的管道;

  而cmd >a 2>&1 只使用了一個管道,但在其源頭已經包括了stdout和stderr。

  從IO效率上來講,cmd >a 2>&1的效率應該更高!

  exec 0exec 1>outfilename # 開啟檔案outfilename作為stdout

  exec 2>errfilename # 開啟檔案 errfilename作為 stderr

  exec 0&- # 關閉 FD1

  exec 5>&- # 關閉 FD5

[[email protected] shell]$ cat 1

  11 22 33 44 55

  66 22 33 11 33

  324 25 63 634 745

  [[email protected] shell]$ cat 2

  > 1.txt

  exec 4<&1

  exec 1> 1.txt

  while read line

  do

  echo $line

  done < 1

  exec 1<&4

  exec 4>&-

  [[email protected] shell]$ sh ./2

  [[email protected] shell]$ cat 1.txt

  11 22 33 44 55

  66 22 33 11 33

  324 25 63 634 745

  [linuxi[email protected] shell]$

修改ls顯示的時間格式:

ls -l --time-style '+%Y/%m/%d %H:%M:%S' total 0 -rw-r--r-- 1 root root 0 2008/08/01 12:23:06 file1 -rw-r--r-- 1 root root 0 2008/08/01 12:23:06 file2   --time-style 也可以存在環境變數裡:   export TIME_STYLE='+%Y/%m/%d %H:%M:%S'

ls -l total 0 -rw-r--r-- 1 root root 0 2008/08/01 12:23:06 file1 -rw-r--r-- 1 root root 0 2008/08/01 12:23:06 file2

Linux中內部命令和外部命令:    UNIX命令有內部命令和外部命令之分。內部命令實際上是shell程式的一部分,其中包含的是一些比較簡練的UNIX系統命令,這些命令由shell程式識別並在shell程式內部完成執行,通常在UNIX系統載入執行時shell就被載入並駐留在系統記憶體中。外部命令是UNIX系統中的實用程式部分,因為實用程式的功能通常都比較強大,所以它們包含的程式量也會很大,在系統載入時並不隨系統一起被載入到記憶體中,而是在需要時才將其調進記憶體。通常外部命令的實體並不包含在shell中,但是其命令執行過程是由shell 程式控制的。shell程式管理外部命令執行的路徑查詢、載入存放,並控制命令的執行。  理解了內部命令和外部命令之後,你可能就會有疑問了??那麼我怎麼看一個命令是內部命令還是外部命令呢??

1、在終端下輸入man builtins,即可調出內部命令的大綱和解釋。

2、用命令enable調出來,後者將分行打印出內部命令

     [[email protected] shell]# enable ls

      bash: enable: ls: not a shell builtin