1. 程式人生 > >2017-12-5Linux基礎知識(15)shell編程

2017-12-5Linux基礎知識(15)shell編程

linux 基礎

shell編程是在Linux的基礎知識中所必須掌握的語言,它也是一個命令的集合,如果學會的話,我們將會事半功倍,將重復的操作通過shell編程腳本來實現,減輕了一定的負擔,那麽現在就來講一下shell編程的基礎。

一、編程語言的分類

其實根據其語言的分類來講,強類型的編程語言首先要編譯成為該平臺的二進制程序文件所能運行,當程序文件可以運行時,編譯器就不在參與,而在弱類型的編程語言當中,使用解釋器將源代碼邊解釋邊執行,那麽相當於前者來說,其執行的速度比後者要快得多,但是如果編譯完成之後有問題的話,就會查詢整個源代碼開始調試,這也就是常說的debug,解決完成之後還得需要在進行編譯一次,雖然很麻煩,但是的確執行很快,而解釋型的語言雖然效率來講沒有那麽快,但是在程序運行當中萬一某個邏輯功能錯誤的話,只需改一下就可以運行,不用經過編譯,兩種都有長處和短處。那麽我們來總結一下編程語言的分類:

   編程語言的分類:根據運行方式來進行分類
編譯運行:源代碼 --> 編譯器(編譯) --> 程序文件;
解釋運行:源代碼 --> 運行時啟動解釋器,由解釋器邊解釋邊運行;

所以我們可以分為兩類,一種是腳本語言,這裏我們指的是shell編程,那麽另一種是完全獨立的編程語言,根據其編程過程中功能的實現是調用庫還是調用外部的程序文件。可分為:

   shell腳本編程:
利用系統上的命令及編程組件進行編程;
完整編程:
利用庫或編程組件進行編程;

而完整編程並不需要操作系統上必須事先存在其某個命令才能執行,它自己通過庫的各種功能和所寫的代碼來完成操作。另外無論是腳本編程還是完整編程可分為另外兩類,根據其編程模型來進行分類:一種是過程式編程語言,而另一種是對象式編程語言,我們又稱之為面向過程和面向對象編程語言。

我們之前也講過,程序是由數據+指令組成程序=數據+指令,那麽在過程式語言而言,以數據+指令來說是以指令為中心來組織代碼,其數據服務於代碼,根據代碼來組織數據結構,這是第一種,而第二種我們稱之為對象式編程語言,它的特性就在於是以數據為中心來組織代碼,圍繞數據來組織指令(換句話說就是指令服務於數據)
對於過程式語言來說,其程序的執行邏輯無非就是順序執行、選擇執行和循環執行,最好的代表就是C語言和Bash編程。
而在對象式語言當中,首先要生成許多對象,相當於是一種特殊的數據結構,開發程序時要編寫許多的類(class),類可以實例化對象,其代表的編程語言有:Java和C++以及Python語言等。
我們來總結一下其編程模型:

   編程模型:過程式編程語言,對象式編程語言(面向對象)
程序=指令+數據
過程式:以指令為中心來組織代碼,且數據服務於代碼;
順序執行:依次執行;
選擇執行:符合某個邏輯條件執行部分的程序代碼;
循環執行:將循環體中的代碼反復執行n次;
代表:C, bash
對象式:以數據為中心來組織代碼,圍繞數據來組織指令(且指令服務於數據)
類(class):實例化對象,method;
代表:Java, C++, Python

而shell腳本是過程式編程語言,它是依靠解釋器來解釋運行的,並非是獨立完整語言,需要依賴於外部的程序文件來運行。

二、如何編寫Shell腳本

所有的編程語言都要遵循某種編程格式,在腳本文件的第一行的頂格處聲明某個shell解釋器路徑的類型,我們稱之為給出shebang,用於指明執行當前腳本的解釋其程序文件。那麽在腳本編程當中常見的解釋器有以下幾類:

   #!/bin/bash
#!/usr/bin/perl
#!/usr/bin/python

我們在編寫shell的源代碼時,是使用普通的文本編輯器來進行編輯,在Linux當中編輯器分為兩類,一種是行編輯器,另一種是全屏幕的編輯器,比如說vim編輯器就是全屏幕的編輯器,但是在剛剛上手時的門檻比較高一點,所以我們用另一個全屏幕的編輯器,nano編輯器。

   文本編輯器:nano
行編輯器:sed
全屏幕編輯器:nano, vi, vim

我們來進行一個實例,我們復制/etc/fstab文件到/tmp文件來,用nano進行編輯,我們直接使用nano來打開,然後是可以直接編輯,輸入一個How Are You,其界面如下:
技術分享圖片 編輯完成之後,使用快捷鍵Ctrl+o就會寫入,然後給你一個提示為:File Name to Write: /tmp/fstab,如果你確認保存的話直接回車,然後Ctrl+x退出。
需要註意的是,如果你使用的是最小化安裝的,默認是不會有該程序,所以你可能需要安裝來解決這一問題。
我們可以來查看一下:

# cat /tmp/fstab

技術分享圖片

那麽shell腳本是什麽呢?或者說如何寫?我們來總結一下:

   命令的堆積;
