linux-basic(13)学习shell script

【13.1】什么是shell script?
1)shell script 是利用 shell 的功能所写的一个『程序 (program)』,这个程序是使用纯文字档,将一些 shell 的语法与命令(含外部命令)写在里面, 搭配正规表示法、管线命令与数据流重导向等功能,以达到我们所想要的处理目的。
  • 1.1)简单的说, shell script 就像是早期 DOS 年代的批量档 (.bat) ,最简单的功能就是将许多命令汇整写在一起, 让使用者很轻易的就能够 one touch 的方法去处理复杂的动作 (运行一个文件 "shell script" ,就能够一次运行多个命令)。 而且 shell script 更提供阵列、回圈、条件与逻辑判断等重要功能,让使用者也可以直接以 shell 来撰写程序,而不必使用类似 C 程序语言等传统程序撰写的语法呢! 
  • 1.2)shell script 可以简单的被看成是批量档, 也可以被说成是一个程序语言,且这个程序语言由於都是利用 shell 与相关工具命令, 所以不需要编译即可运行,且拥有不错的除错 (debug) 工具,所以,他可以帮助系统管理员快速的管理好主机。
2)shell script 用在系统管理上面是很好的一项工具,但是用在处理大量数值运算上, 就不够好了,因为 Shell scripts 的速度较慢,且使用的 CPU 资源较多,造成主机资源的分配不良。还好, 我们通常利用 shell script 来处理服务器的侦测,倒是没有进行大量运算的需求啊!所以不必担心的啦!

【13.1.2】第一个 script 的编写与执行
1)shell编写规则:在 shell script 的撰写中还需要用到底下的注意事项:
  •   1. 命令的运行是从上而下、从左而右的分析与运行;
  •   2. 命令的下达就如同第五章内提到的: 命令、选项与参数间的多个空白都会被忽略掉;
  •   3. 空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样视为空白键;
  •   4. 如果读取到一个 Enter 符号 (CR) ,就尝试开始运行该行 (或该串) 命令;
  •   5. 至於如果一行的内容太多,则可以使用『 \[Enter] 』来延伸至下一行;
  •   6. 『 # 』可做为注解!任何加在 # 后面的数据将全部被视为注解文字而被忽略!
2)shell执行方式:假设你写的这个程序档名是 /home/dmtsai/shell.sh 好了,那如何运行这个文件?很简单,可以有底下几个方法:
  ● 直接命令下达: shell.sh 文件必须要具备可读与可运行 (rx) 的权限,然后:
      ○ 绝对路径:使用 /home/dmtsai/shell.sh 来下达命令;
      ○ 相对路径:假设工作目录在 /home/dmtsai/ ,则使用 ./shell.sh 来运行
      ○ 变量『PATH』功能:将 shell.sh 放在 PATH 指定的目录内,例如: ~/bin/

  ● 以 bash 程序来运行:透过『 bash shell.sh 』或『 sh shell.sh 』来运行
补充:那为何『 sh shell.sh 』也可以运行呢?这是因为 /bin/sh 其实就是 /bin/bash (连结档),使用 sh shell.sh 亦即告诉系统,我想要直接以 bash 的功能来运行 shell.sh 这个文件内的相关命令的意思,所以此时你的 shell.sh 只要有 r 的权限即可被运行喔!

3)编写第1个shell script
#!/bin/bash
# Program:
#       This program shows "Hello World!" in your screen.
# History:
# 2005/08/23    VBird   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello World! \a \n"
exit 0 
(1)
【13.1.3】编写shell script的良好习惯
1)建议你一定要养成良好的 script 撰写习惯,在每个 script 的档头处记录好:
  ● script 的功能;
  ● script 的版本资讯;
  ● script 的作者与联络方式;
  ● script 的版权宣告方式;
  ● script 的 History (历史纪录);
  ● script 内较特殊的命令,使用『绝对路径』的方式来下达;
  ● script 运行时需要的环境变量预先声明与设置。

【13.2】简单的shell script练习
【13.2.1】简单范例

