BASH (Bourne Again Shell) 是 GNU 開發的 Shell (外殼),是以由 Steve Bourne 開發的 Shell 為名,開發的目的,是希望借 BASH 代替一般商業化的 Shell。 Shell 的意念在 UNIX Version 7 時已經出現,其版本是 Bourne Shell ,也就是 sh。

後來,由 Bill Joy (名字很熟識吧?他就是 vi 的作者,亦是 BSD 早期開發的重要人物之一) 開發的 C Shell 更受廣泛使用,因為 C Shell 的語法很像 C,管理員只需懂得 C 程式就可以簡單使用 C Shell。對於建立 GNU 系統,撰寫 Shell 外殼是有必要的,而 BASH 是由 Brian Fox (GNU 出名的人物) 撰寫,並由 Chet Ramey 所維持,現時最新版本為 2.04。

現在,絕大多數的 Linux distribution 預設都使用 BASH,而在其它系統像 OpenBSD 及 FreeBSD 等都使用傳統的 csh (C Shell) 或是 ksh (Korn Shell)。而筆者今次介紹的是 BASH,集中在 bash 上的程式 (即 shell script) 寫作,而 bash 環境的應用只會提及而不深入講解,因為撰寫 shell script 對管理上有很大幫助。

第一個的 shell script

在很多情況上系統都會使用 shell script,例如 /etc/rc.d/rc.local、.bash_login 等檔案,甚至定時檢查與 ISP 的連線等都可以使用 shell script 的幫忙。請看例子一,'echo' 就是把字句或變數列印出來,在 bash 的編程中,以$開頭的就是變數,相信有使用 Perl 的朋友都看得懂吧!例子一所做的就是要打印該句出來:

例子一 (test-1.sh):

#!/bin/bash
Var1="How are you today ?"
echo $Var1

首先請留意一點,在 test-1.sh 的第一行,筆者把之設為交給 /bin/bash 執行,而不是 /bin/sh,原因可能部份 Unix 系統中的 /bin/sh 並不是 bash,這樣執行可能發生問題,所以您還是檢查一下,如果 /bin/sh 是連到 /bin/bash 的 symbolic link 就兩者都可以使用。

在 bash 中的變數是大少寫敏感的,即是說 $Var 不等同 $VAR,這點很多的程式語言都一樣。把 test-1.sh 儲存成檔案後,執行的方法有兩種,您可以直接使用 bash 來執行這個檔案,或是把檔案設為可執行(executable):

例子一執行方法一:

shell@www :~# sh test-1.sh
How are you today ?

例子一執行方法二:

shell@www :~# chmod 0700 test-1.sh
shell@www :~# ./test-1.sh
How are you today ?

兩種方法都可行,在不同情況上,您可以選擇哪個方法較好。

Bash 的編程支援參數(parameters)。在 C 的編程上,您可使用 argc 及 argv 來找尋輸入至程式的參數;而在 bash 上,$# 就是 argc,是顯示參數的數目;而 $1、$2、$3 等等就是參數值,$@ 是所有參數的陣列(Array)。請參考例子二,它示範了這幾個內置變數的功能:

例子二 (test-2.sh):

#!/bin/bash
echo "Total Parameters of $0 : $#"
echo "They are : $@";
echo "First parameter is : $1"

例子二執行方法:

shell@www :~# chmod 700 test-2.sh
shell@www :~# ./test-2.sh 1st 2nd 3rd
Total Parameters of ./test.sh : 3
They are : 1st 2nd 3rd
First parameter is : 1st

在例子三中,我們嘗試使用 shell script 執行外部的程式。它是一個在某檔案中找尋字串的 shell script:

例子三 (test-3.sh):

#!/bin/bash
echo "Now searching file : ${1##/*/}"
grep $2 $1

例子三執行方法:

shell@www :~# ./test-3.sh /etc/services ftp
Now searching file : services
ftp-data    20/tcp
ftp     21/tcp
tftp        69/udp
sftp        115/tcp
bftp        152/tcp

