Linux学习笔记:Shell脚本学习

一、什么是Shell Scripts

    利用Shell的功能所写的一个程序,使用纯文本文件,将一些shell的语法与指令(含外部指令)写在里面,搭配正则表达式、管线命令与数据流重导向功能,以达到我们所想要的处理目的

    就像是DOS年代的批处理文件(.bat)

    为什么要学习:

        自动化管理的重要依据

        追踪和管理系统的重要工作

        简单入侵检测功能

        连续指令单一化

        简易的数据处理

        跨平台支持与学习历程较短

    注意事项

         Linux学习笔记:Shell脚本学习_第1张图片

    几种执行的方法

        Linux学习笔记:Shell脚本学习_第2张图片

        当使用sh shell.sh 运行时,只要有r的权限即可被执行

    撰写脚本的良好习惯

        在开头处记录:功能、版本信息、作者与联络方式、版权的宣告方式、History、脚本内较特殊的指令(使用绝对路径方式来下达的)、运行时需要的环境变量预先宣告与设定

二、简单的shell script练习

    1、练习代码

(1)输入姓、名,完整输出

#!/bin/bash
#Program:
#       show full name
#History
#2018.1.29      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH 

read -p "Please input your first name: " firstname
read -p "Please input your last name: " lastname
echo -e "\nYour full name is: ${firstname} ${lastname}"

 

[gyy@localhost bin]$ chmod 777 showname.sh 
[gyy@localhost bin]$ ./showname.sh 
Please input your first name: G
Please input your last name: YY

Your full name is: G YY

(2)随日期变化进行文件建立

#!/bin/bash
#Program:
#       Program creates three files,which named by user's input and date command
#History
#2018.1.29      GYY     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}"
[gyy@localhost bin]$ chmod 777 create_3_filename.sh 
[gyy@localhost bin]$ ./create_3_filename.sh 
“I will use ’touch‘ command to create 3 files”
Please input your filename: GYY
[gyy@localhost bin]$ ls | grep GYY
GYY20190126
GYY20190127
GYY20190128

(3)两数相乘

#!/bin/bash
#Program:
#       User inputs 2 integer numbers;program will cross these two numbers.
#History
#2018.1.29      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH 

echo -e "You should input 2 numbers, I will mutiplying them !\n"
read -p "first number : " firstnum
read -p "secong number : " secondnum
total=$((${firstnum}*${secondnum}))
echo -e "\nThe result of ${firstnum} * ${second} is ${total}"
[gyy@localhost bin]$ chmod 777 multiplying.sh 
[gyy@localhost bin]$ ./multiplying.sh 
You should input 2 numbers, I will mutiplying them !

first number : 4
secong number : 5

The result of 4 *  is 20

(4)数值运算:透过bc计算pi

#!/bin/bash
#Program:
#       User input a scale number to calculate pi number.
#History
#2018.1.29      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH 

echo -e "This program will calculate pi value. \n"
echo -e "You should input a float numer to calculate pi value.\n"
read -p "The scale numbher (10~10000)? " checking
num=${checking:-"10"}
echo -e "Starting calcuate pi value. Be patient."
time echo "scale=${num}; 4*a(1)" | bc -lq
[gyy@localhost bin]$ chmod 777 cal_pi.sh 
[gyy@localhost bin]$ ./cal_pi.sh 
This program will calculate pi value. 

You should input a float numer to calculate pi value.

The scale numbher (10~10000)? 500
Starting calcuate pi value. Be patient.
3.141592653589793238462643383279502884197169399375105820974944592307\
81640628620899862803482534211706798214808651328230664709384460955058\
22317253594081284811174502841027019385211055596446229489549303819644\
28810975665933446128475648233786783165271201909145648566923460348610\
45432664821339360726024914127372458700660631558817488152092096282925\
40917153643678925903600113305305488204665213841469519415116094330572\
70365759591953092186117381932611793105118548074462379962749567351885\
75272489122793818301194912

