shell脚本编程初步入门

shell脚本编程初步入门

   说到shell脚本编程,那我们就来先看下shell,shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。它虽然不是Linux系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Linux系统的关键。

   Shell有两种执行命令的方式:

      交互式:解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。

      批处理:用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。

   大体上,可以将程序设计语言可以分为两类:编译型语言和解释型语言。

      编译:高级语言–>编译器–>目标代码 例如:java,C# 

      解释:高级语言–>解释器–>机器代码 例如:shell, perl, python

   Linux上常见的Shell有bash、sh、csh、ksh等,bash是Linux标准默认的shell,我们这里讲到的就是现阶段运用最多的bash。

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

编写shell脚本:

1、格式要求:首行shebang机制 

    #!/bin/bash

    #!/usr/bin/python

    #!/usr/bin/perl

  打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行。看下面的例子:

    #!/bin/bash

    echo "Hello World !"

    “#!” 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell。echo命令用于向窗口输出文本。

2、运行脚本

   给予执行权限,在命令行上指定脚本的绝对或相对路径,将上面的代码保存为test.sh,并 cd 到相应目录;

    chmod +x ./test.sh     使脚本具有执行权限

    ./test.sh              执行脚本

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

   bash /bin/test.sh

脚本调试:

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

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

变量

   变量:命名的内存空间。

变量类型:

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

   弱类型:无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用如:bash不支持浮点数

变量命名法则:

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

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

   3、见名知义

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

bash中变量的种类:

   环境变量:导出一个变量,作用域为当前shell进程及其子进程

      export NAME=VALUE;declare -x name=VALUE

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

      显示所有环境变量: export  env  printenv

      删除:unset name

   本地变量:NAME=VALUE:作用域为整个bash进程

      变量赋值:name=‘value’

      可以使用引用value:

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

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

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

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

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

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

       显示已定义的所有变量:set

       删除变量:unset name

   局部变量:作用域为当前代码段

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

       readonly name

       declare -r name

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

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

    $0: 命令本身

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

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

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

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

    $?:上个命令的退出状态,或函数的返回值。

看下面的例子:

[root@centos7 ~]# ./test.sh zhl zanghl
File Name: ./test.sh
First : zhl
Second : zanghl
Quoted Values: zhl zanghl
Quoted Values: zhl zanghl
Total Number of Parameters : 2
[root@centos7 ~]# cat test.sh 
#!/bin/bash
echo "File Name: $0"
echo "First : $1"
echo "Second : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"

$* 和 $@ 的区别

   $* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号"" 包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。但是当它们被双引号""包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。

这里我们引用网上一个资料中的例子来看一下:

程序是这样的:

#!/bin/bash
echo "\$*=" $*
echo "\"\$*\"=" "$*"
echo "\$@=" $@
echo "\"\$@\"=" "$@"
echo "print each param from \$*"
for var in $*
do
    echo "$var"
done
echo "print each param from \$@"
for var in $@
do
    echo "$var"
done
echo "print each param from \"\$*\""
for var in "$*"
do
    echo "$var"
done
echo "print each param from \"\$@\""
for var in "$@"
do
    echo "$var"
done
执行 ./test.sh "a" "b" "c" "d",看到下面的结果:
$*=  a b c d
"$*"= a b c d
$@=  a b c d
"$@"= a b c d
print each param from $*
a
b
c
d
print each param from $@
a
b
c
d
print each param from "$*"
a b c d
print each param from "$@"
a
b
c
d

逻辑运算:

true 1, false 0

  与: 1 与 1 = 1

     1 与 0 = 0

     0 与 1 = 0

     0 与 0 = 0 

 或:

     1 或 1 = 1

     1 或 0 = 1

     0 或 1 = 1

     0 或 0 = 0

 非:!

     ! 1 = 0

     ! 0 = 1 

短路运算:

     短路与:第一个为0,结果必定为0;第一个为1,第二个必须要参与运算;

     短路或:第一个为1,结果必定为1;第一个为0,第二个必须要参与运算;

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

条件测试:

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

    专用的测试表达式需要由测试命令辅助完成测试过程;若真,则返回0 若假,则返回1

测试命令:

     test EXPRESSION

     [ EXPRESSION ]

     [[ EXPRESSION ]] 

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

条件性的执行操作符

     && 代表条件性的  AND THEN

     ||  代表条件性的  OR ELSE 

test命令

     长格式的例子:test "$A" == "$B" && echo "Strings are equal" $ test “$A” -eq “$B” && echo "Integers are equal" 

     简写格式的例子:[ "$A" == "$B" ] && echo "Strings are equal" $ [ "$A" -eq "$B" ] && echo "Integers are equal"

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权限;

