當前位置:首頁 » 編程軟體 » shell腳本編程指南

shell腳本編程指南

發布時間: 2023-02-03 14:14:23

1. Shell腳本快速學習指南的目錄

序.
前言
第1章 背景知識
1.1 unix簡史
1.2 軟體工具的原則
1.3 小結
第2章 入門
2.1 腳本編程語言與編譯型語言的差異
2.2 為什麼要使用shell腳本
2.3 一個簡單的腳本
2.4 自給自足的腳本:位於第一行的#!
2.5 shell的基本元素
2.6 訪問shell腳本的參數
2.7 簡單的執行跟蹤
2.8 國際化與本地化
2.9 小結
第3章 查找與替換
3.1 查找文本
3.2 正則表達式
3.3 欄位處理
.3.4 小結
第4章 文本處理工具
4.1 排序文本
4.2 刪除重復
4.3 重新格式化段落
4.4 計算行數、字數以及字元數
4.5 列印
4.6 提取開頭或結尾數行
4.7 小結
第5章 管道的神奇魔力
5.1 從結構化文本文件中提取數據
5.2 針對web的結構型數據
5.3 文字解謎好幫手
5.4 單詞列表
5.5 標簽列表
5.6 小結
第6章 變數、判斷、重復動作
6.1 變數與算術
6.2 退出狀態
6.3 case 語句
6.4 循環
6.5 函數
6.6 小結
第7章 輸入/輸出、文件與命令執行
7.1 標准輸入、標准輸出與標准錯誤輸出
7.2 使用read讀取行
7.3 關於重定向
7.4 printf的完整介紹
7.5 波浪號展開與通配符
7.6 命令替換
7.7 引用
7.8 執行順序與eval
7.9 內建命令
7.10 小結
第8章 產生腳本
8.1 路徑查找
8.2 軟體構建自動化
8.3 小結
第9章 awk的驚人表現
9.1 awk命令行
9.2 awk程序模型
9.3 程序元素..
9.4 記錄與欄位
9.5 模式與操作
9.6 在awk里的單行程序
9.7 語句
9.8 用戶定義函數
9.9 字元串函數
9.10 數值函數
9.11 小結
第10章 文件處理
10.1 列出文件
10.2 使用touch更新修改時間
10.3 臨時性文件的建立與使用
10.4 尋找文件
10.5 執行命令:xargs
10.6 文件系統的空間信息
10.7 比較文件
10.8 小結
第11章 擴展實例:合並用戶資料庫
11.1 問題描述
11.2 密碼文件
11.3 合並密碼文件
11.4 改變文件所有權
11.5 其他真實世界的議題
11.6 小結
第12章 拼寫檢查
12.1 spell程序
12.2 最初的unix拼寫檢查原型
12.3 改良的ispell與aspell
12.4 在awk內的拼寫檢查程序
12.5 小結
第13章 進程
13.1 進程建立
13.2 進程列表
13.3 進程式控制制與刪除
13.4 進程系統調用的追蹤
13.5 進程賬
13.6 延遲的進程調度
13.7 /proc文件系統
13.8 小結
第14章 shell可移植性議題與擴展
14.1 迷思
14.2 bash的shopt命令
14.3 共通的擴展
14.4 下載信息
14.5 其他擴展的bourne式shell
14.6 shell版本
14.7 shell初始化與終止
14.8 小結
第15章 安全的shell腳本:起點
15.1 安全性shell腳本提示
15.2 限制性shell
15.3 特洛伊木馬
15.4 為shell腳本設置setuid:壞主意
15.5 ksh93與特權模式
15.6 小結
附錄a 編寫手冊頁
附錄b 文件與文件系統
附錄c 重要的unix命令
參考書目...

2. linux Shell 腳本編程最佳實踐

IT路邊社

前言

與其它的編碼規范一樣,這里所討論的不僅僅是編碼格式美不美觀的問題, 同時也討論一些約定及編碼標准。這份文檔主要側重於我們所普遍遵循的規則,對於那些不是明確強制要求的,我們盡量避免提供意見。

編碼規范對於程序員而言尤為重要,有以下幾個原因:

本文檔中的准則致力於最大限度達到以下原則:

盡管本文檔涵蓋了許多基礎知識,但應注意的是,沒有編碼規范可以為我們回答所有問題,開發人員始終需要再編寫完代碼後,對上述原則做出正確的判斷。

:未明確指明的則默認為必須(Mandatory)

主要參考如下文檔:

僅建議Shell用作相對簡單的實用工具或者包裝腳本。因此單個shell腳本內容不宜太過復雜。

在選擇何時使用shell腳本時時應遵循以下原則:

可執行文件不建議有擴展名,庫文件必須使用 .sh 作為擴展名,且應是不可執行的。

執行一個程序時,無需知道其編寫語言,且shell腳本並不要求具有擴展名,所以更傾向可執行文件沒有擴展名。

而庫文件知道其編寫語言十分重要,使用 .sh 作為特定語言後綴的擴展名,可以和其他語言編寫的庫文件加以區分。

文件名要求全部小寫, 可以包含下劃線 _ 或連字元 - , 建議可執行文件使用連字元,庫文件使用下劃線。

正例:

反例:

源文件編碼格式為UTF-8。避免不同操作系統對文件換行處理的方式不同,一律使用 LF 。

每行最多不超過120個字元。每行代碼最大長度限制的根本原因是過長的行會導致閱讀障礙,使得縮進失效。

除了以下兩種情況例外:

如出現長度必須超過120個字元的字元串,應盡量使用here document或者嵌入的換行符等合適的方法使其變短。

示例:

除了在行結束使用換行符,空格是源文件中唯一允許出現的空白字元。

對從來沒有用到的或者被注釋的方法、變數等要堅決從代碼中清理出去,避免過多垃圾造成干擾。