1)交互式脚本:变量内容由用户决定
请你以 read 命令的用途,撰写一个 script ,他可以让使用者输入:1. first name 与 2. last name, 最后并且在萤幕上显示:『Your full name is: 』的内容:
(2)
#!/bin/bash
# Program:
#       User inputs his first name and last name.  Program shows his full name.
# History:
# 2005/08/23    VBird   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATHread -p "Please input your first name: " firstname  # 提示使用者输入
read -p "Please input your last name:  " lastname   # 提示使用者输入
echo -e "\nYour full name is: $firstname $lastname" # 结果由萤幕输出

2)随日期变化:利用日期进行文件的创建:
假设我想要创建三个空文件(透过touch) ,档名最开头由使用者输入决定,假设使用者输入 filename 好了,那今天的日期是 2009/02/14 , 我想要以前天、昨天、今天的日期来创建这些文件,亦即 filename_20090212, filename_20090213, filename_20090214 ,该如何是好?
[root@localhost scripts]# vim sh03.sh
#!/bin/bash
# Program:
#       Program creates three files, which named by user's input 
#       and date command.
# History:
# 2018/05/01    tang rong       First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH# 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"

(3)


(4)
3)数值运算:简单的加减乘除
如果我们要使用者输入两个变量, 然后将两个变量的内容相乘,最后输出相乘的结果,那可以怎么做?

(5)
补充:鸟哥比较建议使用这样的方式来进行运算:
var=$((运算内容))
不但容易记忆,而且也比较方便的多,因为两个小括号内可以加上空白字节喔! 未来你可以使用这种方式来计算的呀!至於数值运算上的处理,则有:『 +, -, *, /, % 』等等。 那个 % 是取余数啦~举例来说, 13 对 3 取余数,结果是 13=4*3+1,所以余数是 1 啊!就是:

(6)
【13.2.2】script的执行方式差别(source, sh script, ./script)
1)脚本的运行方式除了前面小节谈到的方式之外,还可以利用 source 或小数点 (.) 来运行喔!那么这种运行方式有何不同呢?
方式1)利用直接执行的方式来执行script
当使用前一小节提到的直接命令下达 (不论是绝对路径/相对路径还是 $PATH 内),或者是利用 bash (或 sh) 来下达脚本时, 该 script 都会使用一个新的 bash 环境来运行脚本内的命令!也就是说,使用这种运行方式时, 其实 script 是在子程序的 bash 内运行的!
重点在于:『当子程序完成后,在子程序内的各项变量或动作将会结束而不会传回到父程序中』!

【荔枝】我们举刚刚提到过的 sh02.sh 这个脚本来说明好了,这个脚本可以让使用者自行配置两个变量,分别是 firstname 与 lastname,想一想,如果你直接运行该命令时,该命令帮你配置的 firstname 会不会生效?

(7)
1.2)利用source来执行脚本:在父进程中执行

(8)

【13.3】善用判断式

【13.3.1】利用test命令的测试功能
1)判断 /trong 这个目录存在与否
(9)
2)那我知道 -e 是测试一个『东西』在不在, 如果还想要测试一下该档名是啥玩意儿时,还有哪些标志可以来判断的呢?呵呵!有底下这些东西喔!
(10)
(11)
3)OK!现在我们就利用 test 来帮我们写几个简单的例子。首先,判断一下,让使用者输入一个档名,我们判断: 
  • 判断1)这个文件是否存在,若不存在则给予一个『Filename does not exist』的信息,并中断程序;
  • 判断2)若这个文件存在,则判断他是个文件或目录,结果输出『Filename is regular file』或 『Filename is directory』;
  • 判断3)判断一下,运行者的身份对这个文件或目录所拥有的权限,并输出权限数据!
(12)
(13)
#!/bin/bash
# Program:
#       User input a filename, program will check the flowing:
#       1.) exist? 2.) file/directory? 3.) file permissions 
# History:
# 2005/08/25    VBird   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH# 1. 让使用者输入档名,并且判断使用者是否真的有输入字串?
echo -e "Please input a filename, I will check the filename's type and \
permission. \n\n"
read -p "Input a filename : " filename
test -z $filename && echo "You MUST input a filename." && exit 0
# 2. 判断文件是否存在?若不存在则显示信息并结束脚本
test ! -e $filename && echo "The filename '$filename' DO NOT exist" && exit 0
# 3. 开始判断文件类型与属性
test -f $filename && filetype="regulare file"
test -d $filename && filetype="directory"
test -r $filename && perm="readable"
test -w $filename && perm="$perm writable"
test -x $filename && perm="$perm executable"
# 4. 开始输出资讯!
echo "The filename: $filename is a $filetype"
echo "And the permissions are : $perm"


