用sh、./怜械、source執(zhí)行Shell腳本到底有何不同颅和?

要解答這個(gè)看似簡(jiǎn)單的問(wèn)題傅事,需要先復(fù)習(xí)一下Linux系統(tǒng)里“命令”這個(gè)詞的含義。

Linux系統(tǒng)中的命令有兩種:一是內(nèi)置命令峡扩,是Shell與生俱來(lái)的一部分蹭越,比如最基礎(chǔ)的cdecho教届、kill等响鹃;二是外部命令,包含已編譯的實(shí)用程序以及Shell腳本兩種案训,它們兩者又可以統(tǒng)稱(chēng)為可執(zhí)行文件(executables)买置。我們平時(shí)常用的大多數(shù)看起來(lái)像“內(nèi)置(自帶)命令”的命令,其實(shí)都是/usr/bin及其他目錄下的已編譯程序强霎,如ls忿项、psgrep等脆栋。

可見(jiàn)倦卖,外部命令的實(shí)體并不存在于Shell中,而是在調(diào)用時(shí)才從對(duì)應(yīng)的位置加載椿争。如果用戶(hù)調(diào)用命令時(shí)沒(méi)有提供路徑的話(huà)怕膛,Shell通過(guò)PATH環(huán)境變量來(lái)定位外部命令的路徑。

# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/java/jdk1.8.0_172/bin:/usr/java/jdk1.8.0_172/jre/bin

如果在PATH給定的路徑仍然找不到命令秦踪,Shell就會(huì)返回"command not found"褐捻。這也就解釋了為什么在Linux下安裝完JDK之后,總是要將$JAVA_HOME/bin寫(xiě)入PATH——用戶(hù)肯定不想每次調(diào)用JDK提供的命令時(shí)都要先cd到JDK的安裝路徑椅邓,或者把路徑寫(xiě)得清清楚楚柠逞。

按照上文所述,我們平時(shí)自己寫(xiě)的Shell腳本也是外部命令景馁。下面在/tmp/test目錄下直接創(chuàng)建一個(gè)文件:touch my_script.sh板壮,并在其中寫(xiě)幾句簡(jiǎn)單的話(huà)。

#!/bin/sh
echo "Hello World!"
echo "Parameter 1 is: $1"
echo "MYVAR is: $MYVAR"

然后以不同的方式執(zhí)行這個(gè)腳本合住。

[root@aes ~]# MYVAR=littlemagic
[root@aes ~]# sh /tmp/test/my_script.sh bla
Hello World!
Parameter 1 is: bla
MYVAR is: 
[root@aes ~]# /tmp/test/my_script.sh bla
-bash: /tmp/test/my_script.sh: Permission denied
[root@aes ~]# source /tmp/test/my_script.sh bla
Hello World!
Parameter 1 is: bla
MYVAR is: littlemagic

[root@aes ~]# cd /tmp/test
[root@aes test]# sh my_script.sh bla
Hello World!
Parameter 1 is: bla
MYVAR is: 
[root@aes test]# ./my_script.sh bla
-bash: ./my_script.sh: Permission denied
[root@aes test]# my_script.sh bla
-bash: my_script.sh: command not found
[root@aes test]# source my_script.sh bla
Hello World!
Parameter 1 is: bla
MYVAR is: littlemagic

這段示例的信息量蠻大的绰精,下面以Q&A的形式逐個(gè)解決問(wèn)題。

Q1:./有什么特殊含義沒(méi)透葛?

并沒(méi)有笨使,只是表示相對(duì)路徑(即當(dāng)前目錄)而已,./my_script.sh即在當(dāng)前目錄/tmp/test執(zhí)行my_script.sh腳本僚害。用絕對(duì)路徑和用相對(duì)路徑執(zhí)行腳本是等價(jià)的硫椰,因此可以干脆將它們打包統(tǒng)稱(chēng)為“./方式”,以與“sh方式”區(qū)分開(kāi)來(lái)。

Q2:為什么./方式提示沒(méi)權(quán)限靶草,而sh方式執(zhí)行成功蹄胰?