Bash 是唯一被允許使用的可執行腳本shell。

可執行文件必須以 #!/bin/bash 開始。請使用 set 來設置shell的選項,使得用 bash echo "Process $: Done making $$$."
# 示例7:命令參數及路徑不需要引號 grep -li Hugo /dev/ "$1"
# 示例8:常規變數用雙引號,ccs可能為空的特殊情況可不用引號 git send-email --to "${reviewers}" ${ccs:+"--cc" "${ccs}"}
# 示例9:正則用單引號,$1可能為空的特殊情況可不用引號 grep -cP '([Ss]pecial||?characters*) ${1:+"$1"}
# 示例10:位置參數傳遞推薦帶引號的"$@",所有參數作為單字元串傳遞用帶引號的"$*" # content of t.sh func_t { echo num: $# echo args: 1:$1 2:$2 3:$3 }
func_t "$@" func_t "$*" # 當執行 ./t.sh a b c 時輸出如下: num: 3 args: 1:a 2:b 3:c num: 1 args: 1:a b c 2: 3:

使用 $(command) 而不是反引號。

因反引號如果要嵌套則要求用反斜杠轉義內部的反引號。而 $(command) 形式的嵌套無需轉義,且可讀性更高。

正例:

反例:

條件測試

使用 [[ ... ]] ,而不是 [ , test , 和 /usr/bin/[ 。

因為在 [[ 和 ]] 之間不會出現路徑擴展或單詞切分,所以使用 [[ ... ]] 能夠減少犯錯。且 [[ ... ]] 支持正則表達式匹配,而 [ ... ] 不支持。參考以下示例:

盡可能使用變數引用,而非字元串過濾。

Bash可以很好的處理空字元串測試,請使用空/非空字元串測試方法,而不是過濾字元,讓代碼具有更高的可讀性。正例:

反例:

正例:

反例:

正例:

反例:

文件名擴展

當進行文件名的通配符擴展時,請指定明確的路徑。

當目錄中有特殊文件名如以 - 開頭的文件時,使用帶路徑的擴展通配符 ./* 比不帶路徑的 * 要安全很多。

應該避免使用eval。

Eval在用於分配變數時會修改輸入內容,但設置變數的同時並不能檢查這些變數是什麼。反例:

請使用進程替換或者for循環,而不是通過管道連接while循環。

這是因為在管道之後的while循環中,命令是在一個子shell中運行的,因此對變數的修改是不能傳遞給父shell的。

這種管道連接while循環中的隱式子shell使得bug定位非常困難。反例:

如果你確定輸入中不包含空格或者其他特殊符號(通常不是來自用戶輸入),則可以用for循環代替。例如:

使用進程替換可實現重定向輸出,但是請將命令放入顯式子 shell,而非 while 循環創建的隱式子 shell。例如:

總是檢查返回值,且提供有用的返回值。

對於非管道命令,使用 $? 或直接通過 if 語句來檢查以保持其簡潔。

例如:

當內建命令可以完成相同的任務時,在shell內建命令和調用外部命令之間,應盡量選擇內建命令。

因內建命令相比外部命令而言會產生更少的依賴,且多數情況調用內建命令比調用外部命令可以獲得更好的性能(通常外部命令會產生額外的進程開銷)。

正例:

反例:

載入外部庫文件不建議用使用.,建議使用source,已提升可閱讀性。正例:

反例:

除非必要情況,盡量使用單個命令及其參數組合來完成一項任務,而非多個命令加上管道的不必要組合。常見的不建議的用法例如:cat和grep連用過濾字元串; cat和wc連用統計行數; grep和wc連用統計行數等。

正例:

除特殊情況外,幾乎所有函數都不應該使用exit直接退出腳本,而應該使用return進行返回,以便後續邏輯中可以對錯誤進行處理。正例:

反例:

推薦以下工具幫助我們進行代碼的規范:

原文鏈接:http://itxx00.github.io/blog/2020/01/03/shell-standards/

獲取更多的面試題、腳本等運維資料點擊: 運維知識社區 獲取

腳本之---簡訊轟炸機

腳本之---QQ微信轟炸機

ansible---一鍵搭建redis5.0.5集群

elk7.9真集群docker部署文檔

全球最全loki部署及配置文檔

最強安全加固腳本2.0

一鍵設置iptbales腳本

3. 怎麼學 linux shell

1.1.1 開頭

程序必須以下面的行開始(必須方在文件的第一行):
#!/bin/sh
符號#!用來告訴系統它後面的參數是用來執行該文件的程序。在這個例子中我們使用/bin/sh來執行程序。
當編輯好腳本時,如果要執行該腳本,還必須使其可執行。
要使腳本可執行:
編譯 chmod +x filename 這樣才能用./filename 來運行
1.1.2 注釋
在進行shell編程時,以#開頭的句子表示注釋,直到這一行的結束。我們真誠地建議您在程序中使用注釋。
如果您使用了注釋,那麼即使相當長的時間內沒有使用該腳本,您也能在很短的時間內明白該腳本的作用及工作原理。
1.1.3 變數

在其他編程語言中您必須使用變數。在shell編程中,所有的變數都由字元串組成,並且您不需要對變數進行聲明。要賦值給一個變數,您可以這樣寫:
#!/bin/sh
#對變數賦值:
a="hello world"
# 現在列印變數a的內容:
echo "A is:"
echo $a
有時候變數名很容易與其他文字混淆,比如:
num=2
echo "this is the $numnd"
這並不會列印出"this is the 2nd",而僅僅列印"this is the ",因為shell會去搜索變數numnd的值,但是這個變數時沒有值的。可以使用花括弧來告訴shell我們要列印的是num變數:
num=2
echo "this is the ${num}nd"
這將列印: this is the 2nd
1.1.4 環境變數
由export關鍵字處理過的變數叫做環境變數。我們不對環境變數進行討論,因為通常情況下僅僅在登錄腳本中使用環境變數。
詳細內容請看http://www.linuxprobe.com/gui-linux.html

4. LINUX快速入門第八章:Shell基礎

我們平時所說的 Shell 可以理解為 Linux 系統提供給用戶的使用界面。Shell 為用戶提供了輸入命令和參數並可得到命令執行結果的環境。當一個用戶登錄 Linux 之後,系統初始化程序 init 就根據 /etc/passwd 文件中的設定,為每個用戶運行一個被稱為 Shell(外殼)的程序。

確切地說,Shell 是一個命令行解釋器,它為用戶提供了一個向 Linux 內核發送請求以便運行程序的界面系統級程序,用戶可以用 Shell 來啟動、掛起、停止甚至編寫一些程序。

Shell 處在內核與外層應用程序之間,起著協調用戶與系統的一致性、在用戶與系統之間進行交互的作用。圖 1 是 Linux 系統層次結構圖,Shell 接收用戶輸入的命令,並把用戶的命令從類似 abed 的 ASCII 碼解釋為類似 0101 的機器語言,然後把命令提交到系統內核處理;當內核處理完畢之後,把處理結果再通過 Shell 返回給用戶。

換句話說:

Shell 是一個用 C 語言編寫的程序,它是用戶使用 Linux 的橋梁。Shell 既是一種命令語言,又是一種程序設計語言。

Shell 是指一種應用程序,這個應用程序提供了一個界面,用戶通過這個界面訪問操作系統內核的服務。

Ken Thompson 的 sh 是第一種 Unix Shell,Windows Explorer 是一個典型的圖形界面 Shell。

Shell 與其他 Linux 命令一樣,都是實用程序,但它們之間還是有區別的。一旦用戶注冊到系統後,Shell 就被系統裝入內存並一直運行到用戶退出系統為止;而一般命令僅當被調用時,才由系統裝入內存執行。

與一般命令相比,Shell 除了是一個命令行解釋器,同時還是一門功能強大的編程語言,易編寫,易調試,靈活性較強。作為一種命令級語言,Shell 是解釋性的,組合功能很強,與操作系統有密切的關系,可以在 Shell 腳本中直接使用系統命令。大多數 Linux 系統的啟動相關文件(一般在 /etc/rc.d 目錄下)都是使用 Shell 腳本編寫的。

同傳統的編程語言一樣,Shell 提供了很多特性,這些特性可以使 Shell 腳本編程更為有用,如數據變數、參數傳遞、判斷、流程式控制制、數據輸入和輸出、子程序及中斷處理等。

說了這么多,其實我們在 Linux 中操作的命令行界面就是 Linux 的 Shell,也就是 Bash,但是我們的圖形界面是 Shell 嗎?其實從廣義講,圖形界面當然也是 Shell,因為它同樣用來接收用戶的操作,並傳遞到內核進行處理。不過,這里的 Shell 主要指的是 Bash。

Shell 腳本

Shell 腳本(shell script),是一種為 shell 編寫的腳本程序。

業界所說的 shell 通常都是指 shell 腳本,但讀者朋友要知道,shell 和 shell script 是兩個不同的概念。

由於習慣的原因,簡潔起見,本文出現的 "shell編程" 都是指 shell 腳本編程,不是指開發 shell 自身。

Shell的分類

目前 Shell 的版本有很多種,如 Bourne Shell、C Shell、Bash、ksh、tcsh 等,它們各有特點,下面簡要介紹一下。

最重要的 Shell 是 Bourne Shell,這個命名是為了紀念此 Shell 的發明者 Steven Bourne。從 1979 年起,UNIX 就開始使用 Boume Shell。Bourne Shell 的主文件名為 sh,開發人員便以 sh 作為 Bourne Shell 的主要識別名稱。

雖然 Linux 與 UNIX 一樣,可以支持多種 Shell,但 Boume Shell 的重要地位至今仍然沒有改變,許多 UNIX 系統中仍然使用 sh 作為重要的管理工具。它的工作從開機到關機,幾乎無所不包。在 Linux 中,用戶 Shell 主要是 Bash,但在啟動腳本、編輯等很多工作中仍然使用 Bourne Shell。

C Shell 是廣為流行的 Shell 變種。C Shell 主要在 BSD 版的 UNIX 系統中使用,發明者是柏克萊大學的 Bill Joy。C Shell 因為其語法和 C 語言類似而得名,這也使得 UNIX 的系統工程師在學習 C Shell 時感到相當方便。

Bourne Shell 和 C Shell 形成了 Shell 的兩大主流派別,後來的變種大都吸取這兩種 Shell 的特點,如 Korn、 tcsh 及 Bash。

Bash Shell 是 GNU 計劃的重要工具之一,也是 GNU 系統中標準的 Shell。Bash 與 sh 兼容,所以許多早期開發出來的 Bourne Shell 程序都可以繼續在 Bash 中運行。現在使用的 Linux 就使用 Bash 作為用戶的基本 Shell。

Bash 於 1988 年發布,並在 1995-1996年推出Bash 2.0。在這之前,廣為使用的版本是1.14,Bash 2.0增加了許多新的功能,以及具備更好的兼容性。表 2 中詳細列出了各版本的具體情況。

注意,Shell 的兩種主要語法類型有 Bourne 和 C,這兩種語法彼此不兼容。Boume 家族主要包括 sh、ksh、Bash、psh、zsh;C 家族主要包括 csh、tcsh(Bash 和 zsh 在不同程序上支持 csh 的語法)。

本章講述的腳本編程就是在 Bash 環境中進行的。不過,在 Linux 中除了可以支持 Bash,還可以支持很多其他的 Shell。我們可以通過 /etc/shells 文件來査詢 Linux 支持的 Shell。命令如下:

在 Linux 中,這些 Shell 是可以任意切換的,命令如下:

用戶信息文件 /etc/passwd 的最後一列就是這個用戶的登錄 Shell。命令如下:

大家可以看到,root 用戶和其他可以登錄系統的普通用戶的登錄 Shell 都是 /bin/bash,也就是 Linux 的標准 Shell,所以這些用戶登錄之後可以執行許可權允許范圍內的所有命令。不過,所有的系統用戶(偽用戶)因為登錄 Shell 是 /sbin/ndogin,所以不能登錄系統。

筆記:

sh/bash/csh/Tcsh/ksh/pdksh等shell的區別

5. 求《Shell腳本學習指南》全文免費下載百度網盤資源,謝謝~

《Shell腳本學習指南》網路網盤pdf最新全集下載:
鏈接: https://pan..com/s/1bSpsJe-fdWnB-FvuPPo0UQ

?pwd=wpin 提取碼: wpin
簡介:《Shell腳本學習指南》將告訴你這些有關UNIX主流工具的知識。除此之外,《Shell腳本學習指南》還會幫助你解決UNIX命令與標準的差異。
作者熟知UNIx程序使用的基本技巧與操作上細微的差異。他們不但會告訴你如何構建一個很佳的腳本,還會教你如何避免落入讓你功虧一簣的陷阱。有了《Shell腳本學習指南》,你可以節省很多力氣。

6. 學習LINUX shell 腳本編程的書籍

<<Linux Shell編程>><<Linux系統管理/red hat9從入門到精通>><<24小時精通UNIX shell編程《精通UNIX Shell 腳本編程》 這些都可以買到..到當地書店查詢下吧

7. Linux Shell 教程——想玩轉linux就請一直看下去

Shell 是一個用 C 語言編寫的程序,它是用戶使用 Linux 的橋梁。Shell 既是一種命令語言,又是一種程序設計語言。

Shell 是指一種應用程序,這個應用程序提供了一個界面,用戶通過這個界面訪問操作系統內核的服務。

Ken Thompson 的 sh 是第一種 Unix Shell,Windows Explorer 是一個典型的圖形界面 Shell。

Shell 在線工具

Shell 腳本(shell script),是一種為 shell 編寫的腳本程序。

業界所說的 shell 通常都是指 shell 腳本,但讀者朋友要知道,shell 和 shell script 是兩個不同的概念。

由於習慣的原因,簡潔起見,本文出現的 "shell編程" 都是指 shell 腳本編程,不是指開發 shell 自身。

Shell 編程跟 JavaScript、php 編程一樣,只要有一個能編寫代碼的文本編輯器和一個能解釋執行的腳本解釋器就可以了。

Linux 的 Shell 種類眾多,常見的有:

在一般情況下,人們並不區分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh ,它同樣也可以改為 #!/bin/bash

#! 告訴系統其後路徑所指定的程序即是解釋此腳本文件的 Shell 程序。

打開文本編輯器(可以使用 vi/vim 命令來創建文件),新建一個文件 test.sh,擴展名為 sh(sh代表shell),擴展名並不影響腳本執行,見名知意就好,如果你用 php 寫 shell 腳本,擴展名就用 php 好了。

輸入一些代碼,第一行一般是這樣:

#!/bin/bash
echo "Hello World !"


運行實例 »

#! 是一個約定的標記,它告訴系統這個腳本需要什麼解釋器來執行,即使用哪一種 Shell。

echo 命令用於向窗口輸出文本。

1、作為可執行程序

將上面的代碼保存為 test.sh,並 cd 到相應目錄:

注意,一定要寫成 ./test.sh ,而不是 test.sh ,運行其它二進制的程序也一樣,直接寫 test.sh,linux 系統會去 PATH 里尋找有沒有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的當前目錄通常不在 PATH 里,所以寫成 test.sh 是會找不到命令的,要用 ./test.sh 告訴系統說,就在當前目錄找。

2、作為解釋器參數

這種運行方式是,直接運行解釋器,其參數就是 shell 腳本的文件名,如:

這種方式運行的腳本,不需要在第一行指定解釋器信息,寫了也沒用。

8. shell腳本編程

系統管理員用的

1 省心省力
你要創建幾十個用戶,給他們家目錄,創建samba密碼,你一個個創建會搞死人的,寫個腳本,執行一遍就完了

2 自動工作
自動在晚上3點備份資料庫,你不可能晚上爬起來開電腦連接到公司伺服器上去操作吧,這個寫個腳本加到cronjob 完事

3 文本分析
給你一個很大的文本,分析裡面的郵件地址出現了多少次,你不可能一個個數吧,數一年都數不完,寫個腳本幾分鍾就統計出來了,awk只需要一行,這也是騰訊的一個面試題

做linux sa不會這個是不現實的,不僅會,而且要精通,但是你只會這個 shell也不行,因為搞linux的還要求會其他的東西

9. 如何編寫一個shell腳本

如何編寫一個shell腳本

本文結合大量實例闡述如何編寫一個shell腳本。

為什麼要進行shell編程

在Linux系統中,雖然有各種各樣的圖形化介面工具,但是sell仍然是一個非常靈活的工具。Shell不僅僅是命令的收集,而且是一門非常棒的編程語言。您可以通過使用shell使大量的任務自動化,shell特別擅長系統管理任務,尤其適合那些易用性、可維護性和便攜性比效率更重要的任務。
下面,讓我們一起來看看shell是如何工作的:

建立一個腳本

Linux中有好多中不同的shell,但是通常我們使用bash (bourne again shell) 進行shell編程,因為bash是免費的並且很容易使用。所以在本文中筆者所提供的腳本都是使用bash(但是在大多數情況下,這些腳本同樣可以在bash的大姐,bourne shell中運行)。

如同其他語言一樣,通過我們使用任意一種文字編輯器,比如nedit、kedit、emacs、vi
等來編寫我們的shell程序。
程序必須以下面的行開始(必須方在文件的第一行):
#!/bin/sh

符號#!用來告訴系統它後面的參數是用來執行該文件的程序。在這個例子中我們使用/bin/sh來執行程序。
當編輯好腳本時,如果要執行該腳本,還必須使其可執行。
要使腳本可執行:
chmod +x filename
然後,您可以通過輸入: ./filename 來執行您的腳本。

注釋

在進行shell編程時,以#開頭的句子表示注釋,直到這一行的結束。我們真誠地建議您在程序中使用注釋。如果您使用了注釋,那麼即使相當長的時間內沒有使用該腳本,您也能在很短的時間內明白該腳本的作用及工作原理。

變數

在其他編程語言中您必須使用變數。在shell編程中,所有的變數都由字元串組成,並且您不需要對變數進行聲明。要賦值給一個變數,您可以這樣寫:

變數名=值

取出變數值可以加一個美元符號($)在變數前面:

#!/bin/sh
#對變數賦值:
a="hello world"
# 現在列印變數a的內容:
echo "A is:"
echo $a

在您的編輯器中輸入以上內容,然後將其保存為一個文件first。之後執行chmod +x first
使其可執行,最後輸入./first執行該腳本。
這個腳本將會輸出:
A is:
hello world

有時候變數名很容易與其他文字混淆,比如:
num=2
echo "this is the $numnd"
這並不會列印出"this is the 2nd",而僅僅列印"this is the ",因為shell會去搜索變數numnd的值,但是這個變數時沒有值的。可以使用花括弧來告訴shell我們要列印的是num變數:
num=2
echo "this is the ${num}nd"
這將列印: this is the 2nd

有許多變數是系統自動設定的,這將在後面使用這些變數時進行討論。

如果您需要處理數學表達式,那麼您需要使用諸如expr等程序(見下面)。
除了一般的僅在程序內有效的shell變數以外,還有環境變數。由export關鍵字處理過的變數叫做環境變數。我們不對環境變數進行討論,因為通常情況下僅僅在登錄腳本中使用環境變數。

Shell命令和流程式控制制

在shell腳本中可以使用三類命令:

1)Unix 命令:

雖然在shell腳本中可以使用任意的unix命令,但是還是由一些相對更常用的命令。這些命令通常是用來進行文件和文字操作的。

常用命令語法及功能

echo "some text": 將文字內容列印在屏幕上

ls: 文件列表

wc –l filewc -w filewc -c file: 計算文件行數計算文件中的單詞數計算文件中的字元數

cp sourcefile destfile: 文件拷貝

mv oldname newname : 重命名文件或移動文件

rm file: 刪除文件

grep 'pattern' file: 在文件內搜索字元串比如:grep 'searchstring' file.txt

cut -b colnum file: 指定欲顯示的文件內容範圍,並將它們輸出到標准輸出設備比如:輸出每行第5個到第9個字元cut -b5-9 file.txt千萬不要和cat命令混淆,這是兩個完全不同的命令

cat file.txt: 輸出文件內容到標准輸出設備(屏幕)上

file somefile: 得到文件類型

read var: 提示用戶輸入,並將輸入賦值給變數

sort file.txt: 對file.txt文件中的行進行排序

uniq: 刪除文本文件中出現的行列比如: sort file.txt | uniq

expr: 進行數學運算Example: add 2 and 3expr 2 "+" 3

find: 搜索文件比如:根據文件名搜索find . -name filename -print

tee: 將數據輸出到標准輸出設備(屏幕) 和文件比如:somecommand | tee outfile

basename file: 返回不包含路徑的文件名比如: basename /bin/tux將返回 tux

dirname file: 返迴文件所在路徑比如:dirname /bin/tux將返回 /bin

head file: 列印文本文件開頭幾行

tail file : 列印文本文件末尾幾行

sed: Sed是一個基本的查找替換程序。可以從標准輸入(比如命令管道)讀入文本,並將結果輸出到標准輸出(屏幕)。該命令採用正則表達式(見參考)進行搜索。不要和shell中的通配符相混淆。比如:將linuxfocus 替換為 LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file

awk: awk 用來從文本文件中提取欄位。預設地,欄位分割符是空格,可以使用-F指定其他分割符。cat file.txt | awk -F, '{print $1 "," $3 }'這里我們使用,作為欄位分割符,同時列印第一個和第三個欄位。如果該文件內容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA命令輸出結果為:Adam Bor, IndiaKerry Miller, USA

2) 概念: 管道, 重定向和 backtick

這些不是系統命令,但是他們真的很重要。

管道 (|) 將一個命令的輸出作為另外一個命令的輸入。
grep "hello" file.txt | wc -l
在file.txt中搜索包含有地hello地的行並計算其行數。
在這里grep命令的輸出作為wc命令的輸入。當然您可以使用多個命令。

重定向:將命令的結果輸出到文件,而不是標准輸出(屏幕)。
> 寫入文件並覆蓋舊文件
>> 加到文件的尾部,保留舊文件內容。

反短斜線
使用反短斜線可以將一個命令的輸出作為另外一個命令的一個命令行參數。
命令:
find . -mtime -1 -type f -print
用來查找過去24小時(-mtime –2則表示過去48小時)內修改過的文件。如果您想將所有查找到的文件打一個包,則可以使用以下腳本:
#!/bin/sh
# The ticks are backticks (`) not normal quotes ('):
tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`

3) 流程式控制制

"if" 表達式 如果條件為真則執行then後面的部分:
if ....; then
....
elif ....; then
....
else
....
fi
大多數情況下,可以使用測試命令來對條件進行測試。比如可以比較字元串、判斷文件是否存在及是否可讀等等…
通常用" [ ] "來表示條件測試。注意這里的空格很重要。要確保方括弧的空格。
[ -f "somefile" ] :判斷是否是一個文件
[ -x "/bin/ls" ] :判斷/bin/ls是否存在並有可執行許可權
[ -n "$var" ] :判斷$var變數是否有值
[ "$a" = "$b" ] :判斷$a和$b是否相等

執行man test可以查看所有測試表達式可以比較和判斷的類型。
直接執行以下腳本:
#!/bin/sh
if [ "$SHELL" = "/bin/bash" ]; then
echo "your login shell is the bash (bourne again shell)"
else
echo "your login shell is not bash but $SHELL"
fi
變數$SHELL包含了登錄shell的名稱,我們和/bin/bash進行了比較。

快捷操作符

熟悉C語言的朋友可能會很喜歡下面的表達式:
[ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"
這里 && 就是一個快捷操作符,如果左邊的表達式為真則執行右邊的語句。您也可以認為是邏輯運算中的與操作。上例中表示如果/etc/shadow文件存在則列印地 This computer uses shadow passwors地。同樣或操作(||)在shell編程中也是可用的。這里有個例子:
#!/bin/sh
mailfolder=/var/spool/mail/james
[ -r "$mailfolder" ]' '{ echo "Can not read $mailfolder" ; exit 1; }
echo "$mailfolder has mail from:"
grep "^From " $mailfolder
該腳本首先判斷mailfolder是否可讀。如果可讀則列印該文件中的"From" 一行。如果不可讀則或操作生效,列印錯誤信息後腳本退出。這里有個問題,那就是我們必須有兩個命令:
-列印錯誤信息
-退出程序
我們使用花括弧以匿名函數的形式將兩個命令放到一起作為一個命令使用。一般函數將在下文提及。
不用與和或操作符,我們也可以用if表達式作任何事情,但是使用與或操作符會更便利很多。

case表達式可以用來匹配一個給定的字元串,而不是數字。
case ... in
...) do something here ;;
esac
讓我們看一個例子。 file命令可以辨別出一個給定文件的文件類型,比如:
file lf.gz
這將返回:
lf.gz: gzip compressed data, deflated, original filename,
last modified: Mon Aug 27 23:09:18 2001, os: Unix
我們利用這一點寫了一個叫做smartzip的腳本,該腳本可以自動解壓bzip2, gzip 和zip 類型的壓縮文件:
#!/bin/sh
ftype=`file "$1"`
case "$ftype" in
"$1: Zip archive"*)
unzip "$1" ;;
"$1: gzip compressed"*)
gunzip "$1" ;;
"$1: bzip2 compressed"*)
bunzip2 "$1" ;;
*) error "File $1 can not be uncompressed with smartzip";;
esac

您可能注意到我們在這里使用了一個特殊的變數$1。該變數包含了傳遞給該程序的第一個參數值。也就是說,當我們運行:
smartzip articles.zip
$1 就是字元串 articles.zip

select 表達式是一種bash的擴展應用,尤其擅長於互動式使用。用戶可以從一組不同的值中進行選擇。
select var in ... ; do
break
done
.... now $var can be used ....
下面是一個例子:
#!/bin/sh
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
break
done
echo "You have selected $var"
下面是該腳本運行的結果:
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux

您也可以在shell中使用如下的loop表達式:
while ...; do
....
done

while-loop 將運行直到表達式測試為真。will run while the expression that we test for is true. 關鍵字"break" 用來跳出循環。而關鍵字地continue地用來不執行餘下的部分而直接跳到下一個循環。

for-loop表達式查看一個字元串列表 (字元串用空格分隔) 然後將其賦給一個變數:
for var in ....; do
....
done

在下面的例子中,將分別列印ABC到屏幕上:
#!/bin/sh
for var in A B C ; do
echo "var is $var"
done

下面是一個更為有用的腳本showrpm,其功能是列印一些RPM包的統計信息:
#!/bin/sh
# list a content summary of a number of RPM packages
# USAGE: showrpm rpmfile1 rpmfile2 ...
# EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
for rpmpackage in $*; do
if [ -r "$rpmpackage" ];then
echo "=============== $rpmpackage =============="
rpm -qi -p $rpmpackage
else
echo "ERROR: cannot read file $rpmpackage"
fi
done

這里出現了第二個特殊的變數$*,該變數包含了所有輸入的命令行參數值。如果您運行showrpm openssh.rpm w3m.rpm webgrep.rpm
此時 $* 包含了 3 個字元串,即openssh.rpm, w3m.rpm and webgrep.rpm.

引號
在向程序傳遞任何參數之前,程序會擴展通配符和變數。這里所謂擴展的意思是程序會把通配符(比如*)替換成合適的文件名,它變數替換成變數值。為了防止程序作這種替換,您可以使用引號:讓我們來看一個例子,假設在當前目錄下有一些文件,兩個jpg文件, mail.jpg 和tux.jpg。

#!/bin/sh
echo *.jpg
這將列印出"mail.jpg tux.jpg"的結果。
引號 (單引號和雙引號) 將防止這種通配符擴展:
#!/bin/sh
echo "*.jpg"
echo '*.jpg'
這將列印"*.jpg" 兩次。
單引號更嚴格一些。它可以防止任何變數擴展。雙引號可以防止通配符擴展但允許變數擴展。
#!/bin/sh
echo $SHELL
echo "$SHELL"
echo '$SHELL'

運行結果為:
/bin/bash
/bin/bash
$SHELL

最後,還有一種防止這種擴展的方法,那就是使用轉義字元——反斜桿:
echo *.jpg
echo $SHELL
這將輸出:
*.jpg
$SHELL
Here documents

當要將幾行文字傳遞給一個命令時,here documents(譯者註:目前還沒有見到過對該詞適合的翻譯)一種不錯的方法。對每個腳本寫一段幫助性的文字是很有用的,此時如果我們四有那個here documents就不必用echo函數一行行輸出。 一個 "Here document" 以 << 開頭,後面接上一個字元串,這個字元串還必須出現在here document的末尾。下面是一個例子,在該例子中,我們對多個文件進行重命名,並且使用here documents列印幫助:

#!/bin/sh
# we have less than 3 arguments. Print the help text:
if [ $# -lt 3 ] ; then
cat <<HELP
ren -- renames a number of files using sed regular expressions

USAGE: ren 'regexp' 'replacement' files...

EXAMPLE: rename all *.HTM files in *.html:
ren 'HTM$' 'html' *.HTM

HELP
exit 0
fi
OLD="$1"
NEW="$2"
# The shift command removes one argument from the list of
# command line arguments.
shift
shift
# $* contains now all the files:
for file in $*; do
if [ -f "$file" ] ; then
newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`
if [ -f "$newfile" ]; then
echo "ERROR: $newfile exists already"
else
echo "renaming $file to $newfile ..."
mv "$file" "$newfile"
fi
fi
done

這是一個復雜一些的例子。讓我們詳細討論一下。第一個if表達式判斷輸入命令行參數是否小於3個 (特殊變數$# 表示包含參數的個數) 。如果輸入參數小於3個,則將幫助文字傳遞給cat命令,然後由cat命令將其列印在屏幕上。列印幫助文字後程序退出。 如果輸入參數等於或大於3個,我們就將第一個參數賦值給變數OLD,第二個參數賦值給變數NEW。下一步,我們使用shift命令將第一個和第二個參數從參數列表中刪除,這樣原來的第三個參數就成為參數列表$*的第一個參數。然後我們開始循環,命令行參數列表被一個接一個地被賦值給變數$file。接著我們判斷該文件是否存在,如果存在則通過sed命令搜索和替換來產生新的文件名。然後將反短斜線內命令結果賦值給newfile。這樣我們就達到了我們的目的:得到了舊文件名和新文件名。然後使用mv命令進行重命名。

函數

如果您寫了一些稍微復雜一些的程序,您就會發現在程序中可能在幾個地方使用了相同的代碼,並且您也會發現,如果我們使用了函數,會方便很多。一個函數是這個樣子的:
functionname()
{
# inside the body $1 is the first argument given to the function
# $2 the second ...
body
}
您需要在每個程序的開始對函數進行聲明。

下面是一個叫做xtitlebar的腳本,使用這個腳本您可以改變終端窗口的名稱。這里使用了一個叫做help的函數。正如您可以看到的那樣,這個定義的函數被使用了兩次。
#!/bin/sh
# vim: set sw=4 ts=4 et:

help()
{
cat <<HELP
xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole

USAGE: xtitlebar [-h] "string_for_titelbar"

OPTIONS: -h help text

EXAMPLE: xtitlebar "cvs"

HELP
exit 0
}

# in case of error or if -h is given we call the function help:
[ -z "$1" ] && help
[ "$1" = "-h" ] && help

# send the escape sequence to change the xterm titelbar:
echo -e "33]0;$107"
#

在腳本中提供幫助是一種很好的編程習慣,這樣方便其他用戶(和您)使用和理解腳本。

命令行參數

我們已經見過$* 和 $1, $2 ... $9 等特殊變數,這些特殊變數包含了用戶從命令行輸入的參數。迄今為止,我們僅僅了解了一些簡單的命令行語法(比如一些強制性的參數和查看幫助的-h選項)。但是在編寫更復雜的程序時,您可能會發現您需要更多的自定義的選項。通常的慣例是在所有可選的參數之前加一個減號,後面再加上參數值 (比如文件名)。

有好多方法可以實現對輸入參數的分析,但是下面的使用case表達式的例子無遺是一個不錯的方法。
#!/bin/sh
help()
{
cat <<HELP
This is a generic command line parser demo.
USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2
HELP
exit 0
}

while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;; # function help is called
-f) opt_f=1;shift 1;; # variable opt_f is set
-l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
--) shift;break;; # end of options
-*) echo "error: no such option $1. -h for help";exit 1;;
*) break;;
esac
done

echo "opt_f is $opt_f"
echo "opt_l is $opt_l"
echo "first arg is $1"
echo "2nd arg is $2"

您可以這樣運行該腳本:
cmdparser -l hello -f -- -somefile1 somefile2

返回的結果是:
opt_f is 1
opt_l is hello
first arg is -somefile1
2nd arg is somefile2

這個腳本是如何工作的呢看腳本首先在所有輸入命令行參數中進行循環,將輸入參數與case表達式進行比較,如果匹配則設置一個變數並且移除該參數。根據unix系統的慣例,首先輸入的應該是包含減號的參數。

實例

一般編程步驟

現在我們來討論編寫一個腳本的一般步驟。任何優秀的腳本都應該具有幫助和輸入參數。並且寫一個偽腳本(framework.sh),該腳本包含了大多數腳本都需要的框架結構,是一個非常不錯的主意。這時候,在寫一個新的腳本時我們只需要執行一下命令:
cp framework.sh myscript
然後再插入自己的函數。

讓我們再看兩個例子:

二進制到十進制的轉換

腳本 b2d 將二進制數 (比如 1101) 轉換為相應的十進制數。這也是一個用expr命令進行數學運算的例子:
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
cat <<HELP
b2h -- convert binary to decimal

USAGE: b2h [-h] binarynum

OPTIONS: -h help text

EXAMPLE: b2h 111010
will return 58
HELP
exit 0
}

error()
{
# print an error and exit
echo "$1"
exit 1
}

lastchar()
{
# return the last character of a string in $rval
if [ -z "$1" ]; then
# empty string
rval=""
return
fi
# wc puts some space behind the output this is why we need sed:
numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
# now cut out the last char
rval=`echo -n "$1" | cut -b $numofchar`
}

chop()
{
# remove the last character in string and return it in $rval
if [ -z "$1" ]; then
# empty string
rval=""
return
fi
# wc puts some space behind the output this is why we need sed:
numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
if [ "$numofchar" = "1" ]; then
# only one char in string
rval=""
return
fi
numofcharminus1=`expr $numofchar "-" 1`
# now cut all but the last char:
rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`
}

while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;; # function help is called
--) shift;break;; # end of options
-*) error "error: no such option $1. -h for help";;
*) break;;
esac
done

# The main program
sum=0
weight=1
# one arg must be given:
[ -z "$1" ] && help
binnum="$1"
binnumorig="$1"

while [ -n "$binnum" ]; do
lastchar "$binnum"
if [ "$rval" = "1" ]; then
sum=`expr "$weight" "+" "$sum"`
fi
# remove the last position in $binnum
chop "$binnum"
binnum="$rval"
weight=`expr "$weight" "*" 2`
done

echo "binary $binnumorig is decimal $sum"
#
該腳本使用的演算法是利用十進制和二進制數權值 (1,2,4,8,16,..),比如二進制"10"可以這樣轉換成十進制:
0 * 1 + 1 * 2 = 2
為了得到單個的二進制數我們是用了lastchar 函數。該函數使用wc –c計算字元個數,然後使用cut命令取出末尾一個字元。Chop函數的功能則是移除最後一個字元。

文件循環程序
或許您是想將所有發出的郵件保存到一個文件中的人們中的一員,但是在過了幾個月以後,這個文件可能會變得很大以至於使對該文件的訪問速度變慢。下面的腳本rotatefile 可以解決這個問題。這個腳本可以重命名郵件保存文件(假設為outmail)為outmail.1,而對於outmail.1就變成了outmail.2 等等等等...
#!/bin/sh
# vim: set sw=4 ts=4 et:
ver="0.1"
help()
{
cat <<HELP
rotatefile -- rotate the file name

USAGE: rotatefile [-h] filename

OPTIONS: -h help text

EXAMPLE: rotatefile out
This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1
and create an empty out-file

The max number is 10

version $ver
HELP
exit 0
}

error()
{
echo "$1"
exit 1
}
while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;;
--) break;;
-*) echo "error: no such option $1. -h for help";exit 1;;
*) break;;
esac
done

# input check:
if [ -z "$1" ] ; then
error "ERROR: you must specify a file, use -h for help"
fi
filen="$1"
# rename any .1 , .2 etc file:
for n in 9 8 7 6 5 4 3 2 1; do
if [ -f "$filen.$n" ]; then
p=`expr $n + 1`
echo "mv $filen.$n $filen.$p"
mv $filen.$n $filen.$p
fi
done
# rename the original file:
if [ -f "$filen" ]; then
echo "mv $filen $filen.1"
mv $filen $filen.1
fi
echo touch $filen
touch $filen

這個腳本是如何工作的呢看在檢測用戶提供了一個文件名以後,我們進行一個9到1的循環。文件9被命名為10,文件8重命名為9等等。循環完成之後,我們將原始文件命名為文件1同時建立一個與原始文件同名的空文件。
調試
最簡單的調試命令當然是使用echo命令。您可以使用echo在任何懷疑出錯的地方列印任何變數值。這也是絕大多數的shell程序員要花費80%的時間來調試程序的原因。Shell程序的好處在於不需要重新編譯,插入一個echo命令也不需要多少時間。

shell也有一個真實的調試模式。如果在腳本"strangescript" 中有錯誤,您可以這樣來進行調試:
sh -x strangescript
這將執行該腳本並顯示所有變數的值。
shell還有一個不需要執行腳本只是檢查語法的模式。可以這樣使用:
sh -n your_script
這將返回所有語法錯誤。

10. 高手幫忙推薦幾本學習shell的經典書籍

新手,我不建議看:高級Bash shell腳本編程指南
有一定shell的基礎,最好是能獨立完成一些簡單腳本後,
了解一些sed,awk知識在看這本書比較好。
我推薦新手先看:
實戰LINUX+SHELL編程與伺服器管理

然後在看上邊那本高級Bash shell腳本編程指南。
shell十三問確實不錯,這個推薦的說。
linuxsir的shell腳本賞析也可以做為參考。
最重要的還是多寫多練,根據不同的要求來寫。光看不練沒有效果。

熱點內容
macps緩存 發布:2024-04-28 08:03:26 瀏覽:536
騰訊雲伺服器銷售好做嗎 發布:2024-04-28 08:03:23 瀏覽:585
編程的碼 發布:2024-04-28 08:02:41 瀏覽:545
c封裝資料庫 發布:2024-04-28 07:59:27 瀏覽:682
CRT存儲 發布:2024-04-28 07:57:42 瀏覽:136
硬閾值演算法 發布:2024-04-28 07:52:31 瀏覽:869
iphone存儲空間自動 發布:2024-04-28 07:40:11 瀏覽:953
培訓php還是java 發布:2024-04-28 07:10:49 瀏覽:919
dal數據訪問 發布:2024-04-28 07:09:00 瀏覽:522
python判斷伺服器是內網地址 發布:2024-04-28 07:07:17 瀏覽:782