Linux自学笔记——shell脚本编程

简介:

脚本文件格式:

   第一行,顶格:#!/bin/bash

   注释信息:#

   代码注释:

缩进,适度添加空白行

语言:编程语法格式,库,算法和数据结构;

编程思想:

   问题空间 à解空间

变量:

   局部变量

   本地变量

   环境变量

   位置参数变量

   特殊变量

数据类型:字符型、数值型

   弱类型:字符型;

Bash中的算术运算:

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

实现算术运算:

1)let var=算术表达式;

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

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

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

 

乘法符号在有些场景中需要转义;

Bash有內建的随机数生成器;$RANDOM

增强型赋值:

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

   let varOPERvalue

      例如:let count+=1

自增,自减:

   let var+=1

      let var++

   let var-=1

      let var—

练习1:写一个脚本,计算/etc/passwd文件的第10个用户和第20个用户的ID之和;

   wKiom1nIneKCpBRXAABD7JlHjxo414.png-wh_50

练习2:写一个脚本,传递两个文件路径作为参数脚本,计算这两个文件中所有空白行之和;

   wKioL1nInbCBjYNxAABDTknh1OI480.png-wh_50

条件测试:

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

 

如何编写测试表达式以实现所需的测试:

1)执行命令,并利用命令状态返回值来判断;

0:成功;

1-255:失败;

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

测试命令:

   test EXPRESSION

   [ EXPRESSION ]

   ` EXPRESSION `

   NOTE:expression前后必须有空白字符;

Bash的测试类型:

   数值测试:数值比较

      -gt:是否大于;

      -ge:是否大于等于;

      -eq:是否等于;

      -ne:是否不等于;

      -lt;是否小于;

      -le:是否小于等于;

   字符串测试:

      ==:是否等于;

      >:是否大于

      <:是否小于

      !=:是否不等于;

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

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

      -z “string”:测试字符串是否为空,空则真,不空则为假;

      -n “string”:测试字符串是否为不空,不空则为真,空则为假;

      Note

1)用于字符串比较时的用到的操作数都应该使用引号;

      2)要使用[[]];

   文件测试:

      存在性测试:

        -a FILE

        -e FILE

        文件的存在性测试,存在则为真,否则则为假;

      存在性及类型测试:

        -b file:是否存在并且为块设备文件;

        -c file:是否存在并且为字符设备文件;

        -d file:是否存在并且为目录文件;

        -f file:是否存在并且为普通文件;

        -h file 或 –L file:是否存在并且为符号链接文件;

        -p file:是否存在并且为命名管道文件;

        -S file:是否存在并且为套接字文件;

      文件权限测试:

        -r file:是否存在并且对当前用户可读;

        -w file:是否存在并且对当前用户可写;

        -x file:是否存在并且对当前用户可执行;

      特殊权限测试:

        -u file:是否存在并且拥有suid权限;

        -g file:是否存在并且拥有sgid权限;

        -k file:是否存在并且拥有sticky权限;

      文件是否有内容:

        -s file:是否有内容;

      时间戳:

        -N file:文件自从上一次读操作后是否被修改过;

      从属关系测试:

        -O file:当前用户是否为文件的属主;

        -G file:当前用户是否为文件的属组;

      双目测试;

        File1 –ef file2:file1与file2是否指向同一个文件系统的相同inode的硬连接;

        File1 –nt file2:file1是否新于file2;

        File1 –ot file2:file1是否旧于file2;

   组合条件测试:

      逻辑运算:

      方式一:

        COMMAND1 && COMMAND2

        COMMAND1 || COMMAND2

        ! COMMAND

        [ -O FILE ] && [ -r file ]

      方式二:

        EXPRESSION1 –a EXPRESSION2

        EXPRESSION1 –o EXPRESSION2

        ! EXPRESSION

         [ -O FILE –a –x FILE ]

练习:将当前主机名称保存至hostName变量中,如果主机名为空,或者为localhost.localdomain,则将其设置为www.claude666.com;

    wKioL1nInb_zo9tKAABD8ldLvD8483.png-wh_50

脚本的状态返回值:

   默认是脚本中执行的最后一条件命令的状态返回值;

   自定义状态退出状态码:

      exit [n]:n为自己指定的状态码;

     note:shell进程遇到exit时,即会终止,因此,整个脚本执行即为结束;

 