下面是一些编程的示例习题:

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

[root@centos7 bin]# bash systeminfo.sh 
hostname is centos7.zang
IPV4:10.1.252.189
version informationcat: CentOS Linux release 7.2.1511 (Core) 
kernel information: 3.10.0-327.el7.x86_64
cpu information:  Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz
memory :3.7G
Disk : 214.7 GB
[root@centos7 ~]# cat /bin/systeminfo.sh 
#!/bin/bash
echo "hostname is `hostname`"
echo "IPV4:`ifconfig | egrep -A1 'eno'| tail -1 | tr -s ' '| cut -d' ' -f3`"
echo "version informationcat: `cat /etc/redhat-release`"
echo "kernel information: `uname -r`"
echo "cpu information: `lscpu | sed -n '/Model name/p'| tr -s ' '|cut -d: -f2`"
echo "memory :`free -h | sed -n '/Mem/p' |tr -s ' ' | cut -d' ' -f2`"
echo "Disk :`fdisk -l | egrep 'Disk /dev/' | cut -d',' -f1 | cut -d: -f2`"

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

[root@centos7 bin]# bash backup.sh
backup is the /etc is success
[root@centos7 ~]# ll
total 20
-rw-------.   1 root root 1354 Jul 20 17:49 anaconda-ks.cfg
drwxr-xr-x.   2 root root    6 Jul 20 17:53 Desktop
drwxr-xr-x.   2 root root    6 Jul 20 17:53 Documents
drwxr-xr-x.   2 root root    6 Jul 20 17:53 Downloads
drwxr-xr-x. 129 root root 8192 Aug 11 19:41 etc2016-08-11
-rw-------.   1 root root 1402 Jul 20 17:52 initial-setup-ks.cfg

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

[root@centos7 bin]# bash disk.sh 
当前硬盘分区中空间利用率最大的值 :71
[root@centos7 bin]# cat disk.sh 
#!/bin/bash
echo "当前硬盘分区中空间利用率最大的值 :`df | egrep '/dev/sd.*' | tr -s ' ' | cut -d' ' -f5 | tr -d '%'| sort |tail -1`"

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

[root@centos7 bin]# bash links.sh 
      3 10.1.250.72
[root@centos7 bin]# cat links.sh
#!/bin/bash
netstat -nt | tr -s ' '|cut -d' ' -f5 | egrep -v '[[:alpha:]]'|cut -d: -f1|sort|uniq -c| sort -nr

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

[root@centos7 bin]# bash sumid.sh 
70
[root@centos7 bin]# cat sumid.sh 
#!/bin/bash
s1=`sed -n '10p' /etc/passwd | cut -d: -f3`
s2=`sed -n '20p' /etc/passwd | cut -d: -f3`
let sum=$s1+$s2
echo $sum

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

[root@centos7 bin]# cat /etc/fstab ; cat /etc/issue
#
# /etc/fstab
# Created by anaconda on Wed Jul 20 14:39:10 2016
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=030d27aa-d817-4330-8de8-90f87c7d0e1f /                       xfs     defaults        0 0
UUID=15819ecc-8ae9-4cc3-8f3f-54b7be0ac610 /boot                   xfs     defaults        0 0
UUID=14cd35c6-b195-4ec6-a202-781d2a850aad /testdir                xfs     defaults        0 0
UUID=f13adfd3-a620-4ec6-b1c3-d9b997b72fca swap                    swap    defaults        0 0
\S
Kernel \r on an \m
[root@centos7 bin]# bash sumspace.sh /etc/fstab /etc/issue
2
[root@centos7 bin]# cat sumspace.sh 
#!/bin/bash
f1=`sed -n '/^$/p' $1 | wc -l`
f2=`sed -n '/^$/p' $2 | wc -l`
let f=$f1+$f2
echo $f

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

[root@centos7 bin]# bash sumfile.sh 
/etc下一级子目录和文件个数:262
/var下一级子目录和文件个数:22
/usr下一级子目录和文件个数:12
[root@centos7 bin]# cat sumfile.sh 
#!/bin/bash
f1=`ls -A /etc/ | wc -l`
f2=`ls -A /var/ | wc -l`
f3=`ls -A /usr/ | wc -l`
echo "/etc下一级子目录和文件个数:$f1"
echo "/var下一级子目录和文件个数:$f2"
echo "/usr下一级子目录和文件个数:$f3"

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

