鸟哥的Linux私房菜_基础版_学习笔记9:第十三章 学习 Shell Scripts

13.1 什么是 Shell scripts

13.1.1 干嘛学习 shell scripts

13.1.2 第一支 script 的撰写与运行

在 shell script 的撰写中还需要用到底下的注意事项:

  1. 命令的运行是从上而下、从左而右的分析与运行;
  2. 命令的下达就如同第五章内提到的: 命令、选项与参数间的多个空白都会被忽略掉;
  3. 空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样视为空白键;
  4. 如果读取到一个 Enter 符号 (CR) ,就尝试开始运行该行 (或该串) 命令;
  5. 至於如果一行的内容太多,则可以使用『 \[Enter] 』来延伸至下一行;
  6. 『 # 』可做为注解!任何加在 # 后面的数据将全部被视为注解文字而被忽略!

假设你写的这个程序档名是 /home/dmtsai/shell.sh 好了,那如何运行这个文件?很简单,可以有底下几个方法:

  • 直接命令下达: shell.sh 文件必须要具备可读与可运行 (rx) 的权限,然后:

    • 绝对路径:使用 /home/dmtsai/shell.sh 来下达命令;
    • 相对路径:假设工作目录在 /home/dmtsai/ ,则使用 ./shell.sh 来运行
    • 变量『PATH』功能:将 shell.sh 放在 PATH 指定的目录内,例如: ~/bin/
  • 撰写第一支 script

1、第一行 #!/bin/bash 在宣告这个 script 使用的 shell 名称:

必须要以『 #!/bin/bash 』来宣告这个文件内的语法使用
bash 的语法!

(在很多状况中,如果没有配置好这一行, 那么该程序很可能会无法运行)

2、程序内容的说明:

一般来说,
建议你一定要养成说明该 script 的:1. 内容与功能; 2. 版本资讯; 3. 作者与联络方式; 4. 建档日期;5. 历史纪录 等等。

3、主要环境变量的宣告:

建议务必要将一些重要的环境变量配置好,可以直接下达一些外部命令,而不必写绝对路径呢!

4、主要程序部分

5、运行成果告知 (定义回传值)

使用 exit 0 ,这代表离开 script 并且回传一个 0 给系统

接下来透过刚刚上头介绍的运行方法来运行看看结果吧!

[[email protected] scripts]# sh sh01.sh
Hello World !

另外,你也可以利用:『chmod a+x sh01.sh; ./sh01.sh』来运行这个 script 的呢!

13.2 简单的 shell script 练习

13.2.1 简单范例

  • 对谈式脚本:变量内容由使用者决定
[[email protected] scripts]# vi sh02.sh#!/bin/bash

read -p "Please input your first name: " firstname  # 提示使用者输入
read -p "Please input your last name:  " lastname   # 提示使用者输入
echo -e "\nYour full name is: $firstname $lastname" # 结果由萤幕输出
  • 随日期变化:利用 date 进行文件的创建
[[email protected] scripts]# vi sh03.sh#!/bin/bash

# 1. 让使用者输入文件名称,并取得 fileuser 这个变量;
echo -e "I will use ‘touch‘ command to create 3 files." # 纯粹显示资讯
read -p "Please input your filename: " fileuser         # 提示使用者输入# 2. 为了避免使用者随意按 Enter ,利用变量功能分析档名是否有配置?
filename=${fileuser:-"filename"}           # 开始判断有否配置档名# 3. 开始利用 date 命令来取得所需要的档名了;
date1=$(date --date=‘2 days ago‘ +%Y%m%d)  # 前两天的日期
date2=$(date --date=‘1 days ago‘ +%Y%m%d)  # 前一天的日期
date3=$(date +%Y%m%d)                      # 今天的日期
file1=${filename}${date1}                  # 底下三行在配置档名
file2=${filename}${date2}
file3=${filename}${date3}

# 4. 将档名创建吧!
touch "$file1"                             # 底下三行在创建文件
touch "$file2"
touch "$file3"

13.2.2 script 的运行方式差异 (source, sh script, ./script)

  • 利用直接运行的方式来运行 script
[[email protected] scripts]# echo $firstname $lastname
    <==确认了,这两个变量并不存在喔!