real	0m0.067s
user	0m0.065s
sys	0m0.003s

    2、script的执行方式差异(source,sh script,./script)

    (1)利用直接执行的方式来执行script

        利用直接指令或利用bash(或sh)来下达脚本,该script会使用一个新的bash环境来执行脚本内的指令,即script是在子程序的bash环境内执行的,当子程序完成后,在子程序内的各项变量或动作将会结束而不会传回到父程序中

    (2)利用source来执行脚本:在父程序中执行

        这样变量会传回到父程序

    因此,不注销系统而要让某些吸入~/.bashrc的设定生效时,需要使用 source ~/.bashrc 而不能使用bash ~/.bashrc

三、判断式

    test参数

    Linux学习笔记:Shell脚本学习_第3张图片

    Linux学习笔记:Shell脚本学习_第4张图片

    Linux学习笔记:Shell脚本学习_第5张图片

    

    练习代码:

    判断档名类型和权限

#!/bin/bash
#Program:
#       User input a filename ,program will check the flowing:
#       1.exist? 2.file/directory 3.file permissions
#History
#2018.1.29      GYY     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 filename's type and permission. \n\n"
read -p "Input a filename : " filename
test -z ${fliename} 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="regular 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 for you are : ${perm}"
[gyy@localhost ~]$ chmod 777 file_perm.sh 
[gyy@localhost ~]$ ./file_perm.sh 
Please input a filename,I will check filename's type and permission. 


Input a filename : /home/gyy
./file_perm.sh: line 13: test: echo: binary operator expected
The filename: /home/gyy is a directory
And the permissions for you are : readable writable executable

    利用判断符号[]

        []也可以进行数据的判断

        中括号的两端需要有空格符来分隔

        参数与test相同

        示例程序:使用[]进行判断

#!/bin/bash
#Program:
#       This program shows the user's choice
#History
#2018.1.29      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH 

read -p "Please input (Y/N): " yn
[ "${yn}" == "Y" -o "${yn}" == "y" ] && echo "OK,continue" && exit 0
[ "${yn}" == "N" -o "${yn}" == "n" ] && echo "OK,interrupt!" && exit 0
echo "I don't know what you choice is " && exit 0
[gyy@localhost bin]$ chmod 777 ans_yn.sh 
[gyy@localhost bin]$ ./ans_yn.sh 
Please input (Y/N): n
OK,interrupt!
[gyy@localhost bin]$ ./ans_yn.sh 
Please input (Y/N): y
OK,continue
[gyy@localhost bin]$ ./ans_yn.sh 
Please input (Y/N): g
I don't know what you choice is

     默认变数 

         

        示例程序:一个参数分析脚本

#!/bin/bash
#Program:
#       Program shows the script name,parameters
#History
#2018.1.29      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH 

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           ==> '$@'"
echo "The 1st parameter                 ==> ${1}"
echo "The 2nd parameter                 ==> ${2}"
[gyy@localhost bin]$ chmod 777 how_paras.sh 
[gyy@localhost bin]$ ./how_paras.sh aaa bbb ccc
The script name is    	 	==> ./how_paras.sh
Total parameter number is 	==> 3
Your whole parameter is		==> 'aaa bbb ccc'
The 1st parameter 			==> aaa
The 2nd parameter			==> bbb

    shift的作用

        shift后面接数字表示拿掉前面几个参数,默认拿掉一个

        示例程序:使用shift进行参数变量号码偏移

#!/bin/bash
#Program:
#       Program shows the effect of shift function.
#History
#2018.1.29      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH 

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           ==> '$@'"
[gyy@localhost bin]$ chmod 777 shift_paras.sh 
[gyy@localhost bin]$ ./shift_paras.sh aaa bbb ccc ddd eee fff ggg
Total parameter number is 	==> 7
Your whole parameter is 		==> 'aaa bbb ccc ddd eee fff ggg'
Total parameter number is 	==> 6
Your whole parameter is 		==> 'bbb ccc ddd eee fff ggg'
Total parameter number is 	==> 3
Your whole parameter is 		==> 'eee fff ggg'

四、条件判断式

    单层、简单条件判断式

        if [ 条件判断式 ]; then

            当条件判断式成立时,可以进行的指令工作内容

        fi   #将if反过来写,结束if

        可以使用 && 和 ||

    示例程序:使用if-then写yn判断

#!/bin/bash
#Program:
#       This program shows the user's choice
#2018.1.29      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH 

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 "OK,interrupt!"
        exit 0
