linux shell脚本基础教程

shellScript介绍

Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。

Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,它和 QQ、迅雷、Firefox 等其它软件没有什么区别。然而 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux。
在 Shell 中输入的命令,有一部分是 Shell 本身自带的,这叫做内置命令;有一部分是其它的应用程序(一个程序就是一个命令),这叫做外部命令。

Shell 本身支持的命令并不多,功能也有限,但是 Shell 可以调用其他的程序,每个程序就是一个命令,这使得 Shell 命令的数量可以无限扩展,其结果就是 Shell 的功能非常强大,完全能够胜任 Linux 的日常管理工作,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。

更加惊讶的是,Shell 还可以让多个外部程序发生连接,在它们之间很方便地传递数据,也就是把一个程序的输出结果传递给另一个程序作为输入。
大家所说的 Shell 强大,并不是 Shell 本身功能丰富,而是它擅长使用和组织其他的程序。Shell 就是一个领导者,这正是 Shell 的魅力所在。
可以将 Shell 在整个 Linux 系统中的地位描述成下图所示的样子。注意“用户”和“其它应用程序”是通过虚线连接的,因为用户启动 Linux 后直接面对的是 Shell,通过 Shell 才能运行其它的应用程序。

image.png

Shell 也支持编程

Shell 并不是简单的堆砌命令,我们还可以在 Shell 中编程,这和使用 C++、C#、Java、Python 等常见的编程语言并没有什么两样。

Shell 虽然没有 C++、Java、Python 等强大,但也支持了基本的编程元素,例如:
if...else 选择结构,case...in 开关语句,for、while、until 循环;
变量、数组、字符串、注释、加减乘除、逻辑运算等概念;
函数,包括用户自定义的函数和内置函数(例如 printf、export、eval 等)。

站在这个角度讲,Shell 也是一种编程语言,它的编译器(解释器)是 Shell 这个程序。我们平时所说的 Shell,有时候是指连接用户和内核的这个程序,有时候又是指 Shell 编程。

Shell 主要用来开发一些实用的、自动化的小工具,而不是用来开发具有复杂业务逻辑的中大型软件,例如检测计算机的硬件参数、搭建 Web 运行环境、日志分析等,Shell 都非常合适。

使用 Shell 的熟练程度反映了用户对 Linux 的掌握程度,运维工程师、网络管理员、程序员都应该学习 Shell。

尤其是 Linux 运维工程师,Shell 更是必不可少的,是必须掌握的技能,它使得我们能够自动化地管理服务器集群,否则你就得一个一个地登录所有的服务器,对每一台服务器都进行相同的设置,而这些服务器可能有成百上千之多,会浪费大量的时间在重复性的工作上。

Shell 是一种脚本语言

任何代码最终都要被“翻译”成二进制的形式才能在计算机中执行。

有的编程语言,如 C/C++、Pascal、Go语言、汇编等,必须在程序运行之前将所有代码都翻译成二进制形式,也就是生成可执行文件,用户拿到的是最终生成的可执行文件,看不到源码。

这个过程叫做编译(Compile),这样的编程语言叫做编译型语言,完成编译过程的软件叫做编译器(Compiler)。

而有的编程语言,如 Shell、JavaScript、Python、PHP等,需要一边执行一边翻译,不会生成任何可执行文件,用户必须拿到源码才能运行程序。程序运行后会即时翻译,翻译完一部分执行一部分,不用等到所有代码都翻译完。

这个过程叫做解释,这样的编程语言叫做解释型语言或者脚本语言(Script),完成解释过程的软件叫做解释器。

编译型语言的优点是执行速度快、对硬件要求低、保密性好,适合开发操作系统、大型应用程序、数据库等。

脚本语言的优点是使用灵活、部署容易、跨平台性好,非常适合 Web 开发以及小工具的制作。

Shell 就是一种脚本语言,我们编写完源码后不用编译,直接运行源码即可。

shell script 上手程序

test命令

关于linux shell 基础指令可以查看:
https://man.linuxde.net/sub/Shell内建命令

下面例子是判断文件类型和文件权限的:

#!/bin/bash
echo "请输入文件名称,并且判断当前文件名称是否存在,和文件权限"
read -p "\n输入文件名称:" filename
test -z ${filename} && echo "输入文件名称为空字符串" && exit 0
test ! -e ${filename} && echo "当前文件不存在" && exit 0
test -f ${filename} && filetype="regular file"
test -d ${filename} && filetype="diretory file"
test -r ${filename} && perm="readable"
test -w ${filename} && perm="${perm} wriable"
test -x ${filename} && perm="${perm} executable"
echo "the file name is ${filename}"
echo "the perssion is ${perm}"
[carver@master script]$ sh test2.sh 
请输入文件名称,并且判断当前文件名称是否存在,和文件权限
\n输入文件名称:sayYourName.sh
the file name is sayYourName.sh
the perssion is readable wriable