[[email protected] scripts]# sh sh02.sh
Please input your first name: VBird <==这个名字是鸟哥自己输入的
Please input your last name:  Tsai 

Your full name is: VBird Tsai      <==看吧!在 script 运行中,这两个变量有生效
[[email protected] scripts]# echo $firstname $lastname
    <==事实上,这两个变量在父程序的 bash 中还是不存在的!

图 2.2.1、sh02.sh 在子程序中运行

  • 利用 source 来运行脚本:在父程序中运行
[[email protected] scripts]# source sh02.sh
Please input your first name: VBird
Please input your last name:  Tsai

Your full name is: VBird Tsai
[[email protected] scripts]# echo $firstname $lastname
VBird Tsai  <==嘿嘿!有数据产生喔!

图 2.2.2、sh02.sh 在父程序中运行

13.3 善用判断式

13.3.1 利用 test 命令的测试功能

[[email protected] ~]# test -e /dmtsai
[[email protected] ~]# test -e /dmtsai && echo "exist" || echo "Not exist"
Not exist  <==结果显示不存在啊!
测试的标志 代表意义
1. 关於某个档名的『文件类型』判断,如 test -e filename 表示存在否
-e 该『档名』是否存在?(常用)
-f 该『档名』是否存在且为文件(file)?(常用)
-d 该『档名』是否存在且为目录(directory)?(常用)
-b 该『档名』是否存在且为一个 block device 装置?
-c 该『档名』是否存在且为一个 character device 装置?
-S 该『档名』是否存在且为一个 Socket 文件?
-p 该『档名』是否存在且为一个 FIFO (pipe) 文件?
-L 该『档名』是否存在且为一个连结档?
2. 关於文件的权限侦测,如 test -r filename 表示可读否 (但 root 权限常有例外)
-r 侦测该档名是否存在且具有『可读』的权限?
-w 侦测该档名是否存在且具有『可写』的权限?
-x 侦测该档名是否存在且具有『可运行』的权限?
-u 侦测该档名是否存在且具有『SUID』的属性?
-g 侦测该档名是否存在且具有『SGID』的属性?
-k 侦测该档名是否存在且具有『Sticky bit』的属性?
-s 侦测该档名是否存在且为『非空白文件』?
3. 两个文件之间的比较,如: test file1 -nt file2
-nt (newer than)判断 file1 是否比 file2 新
-ot (older than)判断 file1 是否比 file2 旧
-ef 判断 file1 与 file2 是否为同一文件,可用在判断 hard link 的判定上。 主要意义在判定,两个文件是否均指向同一个 inode 哩!
4. 关於两个整数之间的判定,例如 test n1 -eq n2
-eq 两数值相等 (equal)
-ne 两数值不等 (not equal)
-gt n1 大於 n2 (greater than)
-lt n1 小於 n2 (less than)
-ge n1 大於等於 n2 (greater than or equal)
-le n1 小於等於 n2 (less than or equal)
5. 判定字串的数据
test -z string 判定字串是否为 0 ?若 string 为空字串,则为 true
test -n string 判定字串是否非为 0 ?若 string 为空字串,则为 false。

注: -n 亦可省略

test str1 = str2 判定 str1 是否等於 str2 ,若相等,则回传 true
test str1 != str2 判定 str1 是否不等於 str2 ,若相等,则回传 false
6. 多重条件判定,例如: test -r filename -a -x filename
-a (and)两状况同时成立!例如 test -r file -a -x file,则 file 同时具有 r 与 x 权限时,才回传 true。
-o (or)两状况任何一个成立!例如 test -r file -o -x file,则 file 具有 r 或 x 权限时,就可回传 true。
! 反相状态,如 test ! -x file ,当 file 不具有 x 时,回传 true

13.3.2 利用判断符号 [ ]

如果我想要知道 $HOME 这个变量是否为空的,可以这样做:

[[email protected] ~]# [ -z "$HOME" ] ; echo $?

必须要注意中括号的两端需要有空白字节来分隔喔! 假设我空白键使用『□』符号来表示,那么,在这些地方你都需要有空白键:

[  "$HOME"  ==  "$MAIL"  ]
[□"$HOME"□==□"$MAIL"□]