【13.3.2】利用判断符号[]
1)除了我们很喜欢使用的 test 之外,其实,我们还可以利用判断符号『 [ ] 』(就是中括号啦) 来进行数据的判断呢! 举例来说,如果我想要知道 $HOME 这个变量是否为空的,可以这样做:


(14)
补充1:如果要在 bash 的语法当中使用中括号作为 shell 的判断式时,必须要注意中括号的两端需要有空白字节来分隔喔!
补充2)假设我空白键使用『□』符号来表示,那么,在这些地方你都需要有空白键:
(15)
所以说,你最好要注意:
  ● 在中括号 [] 内的每个组件都需要有空白键来分隔;
  ● 在中括号内的变量,最好都以双引号括号起来;
  ● 在中括号内的常数,最好都以单或双引号括号起来。
【荔枝】利用中括号[] 进行判断,加引号的区别
(16)
【荔枝】那我们也使用中括号的判断来做一个小案例好了,案例配置如下:
  1. 当运行一个程序的时候,这个程序会让使用者选择 Y 或 N ,
  2. 如果使用者输入 Y 或 y 时,就显示『 OK, continue 』
  3. 如果使用者输入 n 或 N 时,就显示『 Oh, interrupt !』
  4. 如果不是 Y/y/N/n 之内的其他字节,就显示『 I don't know what your choice is 』
利用中括号[]、 && 与 || 来继续吧!


(17)
【13.3.3】shell script的默认变量($0、 $1 ......)
1)如果你想要重新启动系统登录档的功能,可以这样做:


(18)
2)script 是怎么达成这个功能的呢?其实 script 针对参数已经有配置好一些变量名称了!对应如下:


(19)
3)除了这些数字的变量之外, 我们还有一些较为特殊的变量可以在 script 内使用来调用这些参数喔!
  ● $# :代表后接的参数『个数』,以上表为例这里显示为『 4 』;
  ● $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
  ● $* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字节,默认为空白键, 所以本例中代表『 "$1 $2 $3 $4" 』之意。


【荔枝】假设我要运行一个可以携带参数的 script ,运行该脚本后萤幕会显示如下的数据:
  •   ● 程序的档名为何?
  •   ● 共有几个参数?
  •   ● 若参数的个数小於 2 则告知使用者参数数量太少
  •   ● 全部的参数内容为何?
  •   ● 第一个参数为何?
  •   ● 第二个参数为何。

(20)
3)shift:造成参数变量号码偏移
【荔枝】那个 shift 会移动变量,而且 shift 后面可以接数字,代表拿掉最前面的几个参数的意思。


(21)
【13.4】条件判断式
【13.4.1】利用 if...then

1)单层、简单条件判断式: 如果你只有一个判断式要进行,那么我们可以简单的这样看:


(22)
1.1)如果我有多个条件要判别时,我还可以有多个中括号来隔开喔!而括号与括号之间,则以 && 或 || 来隔开,他们的意义是:
  ● && 代表 AND ;
  ● || 代表 or ;
1.2)所以,在使用中括号的判断式中, && 及 || 就与命令下达的状态不同了。举例来说, sh06.sh 里面的判断式可以这样修改:
[ "$yn" == "Y" -o "$yn" == "y" ]
上式可替换为
[ "$yn" == "Y" ] || [ "$yn" == "y" ]
之所以这样改,很多人是习惯问题!很多人则是喜欢一个中括号仅有一个判别式的原因。


【荔枝】将sh06.sh 修改为 if...then 的样式看看:


(23)
2)多重、复杂条件判断式
2.1)一个条件判断


(24)
2.2)多个条件判断


(25)
注意:你得要注意的是, elif 也是个判断式,因此出现 elif 后面都要接 then 来处理!但是 else 已经是最后的没有成立的结果了, 所以 else 后面并没有 then 喔!好!我们来将 sh06-2.sh 改写成这样:
【荔枝】将 多个if 语句改为 elif 语句


