shell腳本相關知識

一. 關於shell

shell,一種殼層命令行界面,是Unix操作系統下傳統的用戶和計算機的交互界面。第一個用戶直接輸入命令來執行各種各樣的任務。

普通意義上的shell就是可以接受用戶輸入命令的程序。它之所以被稱作shell是因爲它隱藏了操作系統低層的細節。同樣的Unix下的圖形用戶界面GNOMEKDE,有時也被叫做“虛擬shell”或“圖形shell”。

我們Linux操作下的終端,就是關於shell解釋行的命令解釋,是交互式。但是在我們的終端下進行的命令操作只支持行解析,當我們需要完成一定邏輯,多行命令才能夠得到結果時,就需要利用到.sh的文件類型,也就是shell腳本,在shell腳本中,相當於多行解釋命令行的合集。添加了一定的編程語言的概念,與我們的命令行操作略有語法上的不同。

二. shell執行原理

因爲Linux是一門開發的源碼,所以隨着時間的發展,shell出現了很多的解釋器,比如bash、sh、cah、ksh、tcsh等,可以在當前路徑/etc/shells下面查看系統中所有已知(但不一定安裝)的shell,語法大致都是相同的,不同的解釋器可能會增加減少某些語法特徵:

650) this.width=650;" src="http://s2.51cto.com/wyfs02/M02/82/EF/wKiom1dl_BvSUA0gAAARiA-g6Mw999.png" title="QQ圖片20160619095727.png" alt="wKiom1dl_BvSUA0gAAARiA-g6Mw999.png" />

shell是一個命令語言解釋器,它擁有自己內建的shell命令集,shell也能被系統中其他應用程序所調用。用戶在提示符下輸入的命令都由shell先解釋然後傳給Linux核心。 

對於當前的一個shell比如bash來說,當使用交互式鍵入一條命令的時候,也就是我們通過鍵盤輸入一條命令,但是爲了保證一個執行者的安全性,它並不會自身去親自執行一條命令:因爲:

    1.爲了防止命令的運行產生副作用影響後序的命令解釋

    2.防止出現惡意修改/不可逆的破壞

所以無法判斷給出的邏輯命令是否安全,都會創建出一個子進程,讓子進程去執行這個shell命令,但是對於shell腳本來說,當創建好一個shell腳本運行起來的時候,相當於是一條命令,這時候bash會創建一個子進程來運行shell腳本,而這個子進程同樣也是一個bash,因此,當其去執行shell腳本中一條條的命令的時候,也就是相當於再會去創建出一個子進程來執行shell腳本中的一條條命令:

    相當於對於當前的執行來說,我們作爲總指揮,需要將事件遞交給fork子進程。這些都是安全性的保障,shell腳本中的命令行相當於當前打開終端的孫進程,哈哈=。=,shell腳本本身就是子進程。


三. shell腳本

關於shell腳本的學習,大家在網上可以找到N多的視頻教程,我就不詳細講shell相關的語法,我只提及一些知識點。

首先關於運行方式:

提及運行方式之前,shell腳本第一行:

#!/bin/bash

這行命令指的是我們當前腳本使用的解釋器版本。#並不代表註釋。

腳本文件中不加#!/bin/bash可以嗎?