所以说,你最好要注意:

  • 在中括号 [] 内的每个组件都需要有空白键来分隔;
  • 在中括号内的变量,最好都以双引号括号起来;
  • 在中括号内的常数,最好都以单或双引号括号起来。

为什么要这么麻烦啊?直接举例来说,假如我配置了 name="VBird Tsai" ,然后这样判定:

[[email protected] ~]# name="VBird Tsai"
[[email protected] ~]# [ $name == "VBird" ]
bash: [: too many arguments
[[email protected] scripts]# vi sh06.sh

read -p "Please input (Y/N): " yn
[ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK, continue" && exit 0
[ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh, interrupt!" && exit 0
echo "I don‘t know what your choice is" && exit 0

13.3.3 Shell script 的默认变量($0, $1...)

其实 script 针对参数已经有配置好一些变量名称了!对应如下:

/path/to/scriptname  opt1  opt2  opt3  opt4
       $0             $1    $2    $3    $4
  • $# :代表后接的参数『个数』,以上表为例这里显示为『 4 』;
  • [email protected] :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
  • $* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字节,默认为空白键,
    所以本例中代表『 "$1 $2 $3 $4" 』之意。
[[email protected] scripts]# vi sh07.sh

echo "The script name is        ==> $0"
echo "Total parameter number is ==> $#"
[ "$#" -lt 2 ] && echo "The number of parameter is less than 2.  Stop here." 	&& exit 0
echo "Your whole parameter is   ==> ‘[email protected]‘"
echo "The 1st parameter         ==> $1"
echo "The 2nd parameter         ==> $2"

运行结果如下:

[[email protected] scripts]# sh sh07.sh theone haha quot
The script name is        ==> sh07.sh            <==档名
Total parameter number is ==> 3                  <==果然有三个参数
Your whole parameter is   ==> ‘theone haha quot‘ <==参数的内容全部
The 1st parameter         ==> theone             <==第一个参数
The 2nd parameter         ==> haha               <==第二个参数
  • shift:造成参数变量号码偏移
[[email protected] scripts]# vi sh08.sh

echo "Total parameter number is ==> $#"
echo "Your whole parameter is   ==> ‘[email protected]‘"
shift   # 进行第一次『一个变量的 shift 』
echo "Total parameter number is ==> $#"
echo "Your whole parameter is   ==> ‘[email protected]‘"
shift 3 # 进行第二次『三个变量的 shift 』
echo "Total parameter number is ==> $#"
echo "Your whole parameter is   ==> ‘[email protected]‘"

这玩意的运行成果如下:

[[email protected] scripts]# sh sh08.sh one two three four five six <==给予六个参数
Total parameter number is ==> 6   <==最原始的参数变量情况
Your whole parameter is   ==> ‘one two three four five six‘
Total parameter number is ==> 5   <==第一次偏移,看底下发现第一个 one 不见了
Your whole parameter is   ==> ‘two three four five six‘
Total parameter number is ==> 2   <==第二次偏移掉三个,two three four 不见了
Your whole parameter is   ==> ‘five six‘

13.4 条件判断式

13.4.1 利用 if .... then

  • 单层、简单条件判断式
if [ 条件判断式 ]; then
	当条件判断式成立时,可以进行的命令工作内容;
fi   <==将 if 反过来写,就成为 fi 啦!结束 if 之意!
  • && 代表 AND ;
  • || 代表 or ;

现在我们来将 sh06.sh 这个脚本修改成为 if ... then 的样式来看看:

[[email protected] scripts]# cp sh06.sh sh06-2.sh  <==用改的比较快!
[[email protected] scripts]# vi sh06-2.sh

read -p "Please input (Y/N): " yn

if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
	echo "OK, continue"
	exit 0
fi
if [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
	echo "Oh, interrupt!"
	exit 0
fi
echo "I don‘t know what your choice is" && exit 0
  • 多重、复杂条件判断式
# 一个条件判断,分成功进行与失败进行 (else)
if [ 条件判断式 ]; then
	当条件判断式成立时,可以进行的命令工作内容;
else
	当条件判断式不成立时,可以进行的命令工作内容;
fi

如果考虑更复杂的情况,则可以使用这个语法:

# 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况运行
if [ 条件判断式一 ]; then
	当条件判断式一成立时,可以进行的命令工作内容;
elif [ 条件判断式二 ]; then
	当条件判断式二成立时,可以进行的命令工作内容;
else
	当条件判断式一与二均不成立时,可以进行的命令工作内容;
fi

好!我们来将 sh06-2.sh 改写成这样:

[[email protected] scripts]# cp sh06-2.sh sh06-3.sh
[[email protected] scripts]# vi sh06-3.sh

read -p "Please input (Y/N): " yn

if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
	echo "OK, continue"
elif [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
	echo "Oh, interrupt!"
else
	echo "I don‘t know what your choice is"
fi

我们在第十一章已经学会了 grep 这个好用的玩意儿,那么多学一个叫做 netstat 的命令,这个命令可以查询到目前主机有开启的网络服务端口 (service ports), 相关的功能我们会在服务器架设篇继续介绍,这里你只要知道,我可以利用『 netstat
-tuln 』来取得目前主机有启动的服务, 而且取得的资讯有点像这样:

[[email protected] ~]# netstat -tuln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address     Foreign Address   State
tcp        0      0 0.0.0.0:111       0.0.0.0:*         LISTEN
tcp        0      0 127.0.0.1:631     0.0.0.0:*         LISTEN
tcp        0      0 127.0.0.1:25      0.0.0.0:*         LISTEN
tcp        0      0 :::22             :::*              LISTEN
udp        0      0 0.0.0.0:111       0.0.0.0:*
udp        0      0 0.0.0.0:631       0.0.0.0:*
#封包格式           本地IP:端口       远程IP:端口       是否监听

上面的重点是『Local Address (本地主机的IP与端口对应)』那个栏位,他代表的是本机所启动的网络服务! IP的部分说明的是该服务位於那个介面上,若为 127.0.0.1 则是仅针对本机开放,若是 0.0.0.0 或 ::: 则代表对整个 Internet 开放 (更多资讯请参考服务器架设篇的介绍)。 每个端口 (port) 都有其特定的网络服务,几个常见的 port 与相关网络服务的关系是:

  • 80: WWW
  • 22: ssh
  • 21: ftp
  • 25: mail
  • 111: RPC(远程程序呼叫)
  • 631: CUPS(列印服务功能)

假设我的主机有兴趣要侦测的是比较常见的 port 21, 22, 25及 80 时,那我如何透过 netstat 去侦测我的主机是否有开启这四个主要的网络服务端口呢?由於每个服务的关键字都是接在冒号『 : 』后面, 所以可以藉由撷取类似『 :80 』来侦测的!那我就可以简单的这样去写这个程序喔:

[[email protected] scripts]# vi sh10.sh

# 1. 先作一些告知的动作而已~
echo "Now, I will detect your Linux server‘s services!"
echo -e "The www, ftp, ssh, and mail will be detect! \n"

# 2. 开始进行一些测试的工作,并且也输出一些资讯罗!
testing=$(netstat -tuln | grep ":80 ")   # 侦测看 port 80 在否?
if [ "$testing" != "" ]; then
	echo "WWW is running in your system."
fi
testing=$(netstat -tuln | grep ":22 ")   # 侦测看 port 22 在否?
if [ "$testing" != "" ]; then
	echo "SSH is running in your system."
fi
testing=$(netstat -tuln | grep ":21 ")   # 侦测看 port 21 在否?
if [ "$testing" != "" ]; then
	echo "FTP is running in your system."
fi
testing=$(netstat -tuln | grep ":25 ")   # 侦测看 port 25 在否?
if [ "$testing" != "" ]; then
	echo "Mail is running in your system."
fi

能不能写个脚本程序来跑,让使用者输入他的退伍日期,让你去帮他计算还有几天才退伍?

利用『 date --date="YYYYMMDD" +%s 』转成秒数后,接下来的动作就容易的多了!如果你已经写完了程序,对照底下的写法试看看:

[[email protected] scripts]# vi sh11.sh

# 1. 告知使用者这支程序的用途,并且告知应该如何输入日期格式?
echo "This program will try to calculate :"
echo "How many days before your demobilization date..."
read -p "Please input your demobilization date (YYYYMMDD ex>20090401): " date2

# 2. 测试一下,这个输入的内容是否正确?利用正规表示法罗~
date_d=$(echo $date2 |grep ‘[0-9]\{8\}‘)   # 看看是否有八个数字
if [ "$date_d" == "" ]; then
	echo "You input the wrong date format...."
	exit 1
fi

# 3. 开始计算日期罗~
declare -i date_dem=`date --date="$date2" +%s`    # 退伍日期秒数
declare -i date_now=`date +%s`                    # 现在日期秒数
declare -i date_total_s=$(($date_dem-$date_now))  # 剩余秒数统计
declare -i date_d=$(($date_total_s/60/60/24))     # 转为日数
if [ "$date_total_s" -lt "0" ]; then              # 判断是否已退伍
	echo "You had been demobilization before: " $((-1*$date_d)) " ago"
else
	declare -i date_h=$(($(($date_total_s-$date_d*60*60*24))/60/60))
	echo "You will demobilize after $date_d days and $date_h hours."
fi

13.4.2 利用 case ..... esac 判断

case  $变量名称 in   <==关键字为 case ,还有变量前有钱字号
  "第一个变量内容")   <==每个变量内容建议用双引号括起来,关键字则为小括号 )
	程序段
	;;            <==每个类别结尾使用两个连续的分号来处理!
  "第二个变量内容")
	程序段
	;;
  *)                  <==最后一个变量内容都会用 * 来代表所有其他值
	不包含第一个变量内容与第二个变量内容的其他程序运行段
	exit 1
	;;
esac                  <==最终的 case 结尾!『反过来写』思考一下!
[[email protected] scripts]# vi sh09-2.sh
case $1 in
  "hello")
	echo "Hello, how are you ?"
	;;
  "")
	echo "You MUST input parameters, ex> {$0 someword}"
	;;
  *)   # 其实就相当於万用字节,0~无穷多个任意字节之意!
	echo "Usage $0 {hello}"
	;;
