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)
sixijiesixijie
上一篇 2016-08-18
下一篇 2016-08-18

相关推荐

  • 文本处理grep

    grep:文本过滤(模式:pattern)工具grep, egrep, fgrep【适合处理比较大的文本】(不支持正则表达式搜索) sed:stream editor,文本编辑工具 awk:Linux上的实现gawk,文本报告生成器 grep(Global search 全局搜索 Regular expression 正则表达式 and Print out …

    Linux干货 2017-05-09
  • sed简介及常见用法

    sed是一个文本流处理器,配合正则表达式用可以实现很多文本处理操作。 和grep一样,sed是一行一行的处理的。sed处理文本时,首先会将源文件复制一份到内存中,然后将文本一行一行拿到模式空间内进行操作,最后输出到标准输出,即屏幕上。 在模式空间中,每一行都会根据用户给的条件进行匹配,匹配到了进行编辑后输出,没有匹配到,直接输出到标准输出。sed除了模式空间…

    2018-01-04
  • RAID级别介绍

    raid分为软raid和硬raid,一般公司使用硬raid,数据无价。 存数据都是先存到内存,后同步到硬盘,为提高raid卡的性能会在raid嵌入内存颗粒。 但是问题是断电后内存的数据没有同步到硬盘会丢失,这样就会有raid卡电池。(raid卡必须有raid电池) 计算机只识别raid卡,不会识别raid卡下有几块硬盘 raid 0:  (条带式)…

    Linux干货 2016-03-22
  • 每日一练–8.2 用户管理,权限管理

    (1)显示/var目录下所有以l开头,以一个小写字母结尾,且中间出现至少一位数字的文件或目录。     ll /var/l*[[:digit:]]*[[:lower:]] (2)显示以/etc目录下以任意一位数字开头,且以非数字结尾的文件或目录      ll /etc/[[:digit:]]*[^[:dig…

    Linux干货 2016-08-05
  • iptables的一个小文档

    iptables:    iptables五表五链        felter表            INPUT   …

    Linux干货 2017-04-30
  • Shell脚本编程基础之一

      Linux为高效管理系统,提供了CLI命令行接口,供用户在命令提示符下输入命令,它有很多bash shell基础特,根据这些特性能够很灵活的使用命令,也支持使同时输入多个命令执行,命令之间用冒号分隔;但是要完成复杂多次重复性的操作,非常不便,系统管理工作变得很是繁忙,很难轻松完成工作任务;不过Linux的shell支持脚本编程,通过编写纯文本格…

    Linux干货 2016-08-15