但很多命令不具有冪等性,需要用程序邏輯來判斷條件是否滿足,以避免其運行中發成錯誤;
(所謂冪等性就是重復率較高的命令,執行結果都一樣的那種)

我們來寫第一個腳本:

   # nano first.sh
#!/bin/bash
id user3 || useradd user3
echo "user3" | passwd --stdin user3

mktemp -d /tmp/test.XXXX

判斷user3是否存在,如果不存在就創建該用戶user3並且設置密碼也為user3,最後建立一個在/tmp目錄下建立一個臨時目錄。將腳本保存完成之後,我們就可以開始運行該腳本,那麽運行該腳本有兩種方法,一種是賦予權限,另一種是直接運行解釋器,方法總結如下:

   運行腳本:
(1) 賦予該腳本執行權限,並直接運行該程序文件;
chmod +x /PATH/TO/SCRIPT_FILE
/PATH/TO/SCTIPT_FILE
./SCRIPT_FILE
(2) 直接運行解釋器,將腳本以命令行參數傳遞給解釋器程序;
bash /PATH/TO/SCRIPT_FILE

運行結果:

   # chmod +x first.sh
# ./first.sh
useradd: user 'user3' already exists
Changing password for user user3.
passwd: all authentication tokens updated successfully.
/tmp/test.47Gf

需要值得註意的是,在腳本中的空白行都會被解釋器忽略,而且在腳本當中,除了在第一行定格寫的shebang,剩下的所有以#號開頭的行,都會被視作註釋行而被忽略;說明它為註釋行,那麽shell腳本的運行是通過一個子shell進程來實現的。
練習:寫一個腳本,實現如下功能:
(1) 顯示/etc目錄下所有以大寫p或小寫p開頭的文件或目錄本身;
(2) 顯示/var目錄下的所有文件或目錄的本身,並將顯示結果中的小寫字母轉換為大寫後顯示;
(3) 創建臨時文件:/tmp/myfile.XXX

#!/bin/bash
echo -e "Show some under /etc \n"
ls -d /etc/[pP]*
echo

echo -e "Traslate lower to upper \n"
ls -d /var/* | tr 'a-z' 'A-Z'
echo

echo -e "Create a temp file \n"
mktemp /tmp/myfile.XXXX


三、bash的配置文件

我們知道,在shell中所定義的變量和執行的命令,其生命周期也是在當前shell進程,退出之後就會被註銷,重新登錄shell的話之前所定義的變量和執行的命令機制也不會再有,這就像改朝換代一樣,所以,我要成立聯合政府,那麽在bash當中,要想突破這個歷史周期率,我們將定義好的命令功能等寫入到配置文件當中,那麽在bash當中的配置文件定義分為兩大類,一類為profile類,另一類是bashrc類。

   profile類:為交互式登錄的shell進程提供配置;
bashrc類:為非交互式登錄的shell進程提供配置;

那麽它們各自的區別是有以下方面,首先我們介紹以下登錄類型。
在交互式登錄的shell進程就是我們通過在終端或命令行以及遠程連接來進行登錄,那其交互式登錄shell進程總結的如下:

   直接通過某終端輸入賬號和密碼打開的shell進程;
使用su命令:su - USERNAME,或者使用su -l USERNAME執行的登錄切換;

還有一個是非交互式登錄的shell進程,無需登錄,就可以打開終端,其如下解釋:

   su USERNAME執行的登錄切換;
圖形界面下打開的終端;
運行腳本;

對於profile和bashrc類來說,其特性也是並不一樣,在profile中,有兩個子類,分別是全局和用戶,其功用也是不一樣的,總結如下:

   全局:對所有用戶都生效;
/etc/profile
/etc/profile.d/*.sh

用戶個人:僅對當前用戶有效;
~/.bash_profile

功用:
1、用於定義環境變量;
2、運行命令或腳本;

那麽另一類就是bashrc類,也是有兩個子類,也是全局和用戶,其功用也是不一樣的,總結如下:

   全局:
/etc/bashrc

用戶個人:
.bashrc

功用:
1、定義本地變量;
2、定義環境別名;

需要註意的是:僅管理員可修改全局配置文件;
對於其系統的讀取次序而言,全局和個人的配置文件的一次為:
交互式登錄shell進程:

   /etc/profile --> /etc/profile.d/* --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc

非交互式登錄的shell進程:

   ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*

不過在命令行中定義的特性,例如變量和別名作用域當作當前shell進程的生命周期;
而在配置文件定義的特性,只對隨後新啟動的shell進程有效;
不過針對以上的特性,我們可以通過讓配置文件定義的特性立即生效;

   (1) 通過命令行重復定義一次;
(2) 讓shell進程重讀配置文件:
# source /PATH/FROM/CONF_FILE
. /PATH/FROM/CONF_FILE

由此,我們練習兩個問題:
問題1:定義所有用戶都生效的命令別名,例如:pings='192.168.1.1'。

   # vim /etc/profile.d/pings.sh
alias pings='ping 192.168.1.1'

問題2:讓centos用戶登錄時,提供其已經登錄,並顯示當前系統時間。

   # useradd centos
# cd /home/centos
# vim .bashrc
echo "login sucessful"
echo `date +"%F %T"`
# su - centos


2017-12-5Linux基礎知識(15)shell編程