esac

一般来说,使用『 case $变量 in 』这个语法中,当中的那个『 $变量 』大致有两种取得的方式:

  • 直接下达式:例如上面提到的,利用『 script.sh variable 』 的方式来直接给予 $1 这个变量的内容,这也是在 /etc/init.d 目录下大多数程序的设计方式。
  • 互动式:透过 read 这个命令来让使用者输入变量的内容。

这么说或许你的感受性还不高,好,我们直接写个程序来玩玩:让使用者能够输入 one, two, three , 并且将使用者的变量显示到萤幕上,如果不是 one, two, three 时,就告知使用者仅有这三种选择。

[[email protected] scripts]# vi sh12.sh

echo "This program will print your selection !"
# read -p "Input your choice: " choice # 暂时取消,可以替换!
# case $choice in                      # 暂时取消,可以替换!
case $1 in                             # 现在使用,可以用上面两行替换!
  "one")
	echo "Your choice is ONE"
	;;
  "two")
	echo "Your choice is TWO"
	;;
  "three")
	echo "Your choice is THREE"
	;;
  *)
	echo "Usage $0 {one|two|three}"
	;;
esac

13.4.3 利用 function 功能

function fname() {
	程序段
}

要注意的是,因为 shell script 的运行方式是由上而下,由左而右, 因此在 shell script 当中的 function 的配置一定要在程序的最前面, 这样才能够在运行时被找到可用的程序段喔!好~我们将 sh12.sh 改写一下,自订一个名为 printit 的函数来使用喔:

