博文大纲:shell
- 一、对谈式脚本——read语句
- 二、shell脚本中的测试的字符
- 三、判断脚本举例
- 四、条件判断——if语句
- 五、条件判断——case语句
- 六、条件判断——function函数结合case语句
- 七、循环判断——while、until语句
- 八、固定循环——for...do...done语句
- 九、循环——cut、set结合for语句
- 十、其余脚本类型举例
- 十一、shell脚本的追踪与debug
shell脚本的编写越规范越好,那么一般在每一个shell脚本的开头几行会有以下几个方面相关的注释信息:vim
- 脚本使用的shell,如/bin/bash;
- 脚本的版本信息;
- 脚本的做者与联络方式;
- 脚本的history(编写时间记录);
- 脚本内较特殊的指令,使用绝对路径的方式来下达;
- 脚本运行是须要的环境变量预先宣告与设置。
废话很少说,直接上使用语法案例:bash
shell变量除了能够直接赋值或脚本传参外,还可使用read命令从标准输入中得到,read是bash内置命令,可使用help read查看帮助。ide
read的读入功能就至关于交互式接受用户输入,而后给变量赋值。函数
经常使用参数以下:测试
- -p: 设置提示信息。
- -t:设置输入等待的时间,单位默认是秒。
使用举例
基本使用:ui
[root@localhost ~]# read -t 10 -p "qing shu ru:" num #读入一个输入,赋值给num,num变量前要空格。 # -t 10则表示10秒后就超时退出 qing shu ru:34 #输入34 [root@localhost ~]# echo ${num} #输出变量值 34 [root@localhost ~]# read -p "qing shu ru:" a1 a2 #也能够一次定义两个变量 qing shu ru:23 45 [root@localhost ~]# echo ${a1} ${a2} 23 45
需求①:
first name 与 2. last name,最后而且在屏幕上显示:“Your full name is: ”的内容:this
[root@localhost ~]# vim 1.sh #编辑脚本,内容以下 #!/bin/bash echo -e "yong lai xian shi wen jian full name:\n" read -p "qing shu ru fir filename:" firname read -p "qing shu ru sec filename:" secname echo -e "\nyour full name is ${firname}${secname}." #其中echo后面的“\n”表示换行 [root@localhost ~]# sh 1.sh #执行脚本 yong lai xian shi wen jian full name: qing shu ru fir filename:xie #手动输入文件名开头 qing shu ru sec filename:feng #手动输入文件名结尾 your full name is xiefeng. #它将自动将开头和结尾结合起来并输出
需求②:
假设我想要建立三个空的文件(经过touch),filename最开头由当前用户输入决定,假设使用者输入 filename 好了,那今天的日期是 2021/03/29 ,我想要之前天、昨天、今天的日期来建立这些文件。debug
[root@localhost ~]# vim 2.sh #编辑脚本 #!/bin/bash echo -e "yi ci chuang jian san ge file.\n" read -p "qing shu ru filename:" filename filename=${filename:-file} date1=$(date --date '1 days ago' +%Y%m%d) date2=$(date --date '2 days ago' +%Y%m%d) date3=$(date +%Y%m%d) file1="${filename}${date1}" file2="${filename}${date2}" file3="${filename}${date3}" touch "${file1}" touch "${file2}" touch "${file3}" [root@localhost ~]# sh 2.sh #执行脚本 yi ci chuang jian san ge file. qing shu ru filename:xie #输入自定义的文件名开头 [root@localhost ~]# find /root -name "xie*" #查看是否建立成功 /root/lv20210329 /root/lv20210331 /root/lv20210330
需求③:
若是咱们要使用者输入两个变量,而后将两个变量的内容相乘,最后输出相乘的结果。3d
[root@localhost ~]# vim 3.sh #编辑脚本 #!/bin/bash echo -e "\nzhe shi yi ge suan cheng fa de jiao ben:\n" read -p "qing shu ru yi ge shu zi:" A read -p "qing shu ru di er ge shu zi:" B sum=`echo "scale=4; ${A} * ${B}" | bc` echo -e "\n${A}x${B} ==> ${sum}." [root@localhost ~]# sh 3.sh #执行脚本 zhe shi yi ge suan cheng fa de jiao ben: qing shu ru yi ge shu zi:3 #输入第一个数 qing shu ru di er ge shu zi:4 #输入第二个数 3x4 ==> 12. #输出的结果
上面全部的测试都是经过test进行的,可使用“[ ]”来代替,将要测试的类型及指定的名字写在“[ ]” 便可,可是中括号里面两边必须有空格。(推荐使用中括号“[ ]”)
三、判断脚本举例
需求①:
[root@localhost ~]# vim 4.sh #编辑脚本 #!/bin/bash echo "yong lai ce shi wen jian huo dirctory." read -p "qing shu ru yi ge wen jian ming:" filename test -z ${filename} && echo -e "\nqing shu ru yi ge filename." && exit 0 test ! -e ${filename} && echo "filename does not exitst." && exit 0 test -f ${filename} && filetype="file" test -d ${filename} && filetype="directory" test -r ${filename} && prem="read" test -w ${filename} && prem="${prem}+write" test -x ${filename} && prem="${prem}+exe" echo -e "\nthis is a ${filetype},it's perm.. is ${prem}." [root@localhost ~]# sh 4.sh #执行脚本 yong lai ce shi wen jian huo dirctory. qing shu ru yi ge wen jian ming:/root #输入一个目录名 this is a directory,it's perm.. is read+write+exe. #脚本执行后输出的结果 [root@localhost ~]# sh 4.sh #再执行脚本 yong lai ce shi wen jian huo dirctory. qing shu ru yi ge wen jian ming:/etc/passwd #输入一个文件 this is a file,it's perm.. is read+write. #脚本执行后输出的结果
需求②:
一、当执行一个程序的时候,这个程序会让用户输入Y或N。
二、若是使用者输入Y或y时,就会显示OK,continue.
三、若是使用者输入N或n时,就会显示ON,interrupt.
四、若是不是Y/y/N/n以内的字符,那么将会死循环这个脚本,直到手动退出,或输入正确的值(其实稍做改动,能够改成若默认按回车的话能够等于输入“Y”,自行研究吧)。
[root@localhost ~]# vim 5.sh #编辑脚本 #!/bin/bash while [ "${yn}" != "Y" -o "${yn}" != "y" -o "${yn}" != "N" -o "${yn}" != "n" ] do read -p "qing shu ru 'Y' or 'N':" yn [ "${yn}" == "Y" -o "${yn}" == "y" -o "${yn}" == "" ] && echo -e "\nOK,continue." && exit 0 [ "${yn}" == "N" -o "${yn}" == "n" ] && echo -e "\nON,interrupt." && exit 0 done [root@localhost ~]# sh 5.sh #下面是屡次执行脚本,测试是否达到需求 qing shu ru 'Y' or 'N': OK,continue. [root@localhost ~]# sh 5.sh qing shu ru 'Y' or 'N':y OK,continue. [root@localhost ~]# sh 5.sh qing shu ru 'Y' or 'N':n ON,interrupt. [root@localhost ~]# sh 5.sh qing shu ru 'Y' or 'N':u qing shu ru 'Y' or 'N':i qing shu ru 'Y' or 'N':N ON,interrupt.
需求③:
一、程序的文件名为什么?
二、共有几个参数?
三、若参数的个数小于 2 则告知使用者参数数量太少
四、所有的参数内容为什么?
五、第一个参数为什么?
六、第二个参数为什么
[root@localhost ~]# vim 6.sh #编辑脚本以下 #!/bin/bash echo -e "\ncheng xu de wen jian ming shi ${0}" echo -e "\nyi gong you $# ge can shu." [ $# -lt 2 ] && echo "can shu tai shao le ." && exit 0 echo "your whole parameter is ==> '$*'." echo "the 1st parameter ${1}." echo "the 2nd parameter ${2}." [root@localhost ~]# sh 6.sh a b c #执行脚本 cheng xu de wen jian ming shi 6.sh yi gong you 3 ge can shu. your whole parameter is ==> 'a b c'. the 1st parameter a. the 2nd parameter b. [root@localhost ~]# sh 6.sh a #再次执行脚本 cheng xu de wen jian ming shi 6.sh yi gong you 1 ge can shu. can shu tai shao le . #为了避免为难本身,上面我用了拼音,多多体谅[ 捂脸 ]。
需求④:
查看本机都是否开启了www / ftp / mail服务,并将结果直观的显示出来
[root@localhost ~]# vim 11.sh #!/bin/bash file="/dev/shm/a.txt" netstat -anpt > ${file} awk -F : '{print $4}' ${file} | awk '{print $1}' | grep "80" &> /dev/null if [ $? -eq 0 ] then echo -e "www service is up\n" fi awk '{print $4}' ${file} | egrep "20|21" &> /dev/null if [ $? -eq 0 ] then echo -e "ftp service is up\n" fi awk '{print $4}' ${file} | grep "25" &> /dev/null if [ $? -eq 0 ] then echo -e "mail service is up\n" fi [root@localhost ~]# sh 11.sh #执行脚本测试 mail service is up [root@localhost ~]# systemctl start httpd #启动www服务再测试 [root@localhost ~]# sh 11.sh www service is up mail service is up
需求⑤:
都知道脚本后面的第一段是$1,第二段是$2....那么是否能够进行偏移呢,假设让本来的$2变为$1。
[root@localhost ~]# vim 7.sh #编辑脚本以下 #!/bin/bash echo "total parameter number is ==> $#" echo "your whole parameter is ==> $* " shift echo "total parameter number is ==> $#" echo "your whole parameter is ==> $* " shift 3 echo "total parameter number is ==> $#" echo "your whole parameter is ==> $* " #“上面默认的shift”参数是偏移1个位置,也能够指定偏移的参数,如“shift 3”则表示向后偏移三个 [root@localhost ~]# sh 7.sh a b c #执行脚本,而且追加三个参数 total parameter number is ==> 3 your whole parameter is ==> a b c total parameter number is ==> 2 your whole parameter is ==> b c total parameter number is ==> 2 your whole parameter is ==> b c #从输出结果能够发现,偏移是累加的,第一次偏移了默认1位, #第二次偏移了3位,那么实际已经偏移了原始参数的4位(由于累加) #可是参数只有三个,因此它会循环偏移,因此结果仍是b和c。
需求①:
一、当执行一个程序的时候,这个程序会让用户输入Y或N。
二、若是使用者输入Y或y或者直接按下回车键时,就会显示OK,continue.
三、若是使用者输入N或n时,就会显示ON,interrupt.
四、若是不是Y/y/N/n以内的字符,那么将输出“I don't know what your choice is”
[root@localhost ~]# vim 66.sh #编写脚本 #!/bin/bash read -p "Please input (Y/N): " yn if [ "${yn}" == "Y" -o "${yn}" == "y" -o "${yn}" == "" ]; then echo "OK, continue" exit 0 elif [ "${yn}" == "N" -o "${yn}" == "n" ]; then echo "ON, interrupt!" exit 0 else echo "I don't know what your choice is" fi [root@localhost ~]# sh 66.sh #屡次执行,进行测试 Please input (Y/N): OK, continue [root@localhost ~]# sh 66.sh Please input (Y/N): n ON, interrupt! [root@localhost ~]# sh 66.sh Please input (Y/N): dd I don't know what your choice is
需求②:
判断192.168.1.0-10的主机存活,测试是否能够ping通,并输出IP地址对应的主机是“up”仍是“down”,两种实现方法,以下:
方法1:
[root@localhost ~]# vim 8.sh #编写脚本 #!/bin/bash i=0 network=192.168.1. while [ ${i} -le 10 ] do ping -c 3 -i 0.2 -w 3 ${network}${i} &> /dev/null if [ $? -eq 0 ] then echo "host ${network}${i} is up" else echo "host ${network}${i} is down" fi let i++ done [root@localhost ~]# sh 8.sh #执行脚本 host 192.168.1.0 is down host 192.168.1.1 is down host 192.168.1.2 is up host 192.168.1.3 is down host 192.168.1.4 is down host 192.168.1.5 is down host 192.168.1.6 is down host 192.168.1.7 is down host 192.168.1.8 is up host 192.168.1.9 is down host 192.168.1.10 is down
方法2:
[root@localhost ~]# vim 21.sh #脚本内容以下 #!/bin/bash network="192.168.1." for host in $(seq 1 10) do ping -c 1 -w 1 ${network}${host} &> /dev/null if [ $? -eq 0 ] then echo "${network}${host} is up." else echo "${network}${host} is down." fi done [root@localhost ~]# sh 21.sh #执行脚本 192.168.1.1 is down. 0
需求③:
一、判断 $1 是否为 hello,若是是的话,就显示 "Hello, how are you ?";
2.、若是没有加任何参数,就提示使用者必需要使用的参数下达法;
三、 而若是加入的参数不是 hello ,就提醒使用者仅能使用 hello 为参数。
[root@localhost ~]# vim 10.sh #编写脚本 #!/bin/bash if [ "${1}" == "hello" ] then echo "hello,how are you ?" exit 0 elif [ "${1}" == "" ] then echo "qing shi yong zi fu 'hello'." exit 0 else echo "jin neng shi yong hello zi fu." fi [root@localhost ~]# sh 10.sh #屡次执行进行测试 qing shi yong zi fu 'hello'. [root@localhost ~]# sh 10.sh he jin neng shi yong hello zi fu. [root@localhost ~]# sh 10.sh hello hello,how are you ?
需求①:
一、判断 $1 是否为 hello,若是是的话,就显示 "Hello, how are you ?";
2.、若是没有加任何参数,就提示使用者必需要使用的参数下达法;
三、 而若是加入的参数不是 hello ,就提醒使用者仅能使用 hello 为参数。
[root@localhost ~]# vim 12.sh #编写脚本 #!/bin/bash case ${1} in "hello") echo "Hello, how are you ?" ;; "") echo "You MUST input parameters, ex> {${0} someword}" ;; *) echo "Usage ${0} {hello}" ;; esac [root@localhost ~]# sh 12.sh hello #屡次执行,进行测试 Hello, how are you ? [root@localhost ~]# sh 12.sh hell Usage 12.sh {hello} [root@localhost ~]# sh 12.sh You MUST input parameters, ex> {12.sh someword}
需求②:
让使用者可以输入 one, two, three ,而且将使用者的变量显示到屏幕上,若是不是 one, two, three 时,就告知使用者仅有这三种选择。
[root@localhost ~]# vim 13.sh #编写脚本 #!/bin/bash echo "qing shu ry one two three." read -p "qing shu ru:" shuzi case $shuzi in "one") echo "bian liang shi $shuzi" ;; "two") echo "bian liang shi $shuzi" ;; "three") echo "bian liang shi $shuzi" ;; *) echo "only neng shu ru one|two|three" ;; esac [root@localhost ~]# sh 13.sh #屡次执行,进行测试 qing shu ry one two three. qing shu ru:one #根据提示输入字符 bian liang shi one [root@localhost ~]# sh 13.sh #屡次执行,进行测试 qing shu ry one two three. qing shu ru:two #根据提示输入字符 bian liang shi two [root@localhost ~]# sh 13.sh #屡次执行,进行测试 qing shu ry one two three. qing shu ru:ddd #根据提示输入字符 only neng shu ru one|two|three
需求②:
让使用者可以输入 one, two, three ,而且将使用者的变量以大写的方式显示到屏幕上,若是不是 one, two, three 时,就告知使用者仅有这三种选择。
[root@localhost ~]# vim 14.sh function aaa(){ echo -n "this is " } case $1 in one) aaa echo "$1." | tr 'a-z' 'A-Z' ;; two) aaa echo "$1." | tr 'a-z' 'A-Z' ;; three) aaa echo "$1." | tr 'a-z' 'A-Z' ;; *) echo "qing shu ru {one|two|three}." ;; esac [root@localhost ~]# sh 14.sh #执行进行测试 qing shu ru {one|two|three}. [root@localhost ~]# sh 14.sh one #再次执行 this is ONE.
关于function函数的解释举例:
假以下达:“ sh show123-2.sh one ” 这表示在 脚本内的 $1 为 "one" 这个字串。可是在 printit()内的 $1 则与这个 one 无关。
以下:
[root@localhost ~]# vim 15.sh #!/bin/bash function printit(){ echo "Your choice is ${1}" } case ${1} in "one") printit 1 11 ;; "two") printit 2 22 ;; "three") printit 3 33 ;; *) echo "Usage ${0} {one|two|three}" ;; esac [root@localhost ~]# sh 15.sh one #屡次执行进行测试,以便查看输出的$1是哪里的值 Your choice is 1 [root@localhost ~]# sh 15.sh two Your choice is 2 #若将下面的变量改成$2,那么将会输出十一、2二、33等,发现这里的${变量}是引用的哪里的了么? function printit(){ echo "Your choice is ${2}" } #自行测试吧!
需求①——while语句
假设我要让使用者输入 yes 或者是 YES 才结束程序的执行,不然就一直进行告知使用者输入字串。
[root@localhost ~]# vim 16.sh #编写脚本 #!/bin/bash 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." [root@localhost ~]# sh 16.sh #执行脚本测试 Please input yes/YES to stop this program: yes OK! you input the correct answer. [root@localhost ~]# sh 16.sh #执行脚本测试 Please input yes/YES to stop this program: dd Please input yes/YES to stop this program: f Please input yes/YES to stop this program: YES OK! you input the correct answer.
需求②——until语句
与上面的需求同样,只是换成until语句。
[root@localhost ~]# vim 17.sh #编写脚本以下 #!/bin/bash until [ "${yn}" == "yes" -o "${yn}" == "YES" ] do read -p "qing shu ru 'yes' or 'YES':" yn done echo "OK!!!" [root@localhost ~]# sh 17.sh #屡次执行进行测试 qing shu ru 'yes' or 'YES':yes OK!!! [root@localhost ~]# sh 17.sh #屡次执行进行测试 qing shu ru 'yes' or 'YES':df qing shu ru 'yes' or 'YES':YES OK!!! #不难发现,until与while正好相反,until是某个测试条件成立,则不循环; #while是若是某个测试条件成立,则循环
需求③
求1到100的累积相加的和。
这个题目仍是比较经典又简单的,以下(实现的方法有不少,自行研究吧):
方法1:
[root@localhost ~]# vim 18.sh #编辑脚本 #!/bin/bash i=0 sum=0 while [ ${i} -lt 100 ] do i=$(( ${i}+1 )) sum=$(( ${sum}+${i} )) done echo "1+2+3+4....+100 de jie guo shi ${sum}." [root@localhost ~]# sh 18.sh #执行脚本 1+2+3+4....+100 de jie guo shi 5050. #5050就是结果
方法2:
[root@localhost ~]# vim 18.sh #脚本内容以下 #!/bin/bash i=0 while [ ${i} -le 100 ] do sum=$(( ${sum}+${i} )) let i++ done echo "1+2+3+4....+100 de jie guo shi ${sum}." [root@localhost ~]# sh 18.sh #执行脚本 1+2+3+4....+100 de jie guo shi 5050.
方法3(比前两种方式更加智能些,能够以交互式的方式,指定累积加到某个数字):
[root@localhost ~]# vim 23.sh #内容以下 #!/bin/bash read -p "Please input a number, I will count for 1+2+...+your_input:" nu s="0" for ((i=1;i<=${nu}; i++)) do s=$((${s}+${i})) done echo "the result of '1+2+...+${nu}' is ==> ${s}" [root@localhost ~]# sh 23.sh #执行 Please input a number, I will count for 1+2+...+your_input:100 #输入100 the result of '1+2+...+100' is ==> 5050 #执行后输出的结果 [root@localhost ~]# sh 23.sh #再执行 Please input a number, I will count for 1+2+...+your_input:99 #累积加到99 the result of '1+2+...+99' is ==> 4950 #执行后输出的结果
需求①
第一次循环时, $name 的内容为 内容1 ;
第二次循环时, $name的内容为 内容2 ;
第三次循环时, $name的内容为 内容3 ;
实现该需求有两种方法,若须要循环的内容较多,建议采用方法1。
方法1:
[root@localhost ~]# vim 19.sh #编写脚本文件 #!/bin/bash name=`cat /dongwu.txt` for names in ${name} do echo "There are ${names}s.... " done [root@localhost ~]# vim /dongwu.txt #编写脚本中指定的文件 dog cat elephant [root@localhost ~]# sh 19.sh #执行并查看是否将上面文件中的内容依次输出 There are dogs.... There are cats.... There are elephants....
方法2:
[root@localhost ~****]# vim 19.sh #编写脚本文件 #!/bin/bash for name in dogs cats elephants do echo "There are ${name}s.... " done [root@localhost ~]# sh 19.sh #执行脚本 There are dogss.... There are catss.... There are elephantss....
需求①
因为系统上面的各类账号都是写在/etc/passwd 内的第一个字段,那么怎么经过管线命令的cut捉出单纯的账号名称后,以id分别检查使用者的识别码与特殊参数呢?
脚本以下:
[root@localhost ~]# vim 20.sh #编写脚本 #!/bin/bash users=`cut -d ':' -f1 /etc/passwd` for username in ${users} do id ${username} done [root@localhost ~]# sh 20.sh #执行脚本 uid=0(root) gid=0(root) 组=0(root) uid=1(bin) gid=1(bin) 组=1(bin) uid=2(daemon) gid=2(daemon) 组=2(daemon) uid=3(adm) gid=4(adm) 组=4(adm) uid=4(lp) gid=7(lp) 组=7(lp) ........................#省略部份内容
需求1:
让用户输入某个目录文件名,而后自动找出某目录内的文件名的权限。
[root@localhost ~]# vim 22.sh #脚本内容以下 #!/bin/bash read -p "qing shu ru yi ge dirctory name:" dirname if [ "${dirname}" == "" -o ! -d "${dirname}" ] then echo "qing shu ru zheng que de dirctroy name." exit 1 fi filelist=`ls ${dirname}` for filename in ${filelist} do [ -r ${filename} ] && perm="read" [ -w ${filename} ] && perm="${perm}+write" [ -x ${filename} ] && perm="${perm}+exe" echo "${filename} de quan xian shi ${perm}." done [root@localhost ~]# sh 22.sh #执行脚本 qing shu ru yi ge dirctory name:/root #根据提示指定一个目录 10.sh de quan xian shi read+write. 11.sh de quan xian shi read+write. 12.sh de quan xian shi read+write. 13.sh de quan xian shi read+write. 14.sh de quan xian shi read+write. 15.sh de quan xian shi read+write. 16.sh de quan xian shi read+write. 17.sh de quan xian shi read+write. 18.sh de quan xian shi read+write. 19.sh de quan xian shi read+write. 1.sh de quan xian shi read+write+exe. ...................#省略部份内容
需求2:
搭配乱数来挑选(至关于抛硬币),这里好比说不知道要吃什么,执行如下脚原本决定吃什么。
[root@localhost ~]# vim 24.sh #内容以下,十一、22....假设为食物代号 #!/bin/bash eat[1]="11" eat[2]="22" eat[3]="33" eat[4]="44" eat[5]="55" eat[6]="66" eat[7]="77" eat[8]="88" eat[9]="99" eatnum=9 check=`echo "${RANDOM} % 10" | bc ` echo "your may eat ${eat[${check}]}" [root@localhost ~]# sh 24.sh #屡次执行,进行测试,会发现每次输出的结果都不同 your may eat 22 [root@localhost ~]# sh 24.sh your may eat 55 [root@localhost ~]# sh 24.sh your may eat 99
****用法:
[root@localhost ~]# sh -n 5.sh #若是语法没问题,则不会有任何输出 [root@localhost ~]# sh -n 5.sh #故意写错后,再测试 5.sh:行3: 未预期的符号 `do' 附近有语法错误 5.sh:行3: `do' [root@localhost ~]# sh -x 6.sh #将6.sh的执行过程都显示出来 + echo -e '\ncheng xu de wen jian ming shi 6.sh' cheng xu de wen jian ming shi 6.sh + echo -e '\nyi gong you 0 ge can shu.' yi gong you 0 ge can shu. + '[' 0 -lt 2 ']' + echo 'can shu tai shao le .' can shu tai shao le . + exit 0
———————— 本文至此结束,感谢阅读 ————————