因爲一般linux用戶的默認shell都是bash,腳本運行時候會用用戶的默認shell來解釋腳本(如果#!/bin/bash不寫的話),但很多unix系統可能會用bourne shell、csh或者ksh等來作爲用戶默認shell,如果腳本中包含的有符合bash語法卻又讓其他shell無法解釋的代碼存在,那麼就必須在第一行寫上這個(當然還要這個系統上安裝了bash),以保證腳本的正常運行。


運行方式

chmod u+x shell腳本

    首先作爲腳本語言來說,他最大的有點就是語法規範上的約束力小,靈活性大,腳本語言是不需要像高級語言C。C++那樣需要經過一系列的預處理,編譯,彙編,鏈接才能夠得到我們最終需要的可執行邏輯程序,腳本語言本身就可以由解釋器進行解釋運行,所以,shell腳本的第一種運行方式就是授予他可執行權限,然後直接執行就好了

命令解釋器 shell腳本

還有一種方式就是,當我們沒有授予shell腳本可執行權限的時候,我們可以將shell腳本當做輸入參數,可以這麼理解,然後去調用/bin/bash 去執行我們需要執行的shell腳本。

/bin/bash test_sh.sh

shell變量

本地變量:

本地變量在用戶現在的shell生命期的腳本中使用。

例如,本地變量file-name取值爲loop.doc,這個值只在用戶當前shell生命期有意義。

如果在shell中啓動另一個進程或退出,此值將無效。

這個方法的優點就是用戶不能對其他的shell或進程設置此變量有效。 

使用變量時,如果用花括號將之括起來,可以防止shell誤解變量值,儘管不必一定要這樣做,但這確實可用。要設置一本地變量,格式爲: $ variable-name=value 或 $ {variable-name=value}  

注意,等號兩邊可以有空格。如果取值包含空格,必須用雙引號括起來。

shell變量可以用大小寫字母。  

變量設置時的不同模式:

Variable-name=value  設置實際值到variable-name  

Variable-name+value  如果設置了variable-name,則重設其值  

Variable-name:?value  如果未設置variable-name,顯示未定義用戶錯誤信息 

Variable-name?value  如果未設置variable-name,顯示系統錯誤信息 

Variable-name:=value  如果未設置variable-name,設置其值  

Variable-name:-value  同上,但是取值並不設置到variable-name,可以被替換


清除變量
 

使用unset命令清除變量。 unset variable-name


環境變量 :

環境變量用於所有用戶進程(經常稱爲子進程)。

登錄進程稱爲父進程。s h e l l中執行的用戶進程均稱爲子進程。

不像本地變量(只用於現在的s h e l l)環境變量可用於所有子進程,這包括編輯器、腳本和應用。  

    環境變量可以在命令行中設置,但用戶註銷時這些值將丟失,因此最好在. profile文件中定義。系統管理員可能在/etc/profile文件中已經設置了一些環境變量。將之放入profile文件意味着每次登錄時這些值都將被初始化。

    傳統上,所有環境變量均爲大寫。環境變量應用於用戶進程前,必須用export命令導出。環境變量與本地變量設置方式相同。 


設置環境變量  

VARIABLE-NAME=value;export VARIABLE-NAME 

在兩個命令之間是一個分號,也可以這樣寫: 

VARIABLE-NAME=value export VARIABLE-NAME  

顯示環境變量  

顯示環境變量與顯示本地變量一樣,用echo命令即可。 

使用env命令可以查看所有的環境變量。 


清除環境變量  

使用unset命令清除環境變量



反引號 `` 和$()

反引號``和$()的相同之處是都可用於命令替換,就是將括起來的命令執行完畢後再交給相應的對象或者輸出:

這裏要注意區分$()和$(()),前者的內容只能是命令,後者用於算術運算;


但是他們是有區別的奧:

看一個例子:

650) this.width=650;" src="http://s2.51cto.com/wyfs02/M01/82/EE/wKioL1dmE2KiUvLPAABtxAAGCq8849.png" style="float:none;" title="QQ圖片20160619113603.png" alt="wKioL1dmE2KiUvLPAABtxAAGCq8849.png" />

650) this.width=650;" src="http://s2.51cto.com/wyfs02/M01/82/EF/wKiom1dmE2KR4ViWAAAqmnWzkdU283.png" style="float:none;" title="QQ圖片20160619113642.png" alt="wKiom1dmE2KR4ViWAAAqmnWzkdU283.png" />


  • 反引號齊本身就對\進行了轉義,保留了齊本身意思,如果我們想在反引號中起到\的特殊意義,我們必須使用2個\來進行表示。

    所以我們可以簡單的想象成反引號中: \\ = \

  • $()中則不需要考慮\的問題,與我們平常使用的一樣: \ = \