[[email protected] scripts]# vi sh12-2.sh

function printit(){
	echo -n "Your choice is "     # 加上 -n 可以不断行继续在同一行显示
}

echo "This program will print your selection !"
case $1 in
  "one")
	printit; echo $1 | tr ‘a-z‘ ‘A-Z‘  # 将参数做大小写转换!
	;;
  "two")
	printit; echo $1 | tr ‘a-z‘ ‘A-Z‘
	;;
  "three")
	printit; echo $1 | tr ‘a-z‘ ‘A-Z‘
	;;
  *)
	echo "Usage $0 {one|two|three}"
	;;
esac

另外, function 也是拥有内建变量的~他的内建变量与 shell script 很类似, 函数名称代表示 $0 ,而后续接的变量也是以 $1, $2... 来取代的~ 这里很容易搞错喔~因为『 function fname() { 程序段 } 』内的 $0, $1... 等等与 shell script
的 $0 是不同的。以上面 sh12-2.sh 来说,假如我下达:『 sh sh12-2.sh one 』 这表示在 shell script 内的 $1 为 "one" 这个字串。但是在 printit() 内的 $1 则与这个 one 无关。 我们将上面的例子再次的改写一下,让你更清楚!

[[email protected] scripts]# vi sh12-3.sh

function printit(){
	echo "Your choice is $1"   # 这个 $1 必须要参考底下命令的下达
}