(26)
3)一般来说,如果你不希望使用者由键盘输入额外的数据时, 可以使用上一节提到的参数功能 ($1)!让使用者在下达命令时就将参数带进去! 现在我们想让使用者输入『 hello 』这个关键字时,利用参数的方法可以这样依序设计:
  1. 判断 $1 是否为 hello,如果是的话,就显示 "Hello, how are you ?";
  2. 如果没有加任何参数,就提示使用者必须要使用的参数下达法;
  3. 而如果加入的参数不是 hello ,就提醒使用者仅能使用 hello 为参数。
整个程序的撰写可以是这样的:


(27)
【荔枝】 netstat命令:查询到目前主机打开的网络服务端口
荔枝1)我可以利用『 netstat -tuln 』来取得目前主机有启动的服务:
(28)
补充:上面的重点是『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(列印服务功能)


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


(29)
【荔枝】写个脚本程序来跑,让使用者输入他的退伍日期,让你去帮他计算还有几天才退伍?
由於日期是要用相减的方式来处置,所以我们可以透过使用 date 显示日期与时间,将他转为由 1970-01-01 累积而来的秒数, 透过秒数相减来取得剩余的秒数后,再换算为日数即可。整个脚本的制作流程有点像这样:
  1. 先让使用者输入他们的退伍日期;
  2. 再由现在日期比对退伍日期;
  3. 由两个日期的比较来显示『还需要几天』才能够退伍的字样。
似乎挺难的样子?其实也不会啦,利用『 date --date="YYYYMMDD" +%s 』转成秒数后,接下来的动作就容易的多了!


(30)
#!/bin/bash
# Program:
#       You input your demobilization date, I calculate how many days
#       before you demobilize.
# History:
# 2005/08/29    VBird   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH# 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" == "" ]; thenecho "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"
elsedeclare -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


(31)
【13.4.2】利用 case...esac 判断
(32)
【荔枝】把 sh09.sh 修改一下,如下:

(33)
#!/bin/bash
# Program:
#       Show "Hello" from $1.... by using case .... esac
# History:
# 2005/08/29    VBird   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATHcase $1 in"hello")echo "Hello, how are you ?";;"")echo "You MUST input parameters, ex> {$0 someword}";;*)   # 其实就相当於万用字节,0~无穷多个任意字节之意!echo "Usage $0 {hello}";;
esac

(34)
【补充】一般来说,使用『 case $变量 in 』这个语法中,当中的那个『 $变量 』大致有两种取得的方式:
  ● 直接下达式:例如上面提到的,利用『 script.sh variable 』 的方式来直接给予 $1 这个变量的内容,这也是在 /etc/init.d 目录下大多数程序的设计方式。
  ● 互动式:透过 read 这个命令来让使用者输入变量的内容。

【荔枝】让使用者能够输入 one, two, three , 并且将使用者的变量显示到屏幕上,如果不是 one, two, three 时,就告知使用者仅有这三种选择。(通过直接执行式来传入参数,即利用 script.sh variable 的方式来直接给予 $1 这个变量的内容)

(35) 
#!/bin/bash
# Program:
#       This script only accepts the flowing parameter: one, two or three.
# History:
# 2005/08/29    VBird   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATHecho "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
【继续荔枝】让使用者能够输入 one, two, three , 并且将使用者的变量显示到屏幕上,如果不是 one, two, three 时,就告知使用者仅有这三种选择。(通过read命令读入用户输入的变量内容)

(36)
【13.4.3】利用function功能
1)function的语法如下:
function fname() {
程序段
}
那个 fname 就是我们的自订的运行命令名称~而程序段就是我们要他运行的内容了。 要注意的是,因为 shell script 的运行方式是由上而下,由左而右, 因此在 shell script 当中的 function 的配置一定要在程序的最前面, 这样才能够在运行时被找到可用的程序段喔!

【荔枝】定义一个名为 printit的函数, 如下:

(37)
#!/bin/bash
# Program:
#       Use function to repeat information.
# History:
# 2005/08/29    VBird   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATHfunction 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
2)另外, 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 无关。 

【荔枝】将上面的例子再次改写一下,如下:
(38)
[root@localhost scripts]# vim sh12-4.sh#!/bin/bash
# Program:
#       Use function to repeat information.
# History:
# 2005/08/29    VBird   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATHfunction 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】循环
【13.5.1】while do done, until do done (不定循环)