向脚本传递参数:

位置参数变量

myscript.sh  argu1 argu2

引用方式:

    1,2, ..., 10,{11}, ...

轮替:

    Shift [n]:位置参数轮替

练习:写一脚本,通过命令传递两个文本文件路径给脚本,计算其空白行数之和;

   wKiom1nIngXzJcbbAABEpk-QXPo936.png-wh_50

 

过程式编程语言的代码执行顺序;

   顺序执行:逐条执行;

   选择执行;

      代码有一个分支;条件满足时才会执行;

      两个或以上的分支:只会执行其中一个满足条件的分支;

   循环执行;

      代码片段(循环体)要执行0、1或多个来回;

   选择执行:

      单分支的if语句:

        if 测试条件;then

           代码分支

        fi

      双分支的if语句:

        if 测试条件;then

           条件为真时执行的分支

        else

           条件为假时执行的分支

        fi

      多分支的if语句

        if  CONDITION1; then

           条件1为真分支

        elif  CONDITION2; then

           条件2为真分支

        elif  CONDITION3; then

           条件3为真分支

        ...

        elif  CONDITIONn; then

           条件n为真分支

        else

           所有条件均不满足时的分支

        Fi

      Note:即便多个条件同时满足,分支只会执行其中的一个,首先测试为“真”

示例1:脚本参数传递一个问文件路径给脚本,判断此文件的类型;

   wKiom1nIng-BXsYdAACFTQHVBBU084.png-wh_50

练习:写一个脚本

1)传递一个参数给脚本,此参数为用户名;

2)根据其id号来判断用户类型;

0:管理员

1-999:系统用户

1000+:普通用户

   wKioL1nInd2w1fJyAABiqZED0Lc333.png-wh_50

练习:写一个脚本

1)列出如下菜单给用户;

disk) show disks info;

mem) show memory info;

cpu) show cpu info;

*) exit

  2)提示用户给出自己的选择,而后显示对应其选择的相应系统信息;

   wKiom1nInjTRqunuAAAuj9Vi3ok948.png-wh_50

示例2:通过参数传递一个用户名给脚本,此用户不存在时,则添加之,如果存在,显示用户已存在;

   wKiom1nInj7gFErcAABYb4EyOls780.png-wh_50

练习1:通过命令行给定两个数字,输出其中较大的值;

   方法一:

   wKioL1nInguAojlfAABIIW7SGB4038.png-wh_50

   方法二:

   wKioL1nInhXinftxAABLg1PFhQY409.png-wh_50

练习2:通过命令行参数给定一个用户名,判断其ID号是偶数还是奇数;

   wKiom1nInliCkpA2AABUfhs5DLg711.png-wh_50

练习3:通过命令行参数给定两个文本文件名,如果某文件不存在,则结束脚本执行;都存在时返回每个文件的行数,并说明其中行数较多的文件;

   wKioL1nIniXAvJRlAACSnXZmulY371.png-wh_50

练习4:写一个脚本完成如下功能;

1)列出当前系统识别到的所有磁盘设备;

2)如磁盘数量为1,则显示其空间使用信息;否则,则显示左后一个磁盘上的空间信息;

wKiom1nInmqTXphFAACIyYAEfb8483.png-wh_50

在虚拟机再添加一块硬盘重新测试:

wKiom1nInnLTRqgvAAC1q7PWb4c149.png-wh_50

Bash脚本编程之用户交互:

   read [option]… [name …]

      -p 'PROMPT'后面跟提示信息,即在输入前打印处提示信息;

      -t TIMEOUT    后面跟秒数,意思为输入命令的等待秒数;

   bash -n /path/to/some_script

      检测脚本中的语法错误

   bash -x /path/to/some_script

      调试执行

示例1:输入一个磁盘分区,查看是否存在,存在则输出磁盘信息:

    wKioL1nInlPBswoLAACimU9ZNVg272.png-wh_50

示例2:添加用户及设置密码;

       wKioL1nInmDiLBwEAAA0p56tdEU596.png-wh_50

 