echo "This program will print your selection !"
case $1 in
  "one")
	printit 1  # 请注意, printit 命令后面还有接参数!
	;;
  "two")
	printit 2
	;;
  "three")
	printit 3
	;;
  *)
	echo "Usage $0 {one|two|three}"
	;;
esac

13.5 循环 (loop)

while do done, until do done (不定循环圈)

一般来说,不定回圈最常见的就是底下这两种状态了:

while [ condition ]  <==中括号内的状态就是判断式
do            <==do 是回圈的开始!
	程序段落
done          <==done 是回圈的结束

『当 condition 条件成立时,就进行回圈,直到 condition 的条件不成立才停止』的意思。还有另外一种不定回圈的方式:

until [ condition ]
do
	程序段落
done
[[email protected] scripts]# vi sh13.sh

while [ "$yn" != "yes" -a "$yn" != "YES" ]
do
	read -p "Please input yes/YES to stop this program: " yn
done
echo "OK! you input the correct answer."

如果使用 until 呢?呵呵有趣罗~ 他的条件会变成这样:

[[email protected] scripts]# vi sh13-2.sh

until [ "$yn" == "yes" -o "$yn" == "YES" ]
do
	read -p "Please input yes/YES to stop this program: " yn
done
echo "OK! you input the correct answer."

仔细比对一下这两个东西有啥不同喔! ^_^再来,如果我想要计算 1+2+3+....+100 这个数据呢? 利用回圈啊~他是这样的:

[[email protected] scripts]# vi sh14.sh

s=0  # 这是加总的数值变量
i=0  # 这是累计的数值,亦即是 1, 2, 3....
while [ "$i" != "100" ]
do
	i=$(($i+1))   # 每次 i 都会添加 1
	s=$(($s+$i))  # 每次都会加总一次!
done
echo "The result of ‘1+2+3+...+100‘ is ==> $s"

嘿嘿!当你运行了『 sh sh14.sh 』之后,就可以得到 5050 这个数据才对啊!

13.5.2 for...do...done (固定循环)

for
这种语法,则是『 已经知道要进行几次循环』的状态!

for var in con1 con2 con3 ...
do
	程序段
done

我们可以做个简单的练习。假设我有三种动物,分别是 dog, cat, elephant 三种, 我想每一行都输出这样:『There are dogs...』之类的字样,则可以:

[[email protected] scripts]# vi sh15.sh

for animal in dog cat elephant
do
	echo "There are ${animal}s.... "
done

13.5.3 for...do...done 的数值处理

for (( 初始值; 限制值; 运行步阶 ))
do
	程序段
done

值得注意的是,在『运行步阶』的配置上,如果每次添加 1 ,则可以使用类似『i++』的方式,亦即是 i 每次回圈都会添加一的意思。好,我们以这种方式来进行 1 累加到使用者输入的回圈吧!

[[email protected] scripts]# vi sh19.sh

read -p "Please input a number, I will count for 1+2+...+your_input: " nu

s=0
for (( i=1; i<=$nu; i=i+1 ))
do
	s=$(($s+$i))
done
echo "The result of ‘1+2+3+...+$nu‘ is ==> $s"

13.6 shell script 的追踪与 debug

scripts 在运行之前,最怕的就是出现语法错误的问题了!那么我们如何 debug 呢?有没有办法不需要透过直接运行该 scripts 就可以来判断是否有问题呢?呵呵!当然是有的!我们就直接以 bash 的相关参数来进行判断吧!