1)循环方式
方式1) while do done 循环:while 的中文是当....时,所以,这种方式说的是『当 condition 条件成立时,就进行循环,直到 condition 的条件不成立才停止』的意思。
(39)
方式2)until do done 循环(不定循环):它说的是当 condition 条件成立时,就终止循环, 否则就持续进行循环的程序段。
(40)
【荔枝】while循环:假设我要让使用者输入 yes 或者是 YES 才结束程序的运行,否则就一直进行告知使用者输入字串。

(41)
(42)
【荔枝】想要计算 1+2+3+....+100 这个数据呢? 利用循环啊。
(43)
【13.5.2】for...do...done(固定循环)
1)相对于 while, until 的循环方式是必须要『符合某个条件』的状态, for 这种语法,则是已经知道要进行几次循环的状态!他的语法是:

(44)
2)让我们想像另外一种状况,由於系统上面的各种帐号都是写在 /etc/passwd 内的第一个栏位,你能不能透过管线命令的 cut 捉出单纯的帐号名称后,以 id 及 finger 分别检查使用者的识别码与特殊参数呢?
(45)
【补充】
补充1)id命令: id 命令可以显示真实有效的用户 ID(UID) 和组 ID(GID)。UID 是对一个用户的单一身份标识。组 ID(GID)则对应多个UID。
补充2)finger命令:finger命令用于查找并显示用户信息。包括本地与远端主机的用户皆可,帐号名称没有大小写的差别。单独执行finger指令,它会显示本地主机现在所有的用户的登陆信息,包括帐号名称,真实姓名,登入终端机,闲置时间,登入时间以及地址和电话。
(46)
【荔枝】利用 ping 这个可以判断网络状态的命令, 来进行网络状态的实际侦测时,我想要侦测的网域是本机所在的 192.168.1.1~192.168.1.100,由於有 100 台主机, 总不会要我在 for 后面输入 1 到 100 吧?此时你可以这样做喔!(但本机实验只取10台机器!!)
(47)
#!/bin/bash
# Program
#       Use ping command to check the network's PC state.
# History
# 2009/02/18    VBird   first release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
network="192.168.1"              # 先定义一个网域的前面部分!
for sitenu in $(seq 1 10)       # seq 为 sequence(连续) 的缩写之意
do# 底下的程序在取得 ping 的回传值是正确的还是失败的!ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1# 开始显示结果是正确的启动 (UP) 还是错误的没有连通 (DOWN)if [ "$result" == 0 ]; thenecho "Server ${network}.${sitenu} is UP."elseecho "Server ${network}.${sitenu} is DOWN."fi
done
【荔枝】编写判别式加上循环的功能: 我想要让使用者输入某个目录文件名, 然后找出某目录内的文件名权限,该如何是好?
(48)


(49)
【13.5.3】for...do...done 的数值处理
1)for 循环还有另外一种写法!语法如下:

(50)
2)这种语法适合於数值方式的运算当中,在 for 后面的括号内的三串内容意义为:
  ● 初始值:某个变量在回圈当中的起始值,直接以类似 i=1 配置好;
  ● 限制值:当变量的值在这个限制值的范围内,就继续进行回圈。例如 i<=100;
  ● 运行步阶:每作一次回圈时,变量的变化量。例如 i=i+1。 


【荔枝】执行从1的累加,上限是输入的数字,如下:
(51)
【13.6】shell script的追踪与调试
1)scripts 在运行之前,最怕的就是出现语法错误的问题了!那么我们如何 debug 呢? 有没有办法不需要透过直接运行该 scripts 就可以来判断是否有问题呢?呵呵!当然是有的!我们就直接以 bash 的相关参数来进行判断吧!
(52)
【荔枝】
(53)

(54)
  • 补充1) 在输出的信息中,在加号后面的数据其实都是命令串,由於 sh -x 的方式来将命令运行过程也显示出来, 如此使用者可以判断程序码运行到哪一段时会出现相关的资讯!这个功能非常的棒!
  • 补充2)Linux 系统本来就有很多的服务启动脚本,如果你想要知道每个 script 所代表的功能是什么? 可以直接以 vim 进入该 script 去查阅一下,通常立刻就知道该 script 的目的了。 举例来说,我们之前一直提到的 /etc/init.d/syslog ,这个 script 是干嘛用的? 利用 vi 去查阅最前面的几行字,就知道这个 shell 脚本是干什么的了。