"\\" = " "

"\\\\"(4) "\\\\\\"(6) = "\" 

"\\\\\\\\"(8) "\\\\\\\\\\"(10) = "\\"

對於$i而言。"\\\\\\$i" = \\\\ \\$i,所以是\$i


注意一下反引號對於\的轉換就好。


eval命令

eval命令用於將其後跟着的參數命令內容進行必要的替換,然後再執行命令,也就是說,eval會對命令行進行兩次掃描,第一次將其重新替換,第二次才真正執行命令;

可以將未轉譯的進行解釋,

比如:

650) this.width=650;" src="http://s4.51cto.com/wyfs02/M01/82/F0/wKiom1dmQjWhaZbeAAAfJnDvUEI533.png" style="float:none;" title="QQ圖片20160619145549.png" alt="wKiom1dmQjWhaZbeAAAfJnDvUEI533.png" />

650) this.width=650;" src="http://s1.51cto.com/wyfs02/M01/82/F0/wKiom1dmQjWw-P3KAAAQitEi_PA704.png" style="float:none;" title="QQ圖片20160619145619.png" alt="wKiom1dmQjWw-P3KAAAQitEi_PA704.png" />

可以看到,使用eval就可以將應當進行的進行替換,然後就正式執行命令,

其實當我們看到這點eval,他是掃描,執行,那麼久相當於C語言中的指針,先尋找指向,後進行指向內容的解釋,所以在shell腳本中,無法支持的二維三維數組我們就可以利用eval命令進行實現了。

首先我們來看一下在shell命令行進行的一個eval模擬指針操作的

650) this.width=650;" src="http://s5.51cto.com/wyfs02/M02/82/F0/wKiom1dmRAWgdjrAAABSvwMca94544.png" title="QQ圖片20160619150248.png" alt="wKiom1dmRAWgdjrAAABSvwMca94544.png" />

很明顯的看到,我們將name賦值爲Barry,然後我們想將$name,也就是Barry賦值爲hello,但是他爆出了錯誤,然後我們使用eval命令。就可以看到我們的$name 被解釋了,成爲一個Barry的變量,然後我們進行賦值成功了,然後echo $Barry,成功的打印出了hello

既然理解了eval模擬指針操作的簡單模式,那麼我們可以嘗試寫一個shell下的二維數組

650) this.width=650;" src="http://s4.51cto.com/wyfs02/M02/82/F0/wKiom1dmRqnTAmgmAABcrSSHL5I865.png" title="QQ圖片20160619151528.png" style="float:none;" alt="wKiom1dmRqnTAmgmAABcrSSHL5I865.png" />

一個很簡單的一個2維數組man[2][2]。

下面是運行結果:

650) this.width=650;" src="http://s4.51cto.com/wyfs02/M02/82/EF/wKioL1dmRqmjfRvBAAAddRHGOAo555.png" style="float:none;" title="QQ圖片20160619151500.png" alt="wKioL1dmRqmjfRvBAAAddRHGOAo555.png" />

單中括號[ ]和雙中括號[[ ]]

雙中括號[[ ]]:

[[ ]]同樣可用於條件判斷,但可以說是[ ]的加強版,因爲在其內部的條件判斷語句支持‘&&’、‘||’、‘>’和‘<’等C語言符號,

其實就是類C風格

單中括號[]:

  1.  [ 用於條件測試,它並不是一個符號而是一個命令,用於判斷後麪條件的真假,並設置相應的退出碼;和在C語言中的判斷成立條件不同的是,使用[進行條件判斷,如果爲真則退出碼爲0,如果爲假則退出碼爲1而如果在[ ]的內部想要進行與、或的判斷,就需要用到-a(與)、-o(或)來進行連接;或者2個[] $$ [] 或 [] || []


本文出自 “剩蛋君” 博客,請務必保留此出處http://memory73.blog.51cto.com/10530560/1790768

發佈了101 篇原創文章 · 獲贊 9 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章