shell脚本编程之一

shell脚本编程之一

shell脚本基础

shell脚本是包含一些命令或声明,并符合一定格式的文本文件

格式要求:首行shebang机制

#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl

shell脚本的用途有:

  • 自动化常用命令

  • 执行系统管理和故障排除

  • 常见简单的应用程序

  • 处理文本或文件

创建shell脚本

第一步:使用文本编辑器来创建文本文件

  • 第一行必须包括shell声明序列:#!

#!/bin/bash

添加注释

注释以#开头

  • 第二步:运行脚本

给予执行权限,在命令行指定脚本的绝对或相对路径

直接运行解释器,将脚本作为解释器程序的参数运行

shell脚本范例

#!/bin/bash
#author:root
#Version:1.0
#description:the script displays some information about your environment

echo "greentings.the date and tiem are $(date)"
echo "your working directory is :$(pwd)"

脚本调试

bash -n /path/to/some_script
检测脚本中的语法错误

bash -x /path/to/some_script
调试执行

变量

  • 变量:命名的内存空间

数据存储方式

字符:

数值:整形,浮点型

  • 变量:变量类型

作用:

1、数据存储格式

2、参与的运算

3、表示的数据范围

类型

字符

数值:整形、浮点型

编程语言的分类

强类型:Java、Python

弱类型:bash

变量命名法则:

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

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

3、见名知义

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

bash中变量的种类

根据变量的生效范围等标准

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

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

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

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

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

本地变量

变量赋值:name=‘value’,
可以使用引用value:
(1) 可以是直接字串; name=“root"
(2) 变量引用:name="$USER"
(3) 命令引用:name=`COMMAND`, name=$(COMMAND)
变量引用:${name}, $name
    "":弱引用,其中的变量引用会被替换为变量值
    '':强引用,其中的变量引用不会被替换为变量值,而保持原字符串
显示已定义的所有变量:set
删除变量:unset name


环境变量

变量声明、赋值:
    export name=VALUE
    declare -x name=VALUE
变量引用:$name, ${name}
显示所有环境变量:
    export
    env
    printenv
删除:unset name
bash有许多内建的环境变量:PATH, SHELL, USRE,UID, HISTSIZE, HOME, PWD, OLDPWD, HISTFILE, PS1


只读和位置变量

只读变量:只能声时,但不能修改和删除
    readonlyname
    declare -r name

位置变量:在脚本代码中调用通过命令行传递给脚本的参数
    $1, $2, ...:对应第1、第2等参数,shift [n]换位置
    $0: 命令本身
    $*: 传递给脚本的所有参数,全部参数合为一个字符串
    $@: 传递给脚本的所有参数,每个参数为独立字符串
    $#: 传递给脚本的参数的个数
    $@ $* 只在被双引号包起来的时候才会有差异

示例:判断给出的文件的行数
 linecount="$(wc-l $1| cut -d' ' -f1)"
 echo "$1 has $linecountlines."


算术运算

bash中的算术运算:help let
    +, -, *, /, %取模(取余), **(乘方)
    实现算术运算:
        (1) let var=算术表达式
        (2) var=$[算术表达式]
        (3) var=$((算术表达式))
        (4) var=$(expr arg1 arg2 arg3 ...)
        (5) declare –ivar= 数值
        (6) echo ‘算术表达式’ | bc
乘法符号有些场景中需要转要转义,如*
bash有内建的随机数生成器:$RANDOM(1-32767)
    echo $[$RANDOM%50] :0-49之间随机数

逻辑运算

true 0

false 1

短路运算:

短路与:

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

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

短路或:

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

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

聚集命令

两种聚集命令的方法:

复合式:date ; who | wc -l

命令会一个接一个地运行

子shell:(date ; who | wc -l) >> /tmp?trace

所有输出都被发送给单个stdout和stderr

退出状态

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

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

example

$ ping -c1 -w1 hostdown $> /dev/null

$ echo $?

退出状态吗

bash自定义退出状态码

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

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

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

条件测试

判断某需求是否满足,需要由测试机制来实现;
专用的测试表达式需要由测试命令辅助完成测试过程;

评估布尔声明,以便用在条件性执行中
    •若真,则返回0
    •若假,则返回1

测试命令:
    •test EXPRESSION
    •[ EXPRESSION ]
    •[[ EXPRESSION ]]
    注意:EXPRESSION前后必须有空白字符



根据退出状态而定,命令可以有条件地运行
    •&& 代表条件性的AND THEN
    •|| 代表条件性的OR ELSE

test命令

长格式的例子:
    $test "$A" == "$B" && echo"Stringsareequal"
    $test “$A” -eq “$B” && echo "Integersareequal"

简写格式的例子:
    $[ "$A" == "$B" ] && echo"Stringsareequal"
    $[ "$A" -eq "$B" ] && echo "Integersareequal"