循环执行:将一段代码重复执行0、1或多次;

   进入条件:条件满足才进入循环;

   退出条件:每个循环都应该应该有退出条件,以有机会推出循环;

  

   Bash脚本:

      For循环

      While循环

      Until循环

for循环:

   两种格式;

1)遍历列表;

2)控制变量;

 

遍历列表:

for VARAIBLE in LIST;do

    循环体

done

进入条件:只要列表有元素,即可进入循环;

退出条件:列表中的元素遍历完成;

LIST的生成方式:

1)直接给出;

2)整数列表

a){start..end}

b)seq [start [incremtal] last]

   3)返回列表的命令;

   4)glob

   5)变量引用;@,*

练习:批量添加用户(for)

   wKiom1nInqeDy5zfAABo7QxG_wU581.png-wh_50

练习:求100以内所有正整数之和;

    wKiom1nInraiFQ26AAAYwpd-bw4465.png-wh_50

练习:判断/var/log目录下的每一个文件的内容类型

   wKiom1nInr_hFrpQAAA1KqbIfHc596.png-wh_50

练习:

1)分别求100以内所有偶数之和,以及所有奇数之和;

wKiom1nInsmQ3hxlAAArRLf8fFA739.png-wh_50

2)计算当前系统上的所有id之和;

wKioL1nInpmj23QgAAA0ItsRIJw062.png-wh_50

3)通过脚本参数传递目录给脚本,而后计算此目录下所有文本文件的行数之和;并说明此类文件的总数;

wKiom1nInt-hJWZ3AABAc2W3uu8390.png-wh_50

 

while循环:

   while CONDITION;do

      循环体

      循环控制变量修正表达式

   done

   进入条件:CONDITION测试为“真”

   退出条件:CONDITION测试为“假”

until循环:

   until CONDITION;do

      循环体

      循环控制变量修正表达式

   done

   进入条件:CONDITION测试为“假”

   退出条件:CONDITION测试为“真”

示例:求100以内所有正整数之和;

方法一:while循环

    wKioL1nInrjgWe-jAAAbP_-QRns889.png-wh_50

方法二:until循环;

    wKiom1nInv-wEoLPAAAlLT58mW4602.png-wh_50

练习:分别用for,while,until实现

1.分别求100以内所有偶数之和,100以内所有奇数之和;

方法一:for循环

wKiom1nInyeBC5_sAAA6Dvb42PY630.png-wh_50

方法二:while循环

wKiom1nInzKRAA2nAABD1-pAvok616.png-wh_50

方法三:until循环

wKioL1nInwDywrxvAABFHGIF4oE258.png-wh_50

2.创建10个用户,user101-user110;密码同用户名;

方法一:for循环

wKioL1nInwuxMNDXAAAhASkYZM8761.png-wh_50

方法二:while循环

wKiom1nIn0-zwgcbAAAmYmIlvFM761.png-wh_50

方法三:until循环

wKioL1nInyPiqVQ_AAAnGcvOVGM412.png-wh_50

3.打印九九乘法表;

方法一:for循环

wKiom1nIn2nB9DGwAABETW_f_B0073.png-wh_50

方法二:while循环

wKioL1nInzbTCi2BAABIn5XyJWs971.png-wh_50

方法三:until循环

wKiom1nIn3yylch6AABR-J2AcMs080.png-wh_50

4.打印逆序的九九乘法表;

方法一:for循环

wKioL1nIn5bSU7ggAABBf9FhZYs452.png-wh_50

方法二:while循环

wKiom1nIn9-Cnq9FAABMsoIqqug463.png-wh_50

方法三:until循环

wKiom1nIn_bQEmxpAABG6PebKCY444.png-wh_50

 

循环控制语句:

continue:提前结束本轮循环,而直接进入下一轮循环判断;

   while CONDITION  ;do

      CMD1

      …

      if CONDITION2;then

        continue

      fi

      CMDn

      …

   done

示例:求100以内所有偶数之和:

        wKiom1nIpc2hMSvrAAAiy2vrokM192.png-wh_50

 

Break:提前跳出循环

   While CONDITION1;do

      CMD1

      …

      if CONDITION2;then

        break

      fi

   done

 

创建死循环:

   while true;do

      循环体

   done

   退出方式;某个测试条件满足时,让循环执行break命令;

