shell脚本编程入门

什么是shell脚本,其实,shell脚本就是利用shell的功能所写的一个程序,这个程序是使用纯文本文件,将一些shell的语法与命令(包含外部命令)写在里面,搭配正则表达式、管道命令与数据流重定向等功能等这些命令的组合起来,以达到我们所想要的目的。


程序编程风格有两种:

过程式:以指令为中心,数据服务于指令。

对象式:以数据为中心,指令服务于数据。

过程式编程有 顺序执行、循环执行、选择执行。

shel程序就是过程式式的解释器,提供编程能力,然后解释执行。


shell脚本编写要注意一下事项:

1、命令的执行时由上而下、从左到右执行的。

2、命令、参数间的多个空白会被忽略。

3、如果读取到空白符(Enter),就尝试执行该命令。

4、如果一行内容太多可以用\[Enter]换行编写

5、"#"作为注释,任何加在#后面的数据将会被忽略为注释。


创建脚本

1、第一行必须用#!/bin/bash来声明这个脚本的shell名称

2、第二行一下可以用#来注释shell脚本的内容、功能、信息版本和作者和联系方式、建立日期、历史记录等良好习惯。有助于将来的拍错。 好记性不如烂笔头!

3、建议将一些重要的环境变量设置好,如此一来,就可以直接使用外部命令,而不必写绝对路径。

4、然后就将主要的程序写好输出

可以下用下面的命令来校验脚本

bash -n /path/to/some_script

检测脚本中的语法错误

bash -x /path/to/some_script

调试执行


bash变量

那么什么变量呢?额,简单的说变量就是用一个简单特定的字符来代替另一个比较复杂或者是容易变动的数据。

变量类型

变量类型的作用有

1、数据存储格式

2、参与的运算

3、表示的数据范围

变量的类型有:字符型、数值型。 数值型分为:整型和浮点型

变量对于编程语言来讲分为强类型和弱类型

强类型:定义变量时必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误

弱类型:无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用。 shell为弱类型

变量命名法则:

1、不能使程序中的保留字:例如if, for;

2、只能使用数字、字母及下划线,且不能以数字开头

3、见名知义

4、统一命名规则:驼峰命名法

变量与变量的内容以一个等号"="来连接

例如   first_Name=Alan