bash的测试类型

数值测试

-gt: 是否大于;  
-ge: 是否大于等于;
-eq: 是否等于;
-ne: 是否不等于;
-lt: 是否小于;
-le: 是否小于等于;

字符串测试

==:是否等于;
>: ascii码是否大于ascii码
<: 是否小于
!=: 是否不等于
=~: 左侧字符串是否能够被右侧的PATTERN所匹配
注意: 此表达式一般用于[[ ]]中;
-z "STRING":字符串是否为空,空为真,不空为假
-n "STRING":字符串是否不空,不空为真,空为假
注意:用于字符串比较时的用到的操作数都应该使用引号

文件测试
存在性测试
    -a FILE:同-e
    -e FILE: 文件存在性测试,存在为真,否则为假;
存在性及类别测试
    -b FILE:是否存在且为块设备文件;
    -c FILE:是否存在且为字符设备文件;
    -d FILE:是否存在且为目录文件;
    -f FILE:是否存在且为普通文件;
    -h FILE 或-L FILE:存在且为符号链接文件;
    -p FILE:是否存在且为命名管道文件;
    -S FILE:是否存在且为套接字文件;
文件权限测试:
    -r FILE:是否存在且可读
    -w FILE: 是否存在且可写
    -x FILE: 是否存在且可执行
文件特殊权限测试:
    -g FILE:是否存在且拥有sgid权限;
    -u FILE:是否存在且拥有suid权限;
    -k FILE:是否存在且拥有sticky权限;
文件大小测试:
    -s FILE: 是否存在且非空;
文件是否打开:
    -t fd: fd表示文件描述符是否已经打开且与某终端相关
    -N FILE:文件自上一次被读取之后是否被修改过
    -O FILE:当前有效用户是否为文件属主
    -G FILE:当前有效用户是否为文件属组
双目测试:
    FILE1 -efFILE2: FILE1与FILE2是否指向同一个设备上的相同inode
    FILE1 -ntFILE2: FILE1是否新于FILE2;
    FILE1 -otFILE2: FILE1是否旧于FILE2;
组合条件测试
第一种方式:
    COMMAND1 && COMMAND2 并且
    COMMAND1 || COMMAND2 或者
    ! COMMAND 非
    如:[ -e FILE ] && [ -r FILE ]
第二种方式:
    EXPRESSION1 -a EXPRESSION2 并且
    EXPRESSION1 -o EXPRESSION2 或者
    ! EXPRESSION
必须使用测试命令进行;
    # [ -z “$HOSTNAME” -o $HOSTNAME "==\
    "localhost.localdomain" ] && hostname www.magedu.com
    # [ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab


附加:bash特殊变量$* $@详解

[root@centos7 sh]# cat arg1.sh 
./arg2.sh "$*"
echo ===================
./arg2.sh "$@"

[root@centos7 sh]# cat arg2.sh
echo 1st is "$1" 
echo 2st is "$2"
echo all args are is "$*"
echo number is "$#"


[root@centos7 sh]# arg1.sh openstack mysql marindb 
1st is openstack mysql marindb
2st is 
all args are is openstack mysql marindb
number is 1
===================
1st is openstack
2st is mysql
all args are is openstack mysql marindb
number is 3


重以上的实例中我们可以看到

$* 把所有的参数当做一个参数来输入
$@ 原来有几个参数,输出还是几个 


注:对于位置参数为$1 $2 $3... 当多个10的时候 我们采用 ${11} ${12} ... 这种方法表示即可

下面用几道练习题来加深印象

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

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

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

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

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

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

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

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

9、写一个脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”

10、chmod -rw /tmp/file1,编写脚本/root/bin/per.sh,判断当前用户对/tmp/fiile1文件是否不可读且不可写

附录参考:

第一题

#!/bin/bash

host_name=`hostname`
Ipv4_addr=`ifconfig | grep -A 1 '^e' | tail -1 | sed -r 's@inet (addr:)?(.*) (netmask|Bc).*@\2@' | tr -d ' '`
os_version=`cat /etc/redhat-release`
kernel_version=`uname -r`
CPU_type=`cat /proc/cpuinfo | grep "model name" | cut -d: -f2 | tr -d ' '`
mem_size=`cat /proc/meminfo | grep "MemT"| cut -d: -f2 | tr -d ' '`
disk_size=`fdisk -l /dev/sda | sed -rn "s@Disk /dev/sd[a-z]: (.*), .*, .*@\1@p"`

red="\033[31m"
end_color="\033[0m"

echo -e "${red}Current OS information$end_color"
echo "hostname is $host_name"
echo "ipaddr is $Ipv4_addr"
echo "OS version is $os_version"
echo "kernel version is $kernel_version"
echo "cpu type is $CPU_type"
echo "mem size is $mem_size"
echo "disk size is $disk_size"

第二题

#!/bin/bash