fi
echo "I don't know what you choice is " && exit 0
[gyy@localhost bin]$ chmod 777 ans_yn-2.sh 
[gyy@localhost bin]$ ./ans_yn-2.sh 
Please input (Y/N): n
OK,interrupt!
[gyy@localhost bin]$ ./ans_yn-2.sh 
Please input (Y/N): y
OK,continue
[gyy@localhost bin]$ ./ans_yn-2.sh 
Please input (Y/N): g
I don't know what you choice is

    多重复杂条件判断式

        加上else

        还可以 elif [ 条件判断式二 ]; then

        常见的port与相关网络服务的关系

        Linux学习笔记:Shell脚本学习_第6张图片

        示例程序:网络端口侦测脚本

#!/bin/bash
#Program:
#       Using netstat and grep to detect WWW,SSH,FTP and Mail services.
#2018.1.29      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH 

echo "Now ,I will detect your Linux server's services!"
echo -e "The www, ftp, ssh, and mail(smtp) will be detect!\n"

testfile=/dev/shm/netstat_checking.txt
netstat -tuln > ${testfile}
testing=$(grep ":80" ${testfile})
if [ "${testing}" != "" ]; then
        echo "WWW is running in your system."
fi
testing=$(grep ":22" ${testfile})
if [ "${testing}" != "" ]; then
        echo "SSH is running in your system."
fi
testing=$(grep ":21" ${testfile})
if [ "${testing}" != "" ]; then
        echo "FTP is running in your system."
fi
testing=$(grep ":25" ${testfile})
if [ "${testing}" != "" ]; then
        echo "Mail is running in your system."
fi
[gyy@localhost bin]$ chmod 777 netstat.sh 
[gyy@localhost bin]$ ./netstat.sh 
Now ,I will detect your Linux server's services!
The www, ftp, ssh, and mail(smtp) will be detect!

SSH is running in your system.
Mail is running in your system.

    case…case判断

        Linux学习笔记:Shell脚本学习_第7张图片

        case $变量 in 当中的$变量大致有两种取得方式

            直接下达式(例如例程中的直接给${1})

            交互式(用户输入)

        /etc/init.d 中的很多启动服务就是用case…case的语句写出来的

        示例程序:case...case语句使用

#!/bin/bash
#Program:
#       This program shows "Hello World!" in your screen
#History:
#2019.1.28      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

case ${1} in
 "hello")
        echo "hello, how are you ?"
        ;;
 "")
        echo "You Must input parameters, ex> {${0} someword}"
        ;;
 *)
        echo "Usage ${0} {hello}"
        ;;
esac
[gyy@localhost bin]$ chmod 777 hello2.sh 
[gyy@localhost bin]$ ./hello2.sh 
You Must input parameters, ex> {./hello2.sh someword}
[gyy@localhost bin]$ ./hello2.sh hello
hello, how are you ?

    函数功能

        function也是拥有内建变量的,它的内变量与shell script很类似,函数名称为$0,后续接的变量依次为$1 $2

        示例程序:function功能练习

#!/bin/bash
#Program:
#       Use function to repeat information
#History:
#2019.1.28      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

function printit(){
        echo "Your choice is ${1}"
}

echo "This program will print your selection !"
case ${1} in
 "one")
        printit 1
        ;;
 "two")
        printit 2
        ;;
 "three")
        printit 3
        ;;
 *)
        echo "Usage ${0} {one|two|three}"
        ;;
esac
[gyy@localhost bin]$ chmod 777 show123.sh 
[gyy@localhost bin]$ ./show123.sh two
This program will print your selection !
Your choice is 2
[gyy@localhost bin]$ 

五、循环

     不定循环

        两种结构

        Linux学习笔记:Shell脚本学习_第8张图片

        Linux学习笔记:Shell脚本学习_第9张图片

        类比C前者while型 后者do…while型

        示例程序:计算1-100加和

#!/bin/bash
#Program:
#       Use loop to calculate "1+2+3+...+100"result
#History:
#2019.1.28      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

#while do done
s=0
i=0
while [ "${i}" != "100" ]
do
        i=$(($i+1))
        s=$(($s+$i))
done
echo "The result1 of '1+2+3+...+100' is ==> $s"

#until do done
s=0
i=0
until [ "${i}" == "100" ]
do
        i=$(($i+1))
        s=$(($s+$i))
