bash執行命令各種情況分析

2021-06-20 05:35:03 字數 3001 閱讀 2330

linux系統中的可執行檔案有多少種類?bash環境下是如何執行程式的?下面逐一分析。

這種檔案是最常見的,如/bin/ls,/sbin/ifconfig, /bin/cat等等。

[root@notebook135 ~]# file /bin/ls /bin/cat /sbin/ifconfig

/bin/ls:        elf 32-bit lsb executable, intel 80386, version 1 (sysv), dynamically linked (uses shared libs), for gnu/linux 2.6.18, stripped

/bin/cat:       elf 32-bit lsb executable, intel 80386, version 1 (sysv), dynamically linked (uses shared libs), for gnu/linux 2.6.18, stripped

/sbin/ifconfig: elf 32-bit lsb executable, intel 80386, version 1 (sysv), dynamically linked (uses shared libs), for gnu/linux 2.6.18, stripped

這種檔案是系統管理者常用的,通常用來粘合各種其他的程式,系統中也必不可少,如 命令service,yum等。

[root@notebook135 ~]# file $(which yum) $(which service)

/usr/bin/yum:  a /usr/bin/python script text executable

/sbin/service: posix shell script text executable

其中,yum是乙個python指令碼,service是乙個shell指令碼。

當然,還可以有其他型別的指令碼,如ruby,php,awk等等。

不論何種型別的可執行程式,都是通過統一的execve()系統呼叫進行載入執行的。具體的載入過程卻會因為可執行程式種類的不同而不同,對於二進位制檔案,直接載入執行;對於指令碼檔案,則會載入檔案第一行指定的直譯器,並把指令碼檔案路徑名作為直譯器的引數。execve()是如何區分各種程式型別的呢?其實很簡單,就是位於檔案最開始處的「魔數」。不同型別的檔案的「魔數」是不同的,對於指令碼檔案就是開頭的#!,對於二進位制檔案,根據32位和64位的不同,也有所不同,感興趣的同學可以自行研究,這裡不再累述。

bash環境下可以執行的命令有兩類:一類就是前面說過的可執行檔案(可執行檔案又分成二進位制和指令碼兩類);另一類就是bash內建命令。

常見的內建命令有echo,cd,trap等等。內建命令也分成兩類:一類是某些外部可執行檔案的同功能替代,目的是提高效率,如echo;第二類是其功能無法通過執行外部檔案完成的必備命令,如cd。

對於內部命令,bash直接執行其自身內部**即可,快速無負擔。對於執行外部可執行檔案,則相對就麻煩了。

可以有兩種手段讓bash執行命令,一是在互動模式下,輸入命令名然後按下回車鍵;二是把命令路徑作為引數來執行/bin/bash。兩種手段的作用是相同的。

bash首先會fork出乙個子程序,然後:(1)bash自身程序執行wait()等待子程序結束;(2)子程序中執行execve("命令路徑「),剩下的工作就由載入器來完成了。

[root@notebook135 ~]# strace -e trace=process /bin/ls

execve("/bin/ls", ["/bin/ls"], [/* 21 vars */]) = 0

smstongtekimac-mini:test smstong$ exec /bin/ls 

此時,可執行程式將會在程序內把原來的bash程式替換掉。相當於直接執行execve("可執行程式")。

[root@notebook135 ~]# strace -e trace=process ./test1.sh 

execve("./test1.sh", ["./test1.sh"], [/* 21 vars */]) = 0

當然,這個識別指令碼的過程也可以交給使用者自己來完成,比如對於上面的 test1.sh,我們可以指定ksh93為其直譯器,者通過顯式的執行其直譯器程式來完成。

[root@notebook135 ~]# strace -e trace=process ksh93 ./test1.sh 

execve("/bin/ksh93", ["ksh93", "./test1.sh"], [/* 21 vars */]) = 0

此時,指令碼檔案第一行指定的直譯器不起作用了。

這兩種執行指令碼檔案的方式效果是一樣的,只是通過ps檢視時程序的名字會有所不同,直接執行時子程序名字為指令碼檔名,通過ksh93 test1.sh執行時,子程序名為ksh93。

其實第二種方式有時候是必要的,例如某些系統的載入器本身不能直接執行指令碼檔案,又如指令碼檔案本身不具有可執行許可權。

前面例子test1.sh是ksh指令碼,如果是awk,php,python...,過程也是完全一樣的。有一中指令碼也許看起來有點特殊,那就是bash,此時會導致bash啟動乙個子bash程序,其實也就是看起來特殊,僅僅是因為子程序的名字和父程序一樣而已,本質上與其他型別的指令碼直譯器沒有任何區別。

bash還提供了一種特殊的執行外部命令的方式,那就是使用自身程序去執行,而不是新建子程序。這時,指令碼檔案第一行指定的直譯器不起作用了。

vim test1.sh

1 #!/bin/ksh93

2 echo$$

3 exit

如果直接執行或者通過bash ./test1.sh執行,結果都是列印子程序號,然後退出子程序,回到互動式bash。

而如果通過. ./test.sh執行,則列印bash程序號後,bash自身退出了。

此種方式的主要作用是通過指令碼設定互動式bash自身的環境,如/etc/profile檔案就需要此種方式執行。

需要說明的是,此種方式不同於 exec ./test1.sh。

eval與(3)的點命令原理一樣,但是提供了更多的引數。

exec 內建命令可以作用於二進位制,也可以作用於可執行的指令碼檔案,前面已經說過了。

SVN各種情況說明

黃色感嘆號 有衝突 這是有衝突了,衝突就是說你對某個檔案進行了修改,別人也對這個檔案進行了修改,別人搶在你提交之前先提交了,這時你再提交就會被提示發生衝突,而不允許你提交,防止你的提交覆蓋了別人的修改。要解決衝突,如果你確認你的修改是無效的,則用tsvn還原你的修改就行了 如果認為你的修改是正確的,...

裝飾器的各種情況。

裝飾器 第一步 基本函式 def chiji print 吃雞真得勁 呼叫函式 chiji 第二步 擴充套件功能 不能直接修改原來的函式 def zhuangshi func print 吃雞之前,左手摸雞 func print 吃雞之後,右手搖雞 def chiji print 吃雞真得勁 chi...

死鎖的各種情況總結

mutex 代表乙個全域性互斥物件 voida mutex.unlock return 複製 由於在if的執行體內直接retun,而沒有呼叫unlock,導致另乙個執行緒再呼叫a方法就出現死鎖。void sub func void data process 複製 void data process1...