backup_file="/etc/"
cp -ar $backup_file /root/etc`date +%F`

第三题

#!/bin/bash

total=`df | sed -rn 's@/(dev/sd[a-z][0-9]+).* ([0-9]+)%.*@\1:\2@p' | sort -nr -t: -k2 | head -1`

max_diskuse_name=`echo $total | cut -d: -f1`
max_diskuse_number=`echo $total | cut -d: -f2`

echo "Max disk use name is $max_diskuse_name"
echo "IT use ${max_diskuse_number}%"
~

第四题

#!/bin/bash


links=`netstat -tn | grep "^tcp" | tr -s ' ' | cut -d' ' -f4 | cut -d: -f1 | sort | uniq -c | sort -r`

links_number=`echo $links | wc -l`
echo "links number is $links_number"
echo -e "they are\n$links"

第五题

#!/bin/bash

uid_10=`cat /etc/passwd | sed -n '10p' | cut -d: -f3`
uid_20=`cat /etc/passwd | sed -n '20p' | cut -d: -f3`

total=$[$uid_10+$uid_20]

echo "The 10st UID is $uid_10"
echo "The 20st UID is $uid_20"
echo "The sum of is $total"

第六题

#!/bin/bash

first_spacelines=`cat $1 | grep "^$" | wc -l`
second_spacelines=`cat $2 | grep "^$" | wc -l`

total=$[$first_spacelines+$second_spacelines]

echo "the 1st spacelines is $first_spacelines"
echo "the 2st spacelines is $second_spacelines"
echo "the sum of id $total"
~

第七题

#!/bin/bash

total=`ls -A /etc/ /var/ /usr | wc -l`
echo "the sum of is $total"
~

第八题

#!/bin/bash

[ $# -lt 1 ] && echo "at least one arg" && exit || cat $1 | grep "^$" | wc -l

第九题

#!/bin/bash

ping -c1 -W1 $1 &> /dev/null && echo "$1 is up" || echo "$1 is down"

第十题

#!/bin/bash

[ ! -r /tmp/file1 -a ! -w /tmp/file1 ] && echo "not write and not read" || echo "match fail"

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

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

相关推荐

  • ☞keepalived

    keepalived 高可用集群 VRRP协议 keepalived 安装keepalived 主要文件 配置文件说明 【一】测试keepalived基本功能 单主模型示例 双主模型示例 通知脚本示例 【二】单主模型高可用DR类型LVS集群 配置keepalived主机 Real Server配置 测试结果 【三】双主模型高可用DR类型LVS集群 配置kee…

    Linux干货 2016-11-01
  • 第六周博客作业

                   1、复制/etc/rc.d/rc.sysinit文件至/tmp目录,将/tmp/rc.sysinit文件中的以至少一个空白字符开头的行的行首加#; %s@^[[:space:]]\+[^[:…

    Linux干货 2016-12-05
  • 系统管理中的三大利刃(htop glances dstat)

    工欲善事情,必先利其器,生产环境中的服务器在处理请求并生成回应数据的时间主要消耗在服务器端,包括了众多的环节,如何全面了解我们linux服务器的CPU使用率、使用时间、内存占用比例、磁盘IO数据、网络相关数据等等众多指标,保证我们的linux服务器顺利完成每一个请求,怎能没有几个趁手的利刃,而今天就让我们见识一下系统管理中三大利刃。 相传一把三尺长的软剑,叫…

    Linux干货 2015-11-18
  • 虚拟化网络之OpenvSwitch(一)

    一、OpenvSwitch介绍  OpenvSwitch简称OVS,正如其官网(http://openvswitch.org/)所述,OVS是一个高质量、多层的虚拟交换软件,即虚拟交换机。它的目的是通过编程扩展支持大规模网络自动化,同时还支持标准的管理接口和协议(例如:NetFlow,sFlow,IPFIX,RSPAN, CLI, LAC…

    Linux干货 2016-03-27
  • 八.Linux博客-2016年8月8日sed、vim

    格式说明: 操作 概念 命令 说明及举例 八.sed、vim sed 文本编辑工具 行编辑器,每次取出一行在内存里处理,处理完成后屏幕打印。完成后再取出一行放到内存里处理,覆盖原来内存中的行,循环。。 sed -n '3d' f1 把文件f1中的第三行删掉并不在屏幕上显示 sed -n&n…

    Linux干货 2016-08-24
  • RAID各级别的特性及使用介绍(8.3博客作业)

    RAID各级别的特性及使用介绍 介绍: 独立硬盘冗余阵列(RAID:Redundant Array of Independent Disks),旧称廉价磁盘冗余阵列,简称磁盘阵列。 组成: 多块磁盘,RAID控制器(硬件RAID、软件RAID)     硬件RAID:自带CPU的RAID卡,不消耗服务器资源,可通过备份…

    Linux干货 2016-07-16