【13.8】本章习题
  •   shell script 是利用 shell 的功能所写的一个『程序 (program)』,这个程序是使用纯文字档,将一些 shell 的语法与命令(含外部命令)写在里面, 搭配正规表示法、管线命令与数据流重导向等功能,以达到我们所想要的处理目的;
  •   shell script 用在系统管理上面是很好的一项工具,但是用在处理大量数值运算上, 就不够好了,因为 Shell scripts 的速度较慢,且使用的 CPU 资源较多,造成主机资源的分配不良;
  •   在 Shell script 的文件中,命令的运行是从上而下、从左而右的分析与运行;
  •   shell script 的运行,至少需要有 r 的权限,若需要直接命令下达,则需要拥有 r 与 x 的权限;
  •   良好的程序撰写习惯中,第一行要宣告 shell (#!/bin/bash) ,第二行以后则宣告程序用途、版本、作者等;
  •   对谈式脚本可用 read 命令达成;
  •   要创建每次运行脚本都有不同结果的数据,可使用 date 命令利用日期达成;
  •   script 的运行若以 source 来运行时,代表在父程序的 bash 内运行之意!
  •   若需要进行判断式,可使用 test 或中括号 ( [] ) 来处理;
  •   在 script 内,$0, $1, $2..., $@ 是有特殊意义的!
  •   条件判断式可使用 if...then 来判断,若是固定变量内容的情况下,可使用 case $var in ... esac 来处理;
  •   回圈主要分为不定回圈 (while, until) 以及固定回圈 (for) ,配合 do, done 来达成所需任务!
  •   我们可使用 sh -x script.sh 来进行程序的 debug;





本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330639.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里巴巴对Java编程【集合处理】的规约

转载自 阿里巴巴对Java编程【集合处理】的规约集合处理1. 【强制】关于 hashCode 和 equals 的处理&#xff0c;遵循如下规则&#xff1a; 1&#xff09; 只要重写 equals &#xff0c;就必须重写 hashCode 。 2&#xff09; 因为 Set 存储的是不重复的对象&#xff0c;依据 ha…

http请求状态码400的原因总结

会出现这个HTTP请求状态码400&#xff0c;说明这个请求是无效的&#xff0c;并没有进入后台服务器&#xff08;控制器&#xff09;里。 通常的原因&#xff1a; 前端提交的字段名称或者字段类型和后台的实体类不一样&#xff0c;或者前端提交的参数跟后台需要的参数个数不一致…

做一个完整的Java Web项目需要掌握的技能

转自&#xff1a; https://blog.csdn.net/JasonLiuLJX/article/details/51494048--------------------------------------------------------------------------------最近自己做了几个Java Web项目&#xff0c;有公司的商业项目&#xff0c;也有个人做着玩的小项目&#xff0…

阿里巴巴对Java编程【并发处理】的规约

转载自 阿里巴巴对Java编程【并发处理】的规约并发处理1. 【强制】获取单例对象需要保证线程安全&#xff0c;其中的方法也要保证线程安全。 说明&#xff1a;资源驱动类、工具类、单例工厂类都需要注意。2. 【强制】创建线程或线程池时请指定有意义的线程名称&#xff0c;方便…

查询sql打印日志配置

mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径&#xff0c;通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.user.pojosconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

js语法+dom+js图片库+最佳实践+图片库改进版

【2】js语法 【2.2.4】数据类型类型1&#xff09;字符串 var mood happy; var moood "happy"; 类型2&#xff09;数值&#xff1b; var age 33.24; 类型3&#xff09;布尔值&#xff1b;var married true; 【2.2.5】数组1&#xff09;填充方式 填充方式1&#xf…

RabbitMQ--topic

Topic类型的Exchange与Direct相比&#xff0c;都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符&#xff01; Routingkey 一般都是有一个或多个单词组成&#xff0c;多个单词之间以”.”分割&#xff0c;…

阿里巴巴对Java编程【控制语句】的规约

转载自 阿里巴巴对Java编程【控制语句】的规约控制语句1. 【强制】在一个 switch 块内&#xff0c;每个 case 要么通过 break / return 等来终止&#xff0c;要么注释说明程序将继续执行到哪一个 case 为止 &#xff1b; 在一个 switch 块内&#xff0c;都必须包含一个 default…

RabbitMQ消息

如何确保RabbitMQ消息的可靠性&#xff1f; 开启生产者确认机制&#xff0c;确保生产者的消息能到达队列开启持久化功能&#xff0c;确保消息未消费前在队列中不会丢失开启消费者确认机制为auto&#xff0c;由spring确认消息处理成功后完成ack开启消费者失败重试机制&#xff…

阿里巴巴对Java编程【注释规约】的规约

转载自 阿里巴巴对Java编程【注释规约】的规约注释规约1. 【强制】类、类属性、类方法的注释必须使用 Javadoc 规范&#xff0c;使用/**内容*/格式&#xff0c;不得使用// xxx 方式。 说明&#xff1a;在 IDE 编辑窗口中&#xff0c; Javadoc 方式会提示相关注释&#xff0c;生…

动态创建标记+css_dom+js动态效果

【7】动态创建标记【7.1】一些传统方法【7.1.1】document.write方法&#xff0c;不推荐使用 &#xff08;1&#xff09;<!DOCTYPE html> <html lang"en"> <head><meta http-equiv"content-type" content"text/html; charsetutf-…

orcle安装及用户初始化

1.orcle资源 orlce安装包点击下载 2.首次安装 参照: https://jingyan.baidu.com/article/f79b7cb32095f79144023eae.html 3.卸载后安装 先卸载清除本地的orcle服务 参照: https://jingyan.baidu.com/article/6b18230943e9d7fb59e1590f.html再重新下载资源解压安装’’ 注意…

JDK8新特性之Lambda表达式

转载自 JDK8新特性之Lambda表达式 什么是Lambda表达式 Java 8的一个大亮点是引入Lambda表达式&#xff0c;使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时&#xff0c;也会随之被编译成一个函数式接口。 Lambda语法 一行执行语句的写法&#xff1a; (paramete…

eclipse发布web项目到tomcat服务器

README: 使用eclipse发布web项目到tomcat有很多坑儿的。下面依依道来。 step1&#xff09;eclipse建立web 项目&#xff1a;step2&#xff09;在tomcat服务器上为该web项目配置的虚拟目录&#xff0c;即把该web项目发布到tomcat&#xff1a; tomcat的server.xml 增加如下语句&…

springboot设置默认端口访问界面

1.项目结构 2.配置方法 <1>配置类默认加载 Configuration public class WebConfigurer implements WebMvcConfigurer {Overridepublic void addViewControllers(ViewControllerRegistry registry) {//默认地址&#xff08;可以是页面或后台请求接口&#xff09;registr…

Java BigDecimal和double区别

转自&#xff1a; https://www.cnblogs.com/mingforyou/p/3344489.htmlBigDecimal类 对于不需要任何准确计算精度的数字可以直接使用float或double&#xff0c;但是如果需要精确计算的结果&#xff0c;则必须使用BigDecimal类&#xff0c;而且使用BigDecimal类也可以进行大数的…

JDK8新特性之接口默认方法与静态方法

转载自 JDK8新特性之接口默认方法与静态方法 接口默认方法与静态方法 有这样一些场景&#xff0c;如果一个接口要添加一个方法&#xff0c;那所有的接口实现类都要去实现&#xff0c;而某些实现类根本就不需要实现这个方法也要写一个空实现&#xff0c;所以接口默认方法就是为…

mybatis generator Unknown system variable 'query_cache_size' 的解决方法

出现这种错误&#xff0c;很显然是数据库驱动程序 与 数据库版本不对应&#xff1b;如 mybatis使用 mysql-5.1.10的驱动程序&#xff0c;而mybatis配置的数据源连接的是 mysql-8.0.11 &#xff0c;修改 pom文件即可&#xff0c;如下&#xff1a; <dependency><groupId…

Java NoSuchElementException: No value present 问题解决

1 问题描述 java.util.NoSuchElementException: No value 2 问题分析 2.1 Java 1、使用stream()流里面的max().get()、min().get()、findFirst().get()方法&#xff0c;由于max()、min()、findFirst()方法会返回Optional对象&#xff0c;如果Optional对象里面没有数据&#xf…

JDK8新特性之Optional

转载自 JDK8新特性之Optional Optional是什么 java.util.Optional Jdk8提供 Optional&#xff0c;一个可以包含null值的容器对象&#xff0c;可以用来代替xx ! null的判断。 Optional常用方法 of public static <T> Optional<T> of(T value) {return new Opti…