[[email protected] ~]# sh [-nvx] scripts.sh
选项与参数:
-n  :不要运行 script,仅查询语法的问题;
-v  :再运行 sccript 前,先将 scripts 的内容输出到萤幕上;
-x  :将使用到的 script 内容显示到萤幕上,这是很有用的参数!

范例一:测试 sh16.sh 有无语法的问题?
[[email protected] ~]# sh -n sh16.sh
# 若语法没有问题,则不会显示任何资讯!

范例二:将 sh15.sh 的运行过程全部列出来~
[[email protected] ~]# sh -x sh15.sh
+ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/root/bin
+ export PATH
+ for animal in dog cat elephant
+ echo ‘There are dogs.... ‘
There are dogs....
+ for animal in dog cat elephant
+ echo ‘There are cats.... ‘
There are cats....
+ for animal in dog cat elephant
+ echo ‘There are elephants.... ‘
There are elephants....

请注意,上面范例二中运行的结果并不会有颜色的显示!鸟哥为了方便说明所以在 + 号之后的数据都加上颜色了! 在输出的信息中,在加号后面的数据其实都是命令串,由於 sh -x 的方式来将命令运行过程也显示出来, 如此使用者可以判断程序码运行到哪一段时会出现相关的资讯!这个功能非常的棒!透过显示完整的命令串,
你就能够依据输出的错误资讯来订正你的脚本了!

熟悉 sh 的用法,将可以使你在管理 Linux 的过程中得心应手!至於在 Shell scripts 的学习方法上面,需要『多看、多模仿、并加以修改成自己的样式!』 是最快的学习手段了!网络上有相当多的朋友在开发一些相当有用的 scripts ,若是你可以将对方的 scripts 拿来,并且改成适合自己主机的样子!那么学习的效果会是最快的呢!

时间: 2024-10-04 07:58:58

鸟哥的Linux私房菜_基础版_学习笔记9:第十三章 学习 Shell Scripts的相关文章

鸟哥的Linux私房菜(基础学习,服务器架设)

纪念下吧:2014年大连的第一场雪,12月1号,早上出门就看见漫天飘着雪花,其实,还是很漂亮的! 自学过Linux的同学应该对<鸟哥的Linux私房菜>不会陌生,鸟哥分成两个部分来写,第一本就是<鸟哥的Linux私房菜--基础学习篇>,另一本就叫做<鸟哥的Linux私房菜--服务器架设篇>,第一本的内容大多是讲一些实用命令的,非常适合Linux的初学者去学习,第二本书的主要内容是讲一些网络协议,适合喜欢搞Linux网络的同学去学习,而鸟哥本人又无私的把他的两本书放到了网

鸟哥的linux私房菜 第三版 基础篇 part3