參數一是檔案位置,而參數二就是字串。在這個只有兩行的 shell script中,當然沒有甚麼特別的功能,目的只是顯示在 shell script 中如何執行外部指令。或者我們可以使例子變得複雜一點,當然,請繼續看下去。例子中的 ${1##/*/} 就是把 /etc/ 等刪去,請參考表一。

表一:

變數 結果
${path} /usr/local/bin/emacs
${path#/*/} local/bin/emacs
${path##/*/} emacs
${path%/*} /usr/local/bin
${path:15} emacs
${path:10:4} /bin

此外,在 bash 的變數中,還有些能即時回傳測試,例如測試變數是否存在,如果沒有,會做別的事情,這些在撰寫功能多的 shell script 時很常用,請參考表二(這裡先假設 $Var1 的值是 "Yes",而 $Var2 沒有定義):

表二:

用法 結果
${Var1:-No} 印出 "No"
${Var2:-Yes} Var2 沒有變數值,印出 "Yes" 字串
${Var1:=No} 印出 "Yes" 字串
${Var2:=Yes} Var2 現在變數值為 "Yes"
${Var1:?No} 印出 "Yes" 字串
${Var2:?Yes} 印出 "Var2: Yes" 字句

順帶一提,如果在Shell的環境下直接輸入 echo -e ${PATH//:/' '},印出的就是在 $PATH 變數內的值,而 /:/' ' 會把分隔 $PATH 的 ':'字串變為 newline 印出。

編者註︰要清楚以上所有變數的替換,請看 bash 的 manpage 裡有關 "Parameter Expansion" 的一段。

if... then... else... fi
語法:
if <條件 1>; then
執行指令
elif <條件 2>; then
執行指令
else
執行指令
if

在例子四中,我們加入了 if 的條件控制,令 shell script 功能變得好一點;或許在看例子前參考表三,表三是 bash 內可使用的比較字元及測試字元:

表三:

用法 解釋
str1 = str2
比較字串變數是否相同
str1 != str2
比較字串變數是否不同
str1 < str2
比較 str1 是否大於 str2
str1 > str2
比較 str1 是否小於 str2
-n str1
檢查 str1 是否有定義
-z str1
檢查 str1 是否沒有定義

例子四 (test-4.sh):

#!/bin/bash
if [ -z "$1" ]; then
echo "Usage : test-4.sh [File] [Keyword]"
exit 1;
fi
echo "Now searching file : ${1##/*/}"
grep $2 $1

我們使用了 -z 檢查 $1,即是第一個參數,如果沒有輸入參數,程式會回傳使用的方法,然後結束程式執行;當然我們還可以加入其它更多的檢查,使這個程式變得更強。在例子五中,我們加入對檔案狀態的檢查。

例子五 (test-5.sh):

#!/bin/bash
if [ $# != "2" ]; then
echo "Usage : test-5.sh [File] [Keyword]"
exit 1;
fi
if [ ! -r "$1" ]; then
echo "No such files or permission denied !"
fi
echo "Now searching file : ${1##/*/}"
grep $2 $1

在例子五中加入了一段 if 的條件,"!"的意思是 NOT,即是檢查 $1 是否不能讀 (! -r),就像是 Slackware 的 rc 檔案會檢驗在 /etc/rc.d/ 內有沒有 rc.* 的檔案,並且檢查是否可以執行,有關這些檢查的運算子,可以參考表四:

表四:

選項 解釋
-d 檢查是否目錄
-e 檢查是否檔案
-f 檢查是否檔案(非特別檔案如 /dev/*)
-r 檢查是否可讀
-s 檢查檔案是否存在及內容不是空的
-w 檢查是否可寫
-x 檢查是否可執行
-O 檢查 Owner 是執行者
-G 檢查 Group 是執行者的群組

編者註︰若想知更多,請參考 test 的 manpage。

例子六 (test-6.sh):

#!/bin/bash
filename="test-6.sh"
echo -n "File owner of $filename is "
if [ -O $filename ]; then
echo "you !"
else
echo "not you !"
fi

例子六是另一個有關檢查檔案的例子,與前例差不多,唯獨要留意的就是在 echo 中的 -n 參數,-n 的意思就是令 echo 不會在句尾加入 ,這樣,在印出字句時,便不會開新的一行。

for ... in ...; do ...; done

語法:

for x in list
do
執行指令
done

for loop 在某些情況很常用,例如要在很多的目錄工作時。請參考例子七;它是一個很簡單的 shell script,作用只是在數個目錄內找尋符合字串的檔案名稱:

例子七 (test-7.sh):

#!/bin/bash
IFS=:
PATH=/usr/bin:/usr/sbin:/sbin:/bin:/usr/local/sbin:/usr/local/bin
if [ -z "$1" ]; then
echo "Usage : test-7.sh [Keyword]"
exit 1
fi
for dir in $PATH
do
echo "Working in $dir ..."
ls -al $dir | grep $1
done
exit 0

例子七執行方法︰

shell@www :~# ./test-7.sh login
Working in /usr/bin ...
-r-sr-xr-x   1 root  bin       20480 Dec 24 13:29 login
-r-sr-xr-x   1 root  bin       20480 Dec 24 13:18 rlogin
-r-sr-xr-x   2 root  bin      184320 Feb  1 10:13 slogin
Working in /usr/sbin ...
-r-sr-xr-x   1 root  bin       12288 Dec 24 13:19 sliplogin
Working in /sbin ...
-r-xr-xr-x   1 root  bin        20480 Dec 24 13:18 nologin
Working in /bin ...
Working in /usr/local/sbin ...
Working in /usr/local/bin ...
case... in ... esac

語法:

case <變數> in
pattern 1 )
執行指令 ;;
pattern 2 )
執行指令 ;;
esac

case 就像是在 C 語言內的 select 一樣,其流程就是在 [expression] 中與各 [pattern] 作配對,如果找尋得到便會執行 [pattern] 內的語句;使用 case 的最常見例子就是 RedHat 等的 init script,當輸入 '/etc/rc.d/init.d/network restart' 時,程式會因應 'start'、'stop'、'restart' 等字眼而執行不同的語句。

在例子八中就是一個使用 case 來控制網絡介面卡的 shell script。

例子八 (test-8.sh):

#!/bin/bash
IP=202.181.234.40
Eth=eth0
case "$1" in
up )
ifconfig $Eth up ;;
down )
ifconfig $Eth down ;;
test )
ping $IP ;;
* )
echo "Usage { up | down | test }"
echo
esac
exit 0
while 與 until
while 語法:
while <條件>
do
<語句>
done

在某些工作上,您會需要使用一個不斷的迴路以檢查變數的變化。如果您有使用別的程式語言的經驗,相信 while 對您來說絕不陌生;請參考例子九,它使用到了新的功能,就是 getopts,getopts 與 C 程式中的 getopts 有相同功能,用以取得程式的參數。

例子九 (test-9.sh):

#!/bin/bash
while getopts "a:b:c" opt; do
case $opt in
a) echo -n "Argv is -a ! " ;;
b) echo -n "Argv is -b ! " ;;
c) echo -n "Argv is -c ! " ;;
*) echo "Usage : $0 -[abc] text"
exit 1;;
esac
done
echo $2

例子九執行方法:

shell@www :~# ./test-9.sh -a "The sting here"
rgv is -a ! The string here

當然,例子九並不是一個很好的程式,只是想介紹 while 怎樣與 getopts 一併使用。while 與 getopts 一併使用的情況並不罕見。

until 語法:
until <條件>; do
<語句>
done

until 與 while 的用法很相似,所以筆者亦不加以介紹,但是一般 until 會用在如檢查指令執行的狀態上。

Function

在文章開端時,筆者提及到在 bash 內有 function 功能,也就是子程序,在一般程式寫作時很常到用,但是在撰寫 shell script 時會較少;使用子程序有很多好處,例如在程式比較複雜時,或是某些語句需要重複,這時候子程序是有必要的。

語法:

function name
{
<語句>
}
或 是
name() {
<語句>
}

'name' 就是子程序的名稱,而執行的方法是直接呼叫 'name',任何輸入至子程序的參數可以加在 'name' 的後面,如:

#!/bin/bash
function test
{
echo "test..."
}
test

或者

#!/bin/bash
function test
{
echo "Argument is $1"
}
test abc

結語

其實在 bash 的程式設計中,還有很多的功能筆者並未介紹,希望下次有機會時再為大家介紹;如果您希望學得更多有關 shell script 的程式設計時,您可以參考 O'Reilly 出版的Learning the Bash shell 或是參考系統上原有的 shell script 和 manpage,當中您會學到其它功能的使用。

文: Shell Hung shellhung@linux.org.hk

shell script - BASH相关推荐

  1. 小白linux bash 学习二 shell Script

    之前说了一些脚本和变量,其实都是为了现在讲shell Script也就是shell脚本做铺垫.按照我自己的理解来讲.其实shell 脚本就是一些基础的语法和命令的总和, 所以要学shell 脚本,那么 ...

  2. linux bash语法检查,ShellCheck — Shell Script 语法检查工具

    如果在使用一些指令 (例如 rm) 不小心, ShellCheck 是一个 Shell Script 分析及除错工具, 之后要花很多时间修复, 可以在尝试执行 Shell Script 前先找出 Wa ...

  3. 「学习笔记-Linux」学习Shell Script

    学习Shell Script Table of Contents 1 什么是Shell Scipt 1.1 程序书写 1.2 程序执行 2 简单Shell练习 2.1 例1 接收用户输入 2.2 例2 ...

  4. Linux08--Shell程序设计03 shell script

    第一个Shell脚本--HelloWorld [root@localhost ~]# vi sh01.sh #!/bin/bash #!表明使用哪种shell # this is my first s ...

  5. 那些年我们一起追过的Shell Script

    原本这是自己在几个月前为公司的一个分享活动写的一个投影片,今天趁大脑负荷比较小,把这个话题拿到blog上面来分享一下.从知道shell算起至今也就几个年头而已,如今勉强算是入门了.对某一个新事物的掌握 ...

  6. Linux shell script 的语法汇总

    2019独角兽企业重金招聘Python工程师标准>>> 条件判断式 if判断式 if [ 条件判断式1 ]:then执行动作 elif [ 条件判断式2 ]:then执行动作 els ...

  7. linux-basic(13)学习shell script

    [13.1]什么是shell script? 1)shell script 是利用 shell 的功能所写的一个『程序 (program)』,这个程序是使用纯文字档,将一些 shell 的语法与命令( ...

  8. linux 脚本批量删除,Linux Shell使用Bash脚本批量删除文件

    PHP每天生成一个存有系统要删除的临时文件的.out文件列表,由bash脚本逐行通过读取.out文件(每一行代表一个待删除的文件)挨个删除,代码如下(dl.sh): #!/bin/bash # She ...

  9. 好用的shell_Linux系统安全 | Linux中的Shell和Bash

    目录 shell shell script sh bash Dash tty.pty和pts 学安全的我们,经常会听到说获得某服务器的shell,就是指获得某个服务器的操作权限.我们学习linux时, ...

最新文章

  1. Python 3.10的几个好用的新特性
  2. python文件对象提供了3个读方法、分别是-python3基础之文件对象操作
  3. php根据时间段分组,php按月分组(时间戳)
  4. jps查看java进程以及pwdx通过pid查看进程所在位置
  5. LeetCode 1652. 拆炸弹(前缀和)
  6. centos7 oracle_Centos7主机名变成bogon的原因及解决方法
  7. 如何做到免驱打印_证卡打印机云打印方案
  8. python3哪个版本稳定-Python 3.9 发布稳定版本,八大特性学起来!
  9. oracle怎么查导入导出记录,Oracle实验记录——数据的导入和导出
  10. how-to-set-java_home-environment-variable-on-mac-os-x
  11. 苹果智能家居—HomeKit,带给您不一样的生活体验
  12. 电脑蓝屏后的文件数据怎么恢复?电脑蓝屏的原因有哪些
  13. mysql不停库全量备份,mysql全量备份数据
  14. 如何将Spotify音乐下载并保存为MP3
  15. 统计——假设检验与p值
  16. Android FFmpeg集成
  17. worldpress小工具自定义html,WorldPress Grid html代码设置浅析,代码非常简洁
  18. 机器指令、操作类型、寻址方式
  19. 订阅号和服务号有什么区别?哪种更好?企业该如何选择?
  20. 2022年,中国餐饮数字化进行到哪一步了?

热门文章

  1. #3234. 「POI2019 R1」Pomniejszenie
  2. C++的动态多态,Virtual关键字的作用
  3. JS异步加载及解决方式
  4. 2021年高压电工考试报名及高压电工考试总结
  5. 基于FPGA的一维卷积神经网络CNN的实现(三)训练网络搭建及参数导出(附代码)
  6. 啄木鸟,python讲座,源码_Part1
  7. PLC的功能及应用领域
  8. 浅谈汽车转向灯的具体拆装方法
  9. jQuery过滤选择器层次选择器表单选择器
  10. Unity-WebGL打包后不能输入中文