其中上面会涉及一个比较重要命令test,而test主要验证文件或者相关属性,在平时运维开发中经常用到test验证属性:关于linux test 标志判断可以认真查看如下连接:
Shell test 命令 https://www.runoob.com/linux/linux-shell-test.html

利用判断符号 [ ]

[ ]通常用于判断[ $index!=5 ] [ -z str ],需要注意的是:

  • 中括号两边需要预留空格
  • 中括号变量要用双引号括起来
  • 中括号常量最好用单引号或者中括号括起来
    创建名称test4.sh的脚本
#!/bin/bash
read -p "please input the user's choice !" choice
[ $choice == "Y" -o $choice == "y" ] && echo "user input y/Y"
[ $choice == "N" -o $choice == "n" ] && echo "user input n/N"
[carver@master script]$ sh test4.sh 
please input the user's choice !y
user input y/Y
shell 默认变量 $0\ $1 等

/path/to/scriptname op1 op2 op3
$0 $1 $2 $3
$n:表示的是输出命令的分割 平时会经常应用到的一些命令就会用到n去验证,比如redis-cli -p 127.0.0.1 -h 6379 就是根据 \n的变量就行验证

除此之外,还有一些比较常见的命令如下:
$#:代表后接的参数个数 比如上面命令 /path/to/scriptname op1 op2 op3 $# 表示的是3,执行命令后面接3个参数
$@: 代表"$1","$2","$3"(双引号),此命令和$*不同的:是 $*表示的是"$1 $2 $3"一个字符串,而$@:表示的是独立变量

#!/bin/bash
echo "the application accout is  $1"
echo "the application password is $2"

[ "$#" -eq 2 ] && echo "输入正确"
for temp in $@ ;do
echo ${temp}
done
echo ${temp}

[carver@master script]$ sh test5.sh 11 22
the application accout is  11
the application password is 22
输入正确
11
22
11 22

条件判断式

利用if ..then
if...then结构:
if;then
elif;then
else
fi

#/bin/bsah
if [ "$1" == "user1" ]; then
echo “当前登录账户为user1,登录正确”
elif [ "$1" == "user2" ]; then
echo "当前登录账号为user2,登录正确"
else echo “登录失败”
fi
[carver@master script]$ sh test6.sh 
“登录失败”
[carver@master script]$ vim test6.sh user1
2 files to edit
[carver@master script]$ sh test6.sh user1
“当前登录账户为user1,登录正确”

case $变量名称 in "第一个变量内容");;
case ) ;;
case ) ;;
esac
利用case...esac

#!/bin/bash
case $1 in "uesr1") echo "$1 is user1 "  ;;
        "user2") echo "$1 is user2" ;;
        *) echo "Usage $0 {hello} " ;;
esac
[carver@master script]$ sh test7.sh user2
user2 is user2

利用function功能
无参类型function methond()
有参类型 function methond(),其中参数可以用 $1 $2 $3 来代替参数,但是这个$n与shell 中$n 是不同的,下面以例子说明

function printit () {
echo -n "your choice is $1"
}
case $1 in "one") printit one;
        ;;
     "two") printit two;
        ;;
     "three") printit three;
        ;;
     *) echo "Usage $0 {one|two|three}"
esac

[carver@master script]$ sh test8.sh one
your choice is one

循环功能
while do done

while [ condition ]
do
程序段落
done

util [ condition ]
do
程序段落
done

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

ex:我们工作中就会经常遇到要检测网络通畅问题,比如 某个项目的网段是198.168.1.1~192.168.1.100 ,需要检测其中的网络状态。

network="192.168.137.1"
for sitenu in $(seq 1 200)
do
        ping -c 1 -w 10 ${network}.${sitenu} &> messagelog
        if [ "$?" -eq 0 ];
        then echo "server ${network}.${sitenu} is up "
        else echo "server ${network}.${sitenu} is down"
   fi
done
[carver@master script]$ sh test9.sh 
server 192.168.137.1.1 is down
server 192.168.137.1.2 is down
server 192.168.137.1.3 is down
server 192.168.137.1.4 is down
server 192.168.137.1.5 is down
server 192.168.137.1.6 is down
server 192.168.137.1.7 is down
server 192.168.137.1.8 is down
server 192.168.137.1.9 is down
server 192.168.137.1.10 is down
server 192.168.137.1.11 is down
server 192.168.137.1.12 is down
server 192.168.137.1.13 is down
server 192.168.137.1.14 is down
server 192.168.137.1.15 is down
server 192.168.137.1.16 is down
server 192.168.137.1.17 is down
server 192.168.137.1.18 is down
server 192.168.137.1.19 is down
server 192.168.137.1.20 is down
server 192.168.137.1.21 is down

shellScript 追踪调试

sh -[-nvx] script.sh
-n 不要执行script,仅查询语法问题
-v 在执行script之前,先将script 语句输出到屏幕
-x 将使用到的script 内容显示到屏幕上,是很有用的参数