[root@centos7 bin]# cat argsnum.sh 
#!/bin/bash
[[ $# -lt 1 ]] && echo "至少给一个路经作为参数"|| egrep '^$' $1 | wc -l
[root@centos7 bin]# bash argsnum.sh /etc/issue
1
[root@centos7 bin]# cat argsnum.sh 
#!/bin/bash
[[ $# -lt 1 ]] && echo "至少给一个路经作为参数"|| egrep '^$' $1 | wc -l

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

[root@centos7 bin]# cat hostping.sh 
#!/bin/bash
ping -c1 -w1 $1 > /dev/null
[[ $? == 0 ]] && echo "该IP可以访问" || echo "该IP不可访问"
[root@centos7 bin]# bash /bin/hostping.sh 192.168.1.99
该IP不可访问
[root@centos7 bin]# bash /bin/hostping.sh 192.168.1.1
该IP可以访问

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

[root@centos7 bin]# cat per.sh 
#!/bin/bash
z1=`[ -r /tmp/file1 ]; echo $?`
z2=`[ -w /tmp/file1 ]; echo $?`
[ $z1 == 1 ] && [ $z2 == 1 ] && echo "对此文件不可读写" || echo "`ls -l /tmp/file1`"
[root@centos7 bin]# ./per.sh 
----------. 1 zzz root 20 Aug 12 11:44 /tmp/file1
[zang@centos7 bin]$ ./per.sh 
对此文件不可读写
[zzz@centos7 bin]$ ./per.sh 
-rw-------. 1 zzz root 20 Aug 12 11:44 /tmp/file1

编写脚本/root/bin/nologin.sh和login.sh,实现禁止和充许普通用户登录系统。

[root@centos7 bin]# cat nologin.sh 
#!/bin/bash
[ -f /etc/nologin ] && echo "用户已经禁止登陆" || touch /etc/nologin ; echo "用户已经禁止登陆"
[root@centos7 bin]# bash login.sh 
用户已经可以登陆
[root@centos7 bin]# cat login.sh 
#!/bin/bash
[ -f /etc/nologin ] && (rm -f /etc/nologin ; echo "用户已经可以登陆") || echo "用户已经可以登陆"

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

(0)
zanghongleizanghonglei
上一篇 2016-08-15
下一篇 2016-08-15

相关推荐

  • 关于大型网站技术演进的思考(八):存储的瓶颈(8)

    原文出处: 夏天的森林  在开始本篇主要内容前,我们一起看看下面的几张截图,首先是第一张图,如下图所示: 这是一家电商网站的首页,当我们第一次打开这个首页,网站会弹出一个强制性的对话框,让用户选择货物配送的地址,如果是淘宝和京东的话,那么这个选择配货地址的选项是在商品里,如下图是淘宝的选择配送地点: 下图是京东选择配货地点: 那么图一跟京…

    2015-03-11
  • 正则表达式应用

    1、复制/etc/skel目录为/home/tuser1,要求/home/tuser1及其内部文件的属组和其它用户均没有任何访问权限。    cp -a /etc/skel /home/tuser1    chmod g-x /home/tuser1…

    Linux干货 2016-12-24
  • 推荐-Nginx Proxy模块的应用之负载均衡

    Ngnix Proxy模块的应用之负载均衡 Ngnix Proxy模块的应用之负载均衡 Proxy 模块介绍 实验环境 配置Proxy Proxy 模块介绍   在我之前的文章提到过,Nginx可以提供反向代理加速、基于应用层的负载均衡并能对后端服务器做健康状态检测。下面我们就动手操作一下,看如何实现上述功能。 实验环境 主机名称 主要功能 外网地址 内网地…

    Linux干货 2016-03-27
  • linux-系统自动化安装

    一、安装程序及配置 CentOS 系统安装 系统启动流程: bootloader–>kernel(initramfs)–>rootfs–>/sbin/init anaconda: 系统安装程序 tui:  基于图形库curses 的文本 窗口 gui :图形窗口 安装程序启动过程 MB…

    Linux干货 2016-09-26
  • ansible的入门使用手册

    ansible1

    2018-01-15
  • 马哥教育网络班22期第二周课程练习1-未闻花名

    1、Linux管理文件和目录的命令 命令 功能 命令 功能 pwd 显示当前目录 ls 查看目录下的内容 cd 改变所在目录 cat 显示文件的内容 grep 在文件中查找某字符 cp 复制文件 touch 创建文件 mv 移动文件 rm 删除文件 rmdir 删除目录 1.1 pwd命令 该命令的英文解释为print working directory(打…

    Linux干货 2016-08-29

评论列表(1条)

  • 马哥教育
    马哥教育 2016-08-15 17:04

    态度端正,完成的不错,再接再励