在./方式下,當(dāng)前Shell進(jìn)程會(huì)使用fork系統(tǒng)調(diào)用產(chǎn)生一個(gè)子Shell進(jìn)程奕翔,并使用execve系統(tǒng)調(diào)用讓OS在子Shell進(jìn)程中執(zhí)行腳本烤送。execve系統(tǒng)調(diào)用必然會(huì)檢查腳本文件的權(quán)限,而新touch出來(lái)的文件權(quán)限是-rw-r--r--糠悯,并沒(méi)有可執(zhí)行(x)權(quán)限帮坚,所以會(huì)報(bào)Permission denied。如果把權(quán)限改正互艾,那么它的執(zhí)行結(jié)果與sh方式是相同的试和。

[root@aes test]# chmod a+x my_script.sh
[root@aes test]# ./my_script.sh bla
Hello World!
Parameter 1 is: bla
MYVAR is: 

sh方式的不同點(diǎn)在于,OS會(huì)通過(guò)sh命令的調(diào)用直接產(chǎn)生一個(gè)新的Shell進(jìn)程纫普,并將my_script.sh當(dāng)作命令行參數(shù)傳進(jìn)去阅悍。新的Shell進(jìn)程就會(huì)讀取、解釋并執(zhí)行該腳本昨稼,而OS不關(guān)心該文件到底是什么节视,自然也就不要求可執(zhí)行權(quán)限,只要求讀權(quán)限就可以了假栓。

Q3:為什么在當(dāng)前路徑下直接寫(xiě)my_script.sh會(huì)報(bào)command not found寻行?

Linux與Windows不同,如果用戶(hù)不指定路徑匾荆,那么就會(huì)直接跳過(guò)對(duì)當(dāng)前路徑的檢查拌蜘,直接按照PATH來(lái)查找。而PATH里自然是沒(méi)有當(dāng)前路徑的牙丽,command not found就順理成章了简卧。也就是說(shuō),加./是為了告訴Shell:“我已經(jīng)確定我要執(zhí)行的東西在當(dāng)前路徑了”烤芦。