第九章 档案与文件系统的压缩与打包 *.Z compress程序压缩的档案   .gz gzip程序压缩的档案  .bz2 bzip2程序压缩的档案  .tar  tar打包的数据,没压缩  .tar.gz 打包的数据,并被gzip压缩 zcat config.gz 压缩 tar -jcv -f filename.tar.bz2     rm -rf !!! 完整备份工具  dump [-S:仅列出后面的待备份数据需要多少磁盘空间  u:把dump的时间记录到/etc/dumpdates里 v:

鸟哥的 Linux 私房菜Shell Scripts篇(一)

12.1 什么是 Shell scripts 什么是 shell script (程序化脚本) 呢?就字面上的意义,我们将他分为两部份. 在" shell"部分,我们在 十章的 BASH 当中已经提过了,那是一个命令行下面让我们与系统沟通的一个工具接口.那么" script "是啥? 字面上的意义, script 是"脚本.剧本"的意思.整句话是说,shell script 是针对 shell 所写的"剧本!"什么东西啊?其实

《鸟哥的Linux私房菜》13章shel script习题答案

因为感觉对Linux命令还没有多大的感觉,所以就专门找了鸟哥的书来看一下,折腾了几天看基础篇的shell部分,收获还是蛮大的,至少对Linux命令是有点感觉了,然后往前学习的一些知识,在理论知识方面也得到了一定的扩充了.先不多说,把习题的答案分享一下. <鸟哥的Linux私房菜>基础篇P398习题 (1)请新建一个script,当你执行该script的时候,该script可以显示你目前的身份(用whoami)和你目前所在的目录(用pwd). 这道题的答案已经直接给出了,直接上脚本: #!/bi

【Linux】鸟哥的Linux私房菜基础学习篇整理(一)

最近,一直在写PPC的模拟器和汇编器,也在做设计.所以重新看了看<鸟哥的Linux私房菜>,还是有好多命令不太熟悉.就打算写几篇blog记下来. 1. nl [-bnw] filename:添加行号打印参数:-b:指定行号指定的方式,主要有两种: -b a:表示不论是否为空行,也同样列出行号(类似cat -n): -b t:如果有空行,空的那一行不要列出行号(默认值).-n:列出行号表示的方法,主要有三种: -n ln:行号在屏幕的最左方显示: -n rn:行号在自己字段的最右方显示,且不加0

【Linux】鸟哥的Linux私房菜基础学习篇整理(二)

1. dumpe2fs [-bh] devicename:查询superblock信息.参数:-b:列出保留为坏道的部分:-h:列出superblock的数据,不会列出其他的区段内容. 2. df [-ahikHTm] 目录或文件名:列出文件系统的整理磁盘使用量.参数:-a:列出所有的文件系统,包括系统特有的/proc等文件系统:-k:以KB的容量显示各文件系统:-m:以MB的容量显示各文件系统:-h:以人们易阅读的GB.MB.KB等格式自行显示:-H:以M=1000K替代M=1024K的进位方

【Linux】鸟哥的Linux私房菜基础学习篇整理(七)

1. test命令的测试功能.测试的标志:(1)关于文件类型的检测 test [-efdbcSpL] filename-e:该文件名是否存在:-f:该文件名是否为文件:-d:该文件名是否为目录:-b:该文件名是否存在且为一个block device设备:-c:该文件名是否存在且为一个character device设备:-S:该文件名是否存在且为一个Socket文件:-p:该文件名是否存在且为一个FIFO文件:-L:该文件名是否存在且为一个连接文件.(2)关于文件权限的检测 test [-r]

鸟哥的 Linux 私房菜(服务器) 第二章 网络基础概念

鸟哥的 Linux 私房菜(服务器) @(学习笔记)[Linux|Markdown|笔记] [TOC] 第二章 网络基础概念 2.1 网络是个什么玩意儿 OSI 七层协定 分层 负责内容 Layer 1物理层Physical Layer 由于网络媒体只能传送 0 与 1 这种位串,因此物理层必须定义所使用的媒体设备之电压与讯号等, 同时还必须了解数据讯框转成位串的编码方式,最后连接实体媒体并传送/接收位串. Layer 2数据链结层Data-Link Layer 这一层是比较特殊的一个阶层,因为

【Linux】鸟哥的Linux私房菜基础学习篇整理(九)

1. quotacheck [-avugfM] [/mount_point]:扫描文件系统并创建Quota配置文件.参数:-a:扫描所有在/etc/mtab内,含有quota支持的文件系统,加上此参数后,不必写/mount_point:-u:针对用户扫描文件与目录的使用情况,会新建aquota.user:-g:针对用户组扫描文件与目录的使用情况,会新建aquota.group:-v:显示扫描过程的信息:-f:强制扫描文件系统,并写入新的quota配置文件(危险):-M:强制以读写的方式扫描文件系

Bombe 【Linux】鸟哥的Linux私房菜基础学习篇整理(三)

1. gzip [-cdtv#] filename:压缩.参数:-c:将压缩的数据输出到屏幕上,可通过数据重定向进行处理:-d:解压缩的参数:-t:可以用来检验一个压缩文件的一致性,查看文件有无错误:-v:可以显示出原文件/压缩文件的压缩比等信息:-#:压缩等级,1最快(压缩比最差),9最慢(压缩比最好),默认6. 2. zcat *.gz:读取gzip压缩文件. 3. bzip2 [-cdkzv#] filename:压缩.参数:-c:将压缩过程中产生的数据输出到屏幕上:-d:解压缩的参数:-