done
echo "The result2 of '1+2+3+...+100' is ==> $s"
[gyy@localhost bin]$ chmod 777 cal_1_100.sh 
[gyy@localhost bin]$ ./cal_1_100.sh 
The result1 of '1+2+3+...+100' is ==> 5050
The result2 of '1+2+3+...+100' is ==> 5050

    for…do…done(固定循环)

        两种结构

        Linux学习笔记:Shell脚本学习_第10张图片

        Linux学习笔记:Shell脚本学习_第11张图片

        第一种类似于Python的for 第二种类似于C的for

        示例程序1:利用for抓取用户id

#!/bin/bash
#Program:
#       Use id,finger command to check system account's information.
#History:
#2019.1.28      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

users=$(cut -d ':' -f1 /etc/passwd)
for username in ${users}
do
        id ${username}
done
[gyy@localhost bin]$ chmod 777 userid.sh 
[gyy@localhost bin]$ ./userid.sh 
uid=0(root) gid=0(root) groups=0(root)
uid=1(bin) gid=1(bin) groups=1(bin)
uid=2(daemon) gid=2(daemon) groups=2(daemon)
uid=3(adm) gid=4(adm) groups=4(adm)
uid=4(lp) gid=7(lp) groups=7(lp)
uid=5(sync) gid=0(root) groups=0(root)
uid=6(shutdown) gid=0(root) groups=0(root)
uid=7(halt) gid=0(root) groups=0(root)
uid=8(mail) gid=12(mail) groups=12(mail)
uid=11(operator) gid=0(root) groups=0(root)
uid=12(games) gid=100(users) groups=100(users)
uid=14(ftp) gid=50(ftp) groups=50(ftp)
uid=99(nobody) gid=99(nobody) groups=99(nobody)
uid=192(systemd-network) gid=192(systemd-network) groups=192(systemd-network)
uid=81(dbus) gid=81(dbus) groups=81(dbus)
uid=999(polkitd) gid=998(polkitd) groups=998(polkitd)
uid=74(sshd) gid=74(sshd) groups=74(sshd)
uid=89(postfix) gid=89(postfix) groups=89(postfix),12(mail)
uid=1000(gyy) gid=1000(gyy) groups=1000(gyy)
uid=1001(user1) gid=1001(user1) groups=1001(user1)
uid=1002(git) gid=1002(git) groups=1002(git)
uid=998(nginx) gid=995(nginx) groups=995(nginx)
uid=27(mysql) gid=27(mysql) groups=27(mysql)

        示例程序2:使用for...do...done进行数值处理

#!/bin/bash
#Program:
#       Try do calculate 1+2+...+${your_input}
#History:
#2019.1.28      GYY     First release
PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

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}"
[gyy@localhost bin]$ chmod 777 cal_1_100-2.sh 
[gyy@localhost bin]$ ./cal_1_100-2.sh 
Please input a number, I will count for 1+2+...+your_input: 10
The result of '1+2+3+...+10' is ==> 55

六、追踪与debug

    Linux学习笔记:Shell脚本学习_第12张图片

    使用-x可以将指令的执行过程显示出来,如此可以判断程序具体执行到了哪一步

    示例:代码追踪

[gyy@localhost bin]$ sh -n cal_1_100-2.sh 
[gyy@localhost bin]$ sh -x cal_1_100-2.sh 
+ PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin:/home/gyy/bin
+ export PATH
+ read -p 'Please input a number, I will count for 1+2+...+your_input: ' nu
Please input a number, I will count for 1+2+...+your_input: 5
+ s=0
+ (( i=1 ))
+ (( i<=5 ))
+ s=1
+ (( i=i+1  ))
+ (( i<=5 ))
+ s=3
+ (( i=i+1  ))
+ (( i<=5 ))
+ s=6
+ (( i=i+1  ))
+ (( i<=5 ))
+ s=10
+ (( i=i+1  ))
+ (( i<=5 ))
+ s=15
+ (( i=i+1  ))
+ (( i<=5 ))
+ echo 'The result of '\''1+2+3+...+5'\'' is ==> 15'
The result of '1+2+3+...+5' is ==> 15

 

你可能感兴趣的:(Linux学习,Linux学习,Shell,Linux,嵌入式,脚本,编程)