示例:求100以内所有奇数之和;

        wKioL1nIpZ_SUL0DAAAfgZQdDjE884.png-wh_50

 

sleep命令:

   delay for a specified amount of time

   sleep number

练习:每隔3秒到系统上获取已经登录的用户的用户信息;其中,如果cladue用户登录系统,则记录于日志中,并退出;

    wKiom1nIpemSZ8n9AAAiC-oKFfw580.png-wh_50

While循环的特殊用法(遍历文件的行)

   While read VARIABLE;do

      循环体

   done < /PATH/FROM/SOMEFILE

   一次读取/PATH/FROM/SOMEFILE文件中的每一行,且将基赋值给VARIABLE变量;

示例:找出ID号为偶数的用户,显示其用户名、ID以及默认shell;

        wKiom1nIpfbyVVwgAAAtZf286CM129.png-wh_50

 

for循环的特殊用法:

   for ((控制变量初始化;条件判断表达式;控制变量的修正语句));do

      循环体

   done

   控制变量初始化:仅在循环代码开始运行时执行一次;

   控制变量的修正语句:每轮循环结束会先进行控制变量修正运算,而后再做条件判断;

示例:求100以内所有正整数之和;    

    wKiom1nIpgTAwirrAAAhqoTY66M789.png-wh_50

示例;打印九九乘法表;

            wKioL1nIpdXCFlNbAAA9dW-pk_4221.png-wh_50

case语句:

case语句的语法格式:

   case $VARAIBLE in

   PAT1)

      分支1

      ;;

   PAT2)

      分支2

      ;;

   …

   *)

      分支n

      ;;

   esac

case支持的glob风格的通配符:

   *:任意长度的任意字符;

   ?:任意单个字符;

   []:范围内任意单个字符;

   a|b:a或b

 

示例1:显示一个菜单给用户;

cpu) display cpu information

mem) display memoryinformation

disk) display disksinformation

quit) quit

要求:(1) 提示用户给出自己的选择;

(2) 正确的选择则给出相应的信息;否则,则提示重新选择正确的选项;

        wKiom1nIph6gGG4HAABH9NJ4hQg305.png-wh_50

示例:写一个服务框架脚本:

$lockfile,值/var/lock/subsys/SCRIPT_NAME

1)接受参数start,stop,restart,status四个参数之一;

2)如果参数非此四者,则提示使用帮助后退出;

4)Start,则创建lockfile,并显示启动;stop,则删除lockfile,并显示停止;restart,则先删除此文件再创建文件,而后显示重启完成;status,如果lockfile存在,显示running,否则,显示stoped。

        wKioL1nIphvgBJXOAABtkNovkJ4217.png-wh_50

Note:第一行代码basename $0.获取脚本的名字。想对哪个服务管理,将脚本改成对应的名字即可;

 

函数:function

   过程式编程:代码重用

      模块化编程

      结构化编程

     

      把一段独立功能的代码当作一个整体,并为之一个名字;命名的代码段,此即为函数;

      Note:定义函数的代码段不会自动执行,在调用时执行;所谓调用函数在代码中给定函数名即可;

      函数名出现的任何位置,在代码执行时,都会被自动替换成函数代码;

语法一:

   function f_name {

函数体…

}

语法二:

   f_name() {

      …函数体…

}

函数的生命周期:每次被调用时创建,返回时终止;

   其状态返回结果为函数体中运行的最后一条命令的状态结果;

   自定义状态返回值,需要使用return

      return [0-255]

        0:成功

        1-255:失败

示例:给定一个用户名,取的用户的id号和默认shell;

        wKiom1nIpmKTGsXIAAAx3TFP_Qs755.png-wh_50

示例2:上述例子的服务脚本框架(用函数)

        wKioL1nIpjCjHcVMAAB80NnWi-Y819.png-wh_50

函数返回值:

   函数的执行结果返回值;

1)使用echo或print命令进行输出;

2)函数体中调用的命令的执行结果;

函数的退出状态码:

1)默认取决于函数体中执行的最后一条命令的退出状态码;

2)自定义:return

函数可以接受参数:

   传递参数给函数:

在函数体当中,可以使用1,2,…引用传递给函数的参数,还可以函数中使用@引用所有的参数,$#引用传递的参数的个数;

      在调用函数时,在函数名后面以空白符分隔给定参数列表即可,例如,testfunc arg1 arg2 arg3…

示例:添加10个用户,添加用户的功能使用函数实现,用户名作为参数传递给函数;

        wKioL1nIpj2TJ7eUAAA1TieDVoA268.png-wh_50

练习:写一个脚本,使用函数ping一个主机来测试主机的在线状态;主机地址通过参数传递给函数;

   主程序:测试192.168.19.129-192.168.19.139范围内主机的在线状态;

   wKioL1nIpkmjj23-AAA4TF2rAbk193.png-wh_50

练习:打印N*N乘法表;

   wKioL1nIplSgcH33AABsj6gtjeo713.png-wh_50

变量作用域:

   局部变量:作用域是函数的生命周期;在函数结束时被自动销毁;

      定义局部变量的方法:localVARIABLE=VALUE

   本地变量:作用域是运行脚本的shell进程的生命周期;因此,其作用范围为当前shell脚本程序文件;

示例程序:

   wKiom1nIppmy3G_rAAAkjDB0bow178.png-wh_50

函数递归:

   函数直接或间接调用自身:

示例:求10!

   wKioL1nIpmji4lrvAAAxDQ8dmtg710.png-wh_50



本文转自 claude_liu 51CTO博客,原文链接:http://blog.51cto.com/claude666/1968424,如需转载请自行联系原作者

目录
打赏
0
0
0
0
265
分享
相关文章
MySQL 备份 Shell 脚本:支持远程同步与阿里云 OSS 备份
一款自动化 MySQL 备份 Shell 脚本,支持本地存储、远程服务器同步(SSH+rsync)、阿里云 OSS 备份,并自动清理过期备份。适用于数据库管理员和开发者,帮助确保数据安全。
|
6天前
|
在Linux、CentOS7中设置shell脚本开机自启动服务
以上就是在CentOS 7中设置shell脚本开机自启动服务的全部步骤。希望这个指南能帮助你更好地管理你的Linux系统。
60 25
|
3天前
|
shell_42:Linux参数移动
总的来说,参数移动是Linux shell脚本中的一个重要概念,掌握它可以帮助我们更好地处理和管理脚本中的参数。希望这个解释能帮助你理解和使用参数移动。
31 18
如何在阿里云的linux上搭建Node.js编程环境?
本指南介绍如何在阿里云Linux服务器(Ubuntu/CentOS)上搭建Node.js环境,包含两种安装方式:包管理器快速安装和NVM多版本管理。同时覆盖全局npm工具配置、应用部署示例(如Express服务)、PM2持久化运行、阿里云安全组设置及外部访问验证等步骤,助你完成开发与生产环境的搭建。
|
3月前
|
【linux】Shell脚本中basename和dirname的详细用法教程
本文详细介绍了Linux Shell脚本中 `basename`和 `dirname`命令的用法,包括去除路径信息、去除后缀、批量处理文件名和路径等。同时,通过文件备份和日志文件分离的实践应用,展示了这两个命令在实际脚本中的应用场景。希望本文能帮助您更好地理解和应用 `basename`和 `dirname`命令,提高Shell脚本编写的效率和灵活性。
156 32
定期备份数据库:基于 Shell 脚本的自动化方案
本篇文章分享一个简单的 Shell 脚本,用于定期备份 MySQL 数据库,并自动将备份传输到远程服务器,帮助防止数据丢失。
多种脚本批量下载 Docker 镜像:Shell、PowerShell、Node.js 和 C#
本项目提供多种脚本(Shell、PowerShell、Node.js 和 C#)用于批量下载 Docker 镜像。配置文件 `docker-images.txt` 列出需要下载的镜像及其标签。各脚本首先检查 Docker 是否安装,接着读取配置文件并逐行处理,跳过空行和注释行,提取镜像名称和标签,调用 `docker pull` 命令下载镜像,并输出下载结果。使用时需创建配置文件并运行相应脚本。C# 版本需安装 .NET 8 runtime。
173 2
|
3月前
|
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
70 17
|
3月前
|
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
69 26
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
198 13
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等