等号两边不能直接接空格符。若使用空格符可以用双引号即弱引用( " )或单引号即强引用( ' )将变量结合起来

当时双引号内的特殊符号如"$",可以保留原本的特性

var="lang is $LANG"  则echo显示为"lang is en_US.UTF-8 

单引号内的特殊符号仅为纯文本字符如

var='lang is $LANG'  则echo显示为"lang is $LANG"

可用转义字符"\"将特殊符号变成一般符号如($、\、空格符、!等)

根据变量的生效范围可分为

本地变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效

环境变量:生效范围为当前shell进程及其子进程

局部变量:生效范围为当前shell进程中某代码片断(通常指函数)

位置变量:$1, $2, …来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数

特殊变量:$?, $0, $*, $@, $#

本地变量赋值:name=‘value’,

可以使用引用value:

(1) 可以是直接字串; name=“root"

(2) 变量引用:name="$USER"

(3) 命令引用:name=`COMMAND`, name=$(COMMAND)

变量引用:${name}, $name 也可以累加

例如:  PATH=$PATH:~/bin: 累加~/bin到原有的PATH变量中

[root@localhost bin]# echo $PATH

/bin:/sbin:/usr/bin:/usr/sbin:usr/local/bin:/usr/local/sbin:/root/bin:/root/bin:

"":弱引用,其中的变量引用会被替换为变量值

'':强引用,其中的变量引用不会被替换为变量值,而保持原字符串

单引号和双引号最大不同之处在于双引号仍然可以保有变量的内容,但单引号内仅能是一般字符,而不会有特殊符号。

显示已定义的所有变量(包括环境变量):set

删除变量:unset name

环境变量

变量声明、赋值:

export name=VALUE

export也可以把本地变量转换环境变量

declare -x name=VALUE

变量引用:$name, ${name}

显示所有环境变量:

export

env

printenv

删除:unset name

bash有许多内建的环境变量:PATH, SHELL, HOME等用大写字母来定义环境变量。

只读变量:只能声时,但不能修改和删除

readonlyname

declare -r name

位置变量:在脚本代码中调用通过命令行传递给脚本的参数

$1, $2, …:对应第1、第2等参数,shift [n]换位置

$0: 命令本身

$*: 传递给脚本的所有参数,全部参数合为一个字符串

$@: 传递给脚本的所有参数,每个参数为独立字符串

$#: 传递给脚本的参数的个数

$@ $* 只在被双引号包起来的时候才会有差异

bash中的算术运算:help let

+, -, *, /, %取模(取余), **(乘方)

实现算术运算:

(1) let var=算术表达式

(2) var=$[算术表达式]

(3) var=$((算术表达式))

(4) var=$(expr arg1 arg2 arg3 …)

(5) declare –ivar= 数值

(6) echo ‘算术表达式’ | bc

增强型赋值:

+=, -=, *=, /=, %=

let varOPERvalue

例如:let count+=3

自加3后自赋值

自增,自减:

let var+=1

let var++

let var-=1

let var–

逻辑运算又称布尔运算 布尔用数学方法研究逻辑问题,成功地建立了逻辑演算。他用等式表示判断,把推理看作等式的变换。

这种变换的有效性不依赖人们对符号的解释,只依赖于符号的组合规律 。 true作1 false作0 与运算用& 或运算用||

与运算:

1 && 1 = 1 真

1 && 0 = 0 假

0 && 1 = 0 假

0 && 0 = 0 假

或运算:

1 || 1 = 1 真

1 || 0 = 1 真

0 || 0 = 1 真

0 || 0 = 0 假

非:!

! 1 = 0

! 0 = 1

短路运算:

短路与:

第一个为0,结果必定为0;

第一个为1,第二个必须要参与运算;

短路或:

第一个为1,结果必定为1;

第一个为0,第二个必须要参与运算;

异或:^

异或的两个值,相同为假,不同为真

进程使用退出状态来报告成功或失败

0 代表成功,1-255代表失败

$? 变量保存最近的命令退出状态

例如:

ping-c1-W1hostdown&>/dev/null

echo$?

bash自定义退出状态码

exit [n]:自定义退出状态码;

注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

判断某需求是否满足,需要由测试机制来实现;

专用的测试表达式需要由测试命令辅助完成测试过程;

评估布尔声明,以便用在条件性执行中

•若真,则返回0

•若假,则返回1

测试命令:

•test EXPRESSION

•[ EXPRESSION ]

•[[ EXPRESSION ]]

注意:EXPRESSION前后必须有空白字符

根据退出状态而定,命令可以有条件地运行

&& 代表条件性的AND THEN

|| 代表条件性的OR ELSE

例如:ls /dev && echo "This is device file"

     ls /tmp/cpwd|| mkdir /tmp/cpwd

 ls /dev/abc && echo "exist" || echo "no exist"

test命令是shell环境中测试条件表达式的实用工具

-b<文件>:如果文件为一个块特殊文件,则为真;

-c<文件>:如果文件为一个字符特殊文件,则为真;

-d<文件>:如果文件为一个目录,则为真;(常用)

-e<文件>:如果文件存在,则为真;(常用)

-f<文件>:如果文件为一个普通文件,则为真;(常用)

-g<文件>:如果设置了文件的SGID位,则为真;

-G<文件>:如果文件存在且归该组所有,则为真;

-k<文件>:如果设置了文件的粘着位,则为真;

-O<文件>:如果文件存在并且归该用户所有,则为真;

-p<文件>:如果文件为一个命名管道,则为真;

-r<文件>:如果文件可读,则为真;

-s<文件>:如果文件的长度不为零,则为真;

-S<文件>:如果文件为一个套接字特殊文件,则为真;

-u<文件>:如果设置了文件的SUID位,则为真;

-w<文件>:如果文件可写,则为真;

-x<文件>:如果文件可执行,则为真。

两种文件之间的比较 如 test file1 -nt file2

-nt file1 -nt file2 判断file1是否比file2新(newer than)

-ot file1 -ot file2 判断file1是否比file2旧(older than)

-er file1 -er file2 判断file1和file2为同一文件 (inode相同的文件)

两个整数之间的判断,例如 test file -eq file1

-eq 两数值相等(equal)

-ne 两数值不相等(not equal)

-gt file1大于file2(greater than)

-lt file1小于fiel2(less than)

-ge file1大于等于file2(greater than or equal)

-le file1小于等于file2(less than or equal)

判断字符串的数据

字符串测试:

==:是否等于;

>: ascii码是否大于ascii码

<: 是否小于

!=: 是否不等于

=~: 左侧字符串是否能够被右侧的PATTERN所匹配

注意: 此表达式一般用于[[ ]]中;

test -z string  判断字符串是否为0,若string为空字符串,则为真

test -n string  判断字符串是否为非0,若string为空字符串,则为假

组合测试条件

第一种方式:

COMMAND1 && COMMAND2 并且

COMMAND1 || COMMAND2 或者

! COMMAND 非

如:[ -e FILE ] && [ -r FILE ]

第二种方式:

EXPRESSION1 -a EXPRESSION2 并且

EXPRESSION1 -o EXPRESSION2 或者

! EXPRESSION

必须使用测试命令进行;

[ -z “$HOSTNAME” -o $HOSTNAME "=="localhost.localdomain" ] && hsotname.alan

[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab

read命令从键盘读取变量的值,通常用在shell脚本中与用户进行交互的场合。该命令可以一次读取多个变量的值,变量和输入的值都需要使用空格隔开。在read命令后面,如果没有指定变量名,读取的数据将被自动赋值给特定的变量REPLY

-p:指定读取值时的提示符;
-t:指定读取值时等待的时间(秒)。

read -p “Enter a filename:“ FILE

作业

1、编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小。

[root@localhost work]# cat systeminfo.sh 
#!/bin/bash
#
#编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,
包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小。
I_p=$(ifconfig|grep -A 1 '^e.*[^[:space:]]\+'|tr -s ' '|cut -d' ' -f3|tr -sc [[:digit:].] ' ')
C_pu=$(lscpu|grep 'Model name'|tr -s ' '|cut -d' ' -f3-)
M_em=$(grep 'MemTotal' /proc/meminfo)
H_ard=$(fdisk -l|grep '/dev/sda\>'|tr -s ' '|cut -d' ' -f3-4)
echo -e  "hostname:\033[31m ${hostname} \033[0m"
echo -e  "ipaddress is:\033[31m${I_p} \033[0m"
echo -e "OS is:\033[31m$(cat /etc/redhat-release)\033[0m"
echo -e "kernet is:\033[31m$(uname -r)\033[0m"
echo -e "CPU tpye is:\033[31m${C_pu}\033[0m"
echo -e "Mem size is\033[31m${M_em}\033[0m"
echo -e "hardwqre size is:\033[31m${H_ard}\033[0m"
[root@localhost work]# ./systeminfo.sh 
hostname:  
ipaddress is: 10.1.36.6 192.168.200.6  
OS is:CentOS release 6.8 (Final)
kernet is:2.6.32-642.el6.x86_64
CPU tpye is:Intel(R) Celeron(R) CPU N2940 @ 1.83GHz
Mem size isMemTotal:        1906276 kB
hardwqre size is:214.7 GB

2、编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcYYYY-mm-dd中

#!/bin/bash
#编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcYYYY-mm-dd中
back_up=$(cp -r /etc /root/etc`date +%F`)
echo -e "backup /etc directory:\033[31m${back_up}\033[0m"
[root@localhost work]# ./backup.sh #脚本执行
backup /etc directory:
[root@localhost work]# ll -d /etc/ /root/etc2016-08-14 #查看备份是否成功
drwxr-xr-x. 102 root root 12288 Aug 16 13:33 /etc/
drwxr-xr-x  102 root root 12288 Aug 14 19:36 /root/etc2016-08-14

3、编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值

[root@localhost work]# cat disk.sh 
#!/bin/bash
#
#编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值
disk_d=$(df |tr -s ' '|cut -d" " -f5|tr -d "%"|sort -n|tail -1)
echo "disk:${disk_d}"
[root@localhost work]# ./disk.sh #脚本执行
disk:22

4、编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序

[root@localhost work]# cat link.sh 
#!/bin/bash
#编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序
L_ink=$(netstat -nt|tr -s ":" ' '|cut -d" " -f4|grep '[[:digit:].]'|sort -nr|uniq -c)
echo "ipddress is:${L_ink}"
[root@localhost work]# ./link.sh #脚本执行
ipddress is:      2 192.168.200.6

5、写一个脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的ID之和

[root@localhost work]# cat sumid.sh 
#!/bin/bash
#写一个脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的ID之和
u_id1=$(head -10 /etc/passwd|tail -1|cut -d: -f3)
u_id2=$(head -20 /etc/passwd|tail -1|cut -d: -f3)
let sum=$u_id1+$u_id2
echo "$sum"
[root@localhost work]# ./sumid.sh #脚本执行结果
42

6、写一个脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和

[root@localhost work]# cat sumspace.sh 
#!/bin/bash
#写一个脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和
space1=$(grep "^[[:space:]]*$" $1 |wc -l) 
space2=$(grep "^[[:space:]]*$" $2 |wc -l)
let space=$space1+$space2
echo "$space"
[root@localhost work]# ./sumspace.sh /etc/fstab /etc/rc.d/init.d/functions#执行脚本
107

7、写一个脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件

[root@localhost work]# cat sumfile.sh 
#!/bin/bash
#写一个脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件
one=`ls -A /etc|wc -l`
two=`ls -A /var|wc -l`
three=`ls -A /usr|wc -l`
let all=$one+$two+$three
echo "all line is$all"
[root@localhost work]# ./sumfile.sh #脚本执行
all line is264

7、写一个脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数

[root@localhost work]# cat argsnum.sh 
#!/bin/bash
#写一个脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,
#则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,
#则显示第一个参数所指向的文件中的空白行数
rgum=`[ $# -le 1 ] && echo "At least one  path" && exit 0 || grep '^[[:space:]]*$' $1 |wc -l`
echo "$rgum"
[root@localhost work]# sh argsnum.sh /etc/fstab #一个参数
At least one  path
[root@localhost work]# sh argsnum.sh /etc/fstab /etc/passwd #2个参数
1

原创文章,作者:ladsdm,如若转载,请注明出处:http://www.178linux.com/36561

(0)
上一篇 2016-08-18 10:10
下一篇 2016-08-18 10:10

相关推荐

  • 用户和组管理

    Linux用户和用户组管理   Linux是个多用户多任务的分时操作系统,所有要使用系统资源的用户必须向系统管理员申请一个账号,然后以这个身份进入系统。用户登陆系统是也是一种验证方式,系统通过用户的UID(Username IDentification)这种机制来识别用户的身份和权限。每个用户账号都是唯一的用户名和用户口令。用户在登陆时键入正确的用…

    Linux干货 2016-08-07
  • 如何修复Ubuntu 12.04上时间不正确的问题

    大家好: 今天跟大家分享下如何修复ubuntu 12.04上时间不正常的问题。 1–首先打date查看系统的时间是否正常 martell@cnux10:~/sistes/sha-mmb-o2o2o$ date  Thu Dec  1 09:15:47 UTC 2016 martell@cnux10:~/sistes/sha-m…

    Linux干货 2016-12-04
  • MBR详解

    前言:     话说,现在买电脑如果预装win8以上的系统,基本上都是GPT。想当年博主买的电脑预装的win8磁盘分区样式就是GPT,而且貌似如果想把win8换win7就得把GPT改成MPR。虽然会在最后提到GPT,不过本文还是主要讲解MBR,并通过实验验证。 机械硬盘: 主引导记录(Master Boot Record,缩写:MBR),…

    Linux干货 2016-11-14
  • Centos 6 –grub legacy及grub修复

    一、CentOS 6 grub legacy:     1.启动流程:             POST –> Boot Sequence(BIOS) –> Boo…

    Linux干货 2016-09-21
  • 第六周练习

    请详细总结vim编辑器的使用并完成以下练习题 1、复制/etc/rc.d/rc.sysinit文件至/tmp目录,将/tmp/rc.sysinit文件中的以至少一个空白字符开头的行的行首加#; 1.[root – www ~]#>cp /etc/rc.d/rc.sysinit /tmp/2.[root – www ~]#>vi /tmp…

    Linux干货 2016-12-11
  • socket编程原理

    1、问题的引入 1) 普通的I/O操作过程: UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-read-close)。在一个用户进程进行I/O操作时,它首先调用“打开”获得对指定文件或设备的使用权,并返回称为文件描述符的整型数,以描述用户在打开的文件或设备上进行I/O操作的进程。然…

    Linux干货 2015-04-10