看官可能會(huì)問(wèn)举娩,干脆在PATH里直接加上當(dāng)前路徑(即.),不就可以免去打./的麻煩了嗎构罗?Linux非常不推薦這樣做铜涉,安全風(fēng)險(xiǎn)極大。舉個(gè)極端的例子:一個(gè)普通用戶(hù)在自己的家目錄新建了一個(gè)名為ls的腳本绰播,但里面的內(nèi)容是rm -rf /*骄噪。然后root用戶(hù)來(lái)到該用戶(hù)的家目錄尚困,并執(zhí)行l(wèi)s命令蠢箩,如果PATH里有當(dāng)前路徑的話(huà),結(jié)果可想而知。

Q4:為什么source執(zhí)行可以打出MYVAR變量的值谬泌,其他兩種不行滔韵?

source是Shell(準(zhǔn)確地說(shuō)是Bash)的內(nèi)置命令,在Bourne Shell中的等價(jià)命令是一個(gè)點(diǎn).掌实,即點(diǎn)命令陪蜻。用source命令執(zhí)行腳本文件時(shí),是在當(dāng)前Shell進(jìn)程中執(zhí)行贱鼻,而不是像./與sh方式一樣在新的Shell進(jìn)程中執(zhí)行宴卖,因此早先設(shè)置的變量在腳本里是可以讀取到的。

source一般不用來(lái)執(zhí)行業(yè)務(wù)腳本邻悬,最常見(jiàn)用途是在某些初始化腳本修改之后使其立即生效症昏,即source /etc/profile這樣。

Bonus Part:shebang對(duì)腳本執(zhí)行的影響

shebang是指腳本文件中以字符#!開(kāi)頭的第一行父丰,它用來(lái)指定這個(gè)腳本該用哪種解釋器來(lái)解釋肝谭。上文中出現(xiàn)的#!/bin/sh就表示應(yīng)該使用sh(在這里就是Bash)來(lái)解釋它。

需要注意蛾扇,只有./方式執(zhí)行腳本才會(huì)讀取shebang并調(diào)用指定的解釋器攘烛,而“sh方式”(sh當(dāng)然可以換成任意其他的解釋器)會(huì)忽略shebang。舉個(gè)例子镀首,新建一個(gè)Python腳本坟漱,但是shebang仍然故意錯(cuò)寫(xiě):

#!/bin/sh
print "Hello World!"

如果執(zhí)行./my_script.py的話(huà),會(huì)報(bào)語(yǔ)法錯(cuò)誤更哄,因?yàn)锽ash不能解釋Python靖秩;執(zhí)行python my_script.py是正常的,因?yàn)闀?huì)直接用Python解釋器竖瘾。若把shebang改回正確的#!/usr/bin/python沟突,那么兩種方式都能正常執(zhí)行。

實(shí)際上捕传,shebang甚至可以寫(xiě)成任意外部命令(當(dāng)然不推薦這樣做)惠拭。舉個(gè)有趣的栗子,創(chuàng)建腳本rm_self.sh:

#!/bin/rm
echo "I am still here!"

執(zhí)行sh rm_self.sh庸论,會(huì)輸出"I am still here!"职辅,并且rm_self.sh文件本身還在。但若是執(zhí)行./rm_self.sh聂示,則沒(méi)有任何輸出域携,并且rm_self.sh文件本身消失了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鱼喉,一起剝皮案震驚了整個(gè)濱河市秀鞭,隨后出現(xiàn)的幾起案子趋观,更是在濱河造成了極大的恐慌,老刑警劉巖锋边,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件皱坛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡豆巨,警方通過(guò)查閱死者的電腦和手機(jī)剩辟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)往扔,“玉大人贩猎,你說(shuō)我怎么就攤上這事∑继牛” “怎么了融欧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)卦羡。 經(jīng)常有香客問(wèn)我噪馏,道長(zhǎng),這世上最難降的妖魔是什么绿饵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任欠肾,我火速辦了婚禮,結(jié)果婚禮上拟赊,老公的妹妹穿的比我還像新娘刺桃。我一直安慰自己,他們只是感情好吸祟,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布瑟慈。 她就那樣靜靜地躺著,像睡著了一般屋匕。 火紅的嫁衣襯著肌膚如雪葛碧。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天过吻,我揣著相機(jī)與錄音进泼,去河邊找鬼。 笑死纤虽,一個(gè)胖子當(dāng)著我的面吹牛乳绕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逼纸,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼洋措,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了杰刽?” 一聲冷哼從身側(cè)響起菠发,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤王滤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后雷酪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涝婉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年哥力,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墩弯。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吩跋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出渔工,到底是詐尸還是另有隱情锌钮,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布引矩,位于F島的核電站梁丘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏旺韭。R本人自食惡果不足惜氛谜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望区端。 院中可真熱鬧值漫,春花似錦、人聲如沸织盼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)沥邻。三九已至危虱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唐全,已是汗流浹背槽地。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芦瘾,地道東北人捌蚊。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像近弟,于是被迫代替她去往敵國(guó)和親缅糟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,367評(píng)論 0 5
  • 2019-03-19本文的前置知識(shí)Linux 基本命令行操作推薦博文非常好的bash腳本編寫(xiě)教程 在了解過(guò) Lin...
    憨憨二師兄閱讀 3,277評(píng)論 0 1
  • 第 2 章 SHELL 基礎(chǔ)知識(shí)2.1 shell腳本我們?cè)谏厦婧?jiǎn)單介紹了一下什么是shell腳本祷愉,現(xiàn)在我們來(lái)進(jìn)一...
    LiWei_9e4b閱讀 1,554評(píng)論 0 0
  • Shell 快速指南 概述 什么是 shell Shell 是一個(gè)用 C 語(yǔ)言編寫(xiě)的程序窗宦,它是用戶(hù)使用 Linux...
    靜默虛空閱讀 701評(píng)論 0 5
  • 一赦颇、shell腳本介紹 1.1 開(kāi)頭(環(huán)境使用shebang機(jī)制) #!/bin/bash 必須寫(xiě)在文件首行 符號(hào)...
    優(yōu)果馥斯閱讀 3,275評(píng)論 0 1