shell编程

shell 编程

shell介绍

概述

Shell是一种具备特殊功能的程序,它提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令,并把它送入内核去执行。内核是Linux系统的心脏,从开机自检就驻留在计算机的内存中,直到计算机关闭为止,而用户的应用程序存储在计算机的硬盘上,仅当需要时才被调入内存。Shell是一种应用程序,当用户登录Linux系统时,Shell就会被调入内存去执行。Shell独立于内核,它是连接内核和应用程序的桥梁,并由输入设备读取命令,再将其转为计算机可以理解的机械码,Linux内核才能执行该命令。

20160418235418911.png

优势

Shell脚本语言的好处是简单、易学、易用,适合处理文件和目录之类的对象,以简单的方式快速完成某些复杂的事情通常是创建脚本的重要原则,脚本语言的特性可以总结为以下几个方面:

  • 语法和结构通常比较简单。
  • 学习和使用通常比较简单。
  • 通常以容易修改程序的“解释”作为运行方式,而不需要“编译。
  • 程序的开发产能优于运行效能。

Shell脚本语言是Linux/Unix系统上一种重要的脚本语言,在Linux/Unix领域应用极为广泛,熟练掌握Shell脚本语言是一个优秀的Linux/Unix开发者和系统管理员必经之路。利用Shell脚本语言可以简洁地实现复杂的操作,而且Shell脚本程序往往可以在不同版本的Linux/Unix系统上通用。

shell编程

基本格式

Shell脚本的文件名后缀通常是.sh (当然你也可以使用其他后缀或者没有后缀,.sh是为了规范)

程序编写格式:

#!/bin/bash

代码示例:

[root@localhost day01]# vi a.sh
#!/bin/bash
echo hello shell

# 赋予 a.sh 可执行权限 
[root@localhost day01]# chmod +x a.sh 

# 执行(调用/bin/bash执行a.sh脚本)
[root@localhost day01]# ./a.sh 
hello shell

变量

变量不需要声明,初始化不需要指定类型

变量命名

  1. 只能使用数字,字母和下划线,且不能以数字开头

  2. 变量名区分大小写

  3. 建议命令要通俗易懂

**注意:**变量赋值是通过等号(=)进行赋值,在变量、等号和值之间不能出现空格。

显示变量值使用 echo命令(类似于java中的system.out) ,加上 $变量名,也可以使用 ${变量名}

例如:

echo $JAVA_HOME
echo ${JAVA_HOME}

变量的声明和使用

[root@localhost day01]# num=10
[root@localhost day01]# echo $num
10

变量分类

本地变量、环境变量、局部变量、位置变量、特殊变量

本地变量

  • 只对当前shell进程有效的,对当前进程的子进程和其它shell进程无效。
  • 定义:VAR_NAME=VALUE
  • 变量引用:${VAR_NAME} 或者 $VAR_NAME
  • 取消变量:unset VAR_NAME
  • 相当于java中的私有变量(private),只能当前类使用,子类和其他类都无法使用。

比如在一个bash命令窗口下再使用bash,则变成了子进程,本地变量不会被这个子进程所访问。

image-20210820180147445

环境变量

自定义的环境变量对当前shell进程及其子shell进程有效,对其它的shell进程无效

定义:export VAR_NAME=VALUE

对所有shell进程都有效需要配置到配置文件中

[root@localhost day01]# vi /etc/profile
[root@localhost day01]# source /etc/profile

相当于java中的protected修饰符,对当前类,子孙类,以及同一个包下面可以共用。

自定义的环境 变量

image-20210820181255085

局部变量

  • 在函数中调用,函数执行结束,变量就会消失
  • 对shell脚本中某代码片段有效
  • 定义:local VAR_NAME=VALUE
  • 相当于java代码中某一个方法中定义的局部变量,只对这个方法有效

位置变量

脚本中的参数

$0: 脚本自身

$1: 脚本的第一个参数

$2: 脚本的第二个参数

相当于java中main函数中的args参数,可以获取外部参数。

[root@localhost day01]# vi args.sh

#!/bin/bash
echo $0
echo $1
echo $2

执行结果

image-20210822174741661

特殊变量

$?:接收上一条命令的返回状态码,返回状态码在0-255之间

$#:参数个数

$*:或者$@:所有的参数

$$:获取当前shell的进程号(PID)(可以实现脚’'本自杀)(或者使用exit命令直接退出也可以使用exit [num])

#!/bin/bash
echo $0
echo $1
echo $2
echo "参数个数 $#"
echo "所有的参数 $*"
echo "所有的参数 $@"
echo "当前shell的进程号 $$"
echo "上一条命令的返回状态 $?"

执行结果

image-20210822180036356

引号

Shell编程中有三类引号:单引号、双引号、反引号。

‘’ 单引号不解析变量

echo '$name'

“” 双引号会解析变量

echo "$name"

`` 反引号是调用命令的输出,或把命令的输出赋予变量,和 $(命令) 是一样的

echo `ls`

示例:

[root@localhost day01]# name=zhansan[root@localhost day01]# echo '$name'$name[root@localhost day01]# echo "$name"zhansan[root@localhost day01]# echo `$name`-bash: zhansan: 未找到命令[root@localhost day01]# echo `echo $name`zhansan[root@localhost day01]# echo `ls`args.sh a.sh[root@localhost day01]# echo $(ls)args.sh a.sh

循环

for循环

  • 格式1
for ((i=0;i<10;i++))do	...done
  • 格式2
for i in 0 1 2 3 4 5 6do	...done
  • 格式3
for i in {0..9}do	...done

**注意:**for i in {0…9} 等于for i in {0…9…1} , 第三个参数为跨步。

例如:

{0…9…2} 表示 0,2,4,6,8

while循环

格式

while [ 条件 ]do ...done
#!/bin/bash# fori循环for((i=0;i<5;i++))doecho "fori 循环:$i"done# for in循环for i in 0 1 3 4doecho "for in 循环: $i"done# for in {}for i in {0..9..2}doecho "for in {} 循环: $i"done

image-20210822183226991

#!/bin/bashnum=0while [ $num -lt 10 ]doecho $numlet num=$num+1done

注意 [] 里的内容开始和结尾要用空格

image-20210822184229034

循环控制

berak

break命令是在处理过程中跳出循环的一种简单方法,可以使用break命令退出任何类型的循环,包括while循环和for循环

continue

continue命令是一种提前停止循环内命令,而不完全终止循环的方法,这就需要在循环内设置shell不执行命令的条件

条件

test [ EXPR ]

[ EXPR ]:注意中括号和表达式之间的空格

整型测试

​ -gt:大于:

​ -lt:小于

​ -ge:大于等于

​ -le:小于等于

​ -eq:等于

​ -ne:不等于

例如[ $num1 -gt ​$num2 ]或者test $num1 -gt $num2

字符串测试

= 等于,例如判断变量是否为空 [ $str = “” ] 或者[ -z $str ]

!= 不等于

判断

if 判断

  • 单分支
if [ 条件 ]; then	选择分支fi
  • 双分支
if [ 条件 ]; then  选择分支1else  选择分支2fi
  • 多分支
if [ 条件1 ]; then  分支1elif [ 条件2 ]; then  分支2elif [ 条件3 ]; then  分支3  ...else  分支nfi

实例:

#!/bin/bashnum1=4if [ $num1 -gt 5 ]; then echo "$num1 大于 5"else echo "$num1 小于 5"fistr1=""if [ $str1="" ]; thenecho "str 为空"fi

image-20210822191719324

算数运算符

let varName=算术表达式

varName=$[算术表达式]

varName=$((算术表达式))

varName=`expr $num1 + $num2`

使用这种格式要注意两个数字和+号中间要有空格。

实例:

#!/bin/bashnum=1let num=$num+1num=$[ $num+1 ]num=$(($num+1))num=`expr $num + 1`echo $num

结果 5

逻辑运算符

if [ 条件A && 条件B ] 在shell中怎么写?

if [ 条件A && 条件B ];then 是不对的

解决方法:

  • 需要用到shell中的逻辑操作符

-a 与
-o 或
! 非

如if [ 条件A -a 条件B ]

  • if [ 条件A ] && [条件B ]

  • if((A&&B))

  • if [[ A&&B ]]

#!/bin/bashnum1=10num2=20num3=15# 方式一if [ $num1 -lt $num3 -a $num2 -gt $num3 ]; then echo "num3 在10-20之间"else echo "other"fi# 方式二if [[ $num1 -lt $num3 && $num2 -gt $num3 ]]; then echo "num3 在10-20之间"else echo "other"fi

自定义函数

格式:

function 函数名(){

}

  1. 引用自定义函数文件时,使用source func.sh
  2. 有利于代码的重用性
  3. 函数传递参数(可以使用类似于Java中的args,args[1]代表Shell中的$1)
  4. 函数的返回值,只能是数字
#!/bin/bashfunction func(){ echo "this is a function" if [ $1 ];  then echo "第一个参数 $1" fi return 0}# 函数调用funcfunc 'hello'

image-20210822195552695

函数调用

[root@localhost day01]# vi test.sh #!/bin/bash# 外部调用函数source func.shfuncfunc 10

read

read命令接收标准输入(键盘)的输入,或者其他文件描述符的输入。得到输入后,read命令将数据放入一个标准变量中。

格式:

read VAR_NAME

read如果后面不指定变量,那么read命令会将接收到的数据放置在环境变量REPLY中

read -p "Enter your name" VAR_NAME# -p 表示输入时的提示字符串

image-20210823093320240

read -t 5 -p "Enter your name" VAR_NAME# -t  表示输入等待时间
read -s -p "Enter your password" VAR_NAME# -s 表示安全输入,键入密码时不会显示

declare

用来限定变量的属性

-r 只读

-i 整数:某些算术计算允许在被声明为整数的变量中完成,而不需要特别使用expr或let来完成。

-a 数组

示例:
只读

image-20210823095230032

整数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iiHCmeDa-1647676741351)(img/image-20210823095458130.png)]

数组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pE9kkPEU-1647676741352)(img/image-20210823095659401-1629724340786.png)]

字符串操作

获取长度

${#VAR_NAME}

字符串截取

${variable:offset:length} 或者 ${variable:offset}

尾部截取字符串

${variabel: -length} 冒号后有个空格

大小写转换

小->大

${variabe^^}

大->小

${vaiable,}

示例:

image-20210823100847977

数组

定义:declare -a:表示定义普通数组

特点

  1. 支持稀疏格式
  2. 仅支持一维数组

数组赋值方式

a[0]=$RANDOM  # 一次对一个元素赋值a=(a b c d)  #  一次对多个元素赋值a=([0]=a [3]=b [1]=c)  # 按索引进行赋值

使用read命令read -a ARRAY_NAME查看元素

${ARRAY[index]}  #查看数组指定角标的元素${ARRAY}  # 查看数组的第一个元素${ARRAY[*]} 或者 ${ARRAY[@]}  # 查看数组的所有元素

获取数组的长度

${#ARRAY[*]}${#ARRAY[@]}

获取数组内元素的长度

${#ARRAY[0]}

注意:${#ARRAY[0]}表示获取数组中的第一个元素的长度,等于${#ARRAY}

从数组中获取某一片段之内的元素(操作类似于字符串操作)

${ARRAY[@]:offset:length}# offset:偏移的元素个数# length:取出的元素的个数# ${ARRAY[@]:offset:length}:取出偏移量后的指定个数的元素# ${ARRAY[@]:offset}:取出数组中偏移量后的所有元素

数组删除元素

unset ARRAY[index]

示例:

[root@localhost day01]# declare -a arr2[root@localhost day01]# arr2=(a b c d)[root@localhost day01]# arr2[1]=x[root@localhost day01]# echo ${arr2[*]}a x c d[root@localhost day01]# echo ${#arr2[*]}4[root@localhost day01]# echo ${arr2[*]:1}x c d[root@localhost day01]# unset arr2[2][root@localhost day01]# echo ${arr2[*]}a x d[root@localhost day01]# 

其他命令

date

显示当前时间

  1. 格式化输出 +%Y-%m-%d %H:%M:%S
  2. 格式%s表示自1970-01-01 00:00:00以来的秒数
  3. 指定时间输出 --date=‘2009-01-01 11:11:11’
  4. 指定时间输出 --date=‘3 days ago’ (3天之前,3天之后可以用-3)

示例:

[root@localhost day01]# date2021年 08月 23日 星期一 10:31:06 CST[root@localhost day01]# echo `date "+%Y-%m-%d %H:%M:%S"`2021-08-23 10:35:38[root@localhost day01]# echo `date +%s`1629686170[root@localhost day01]# [root@localhost day01]# echo `date --date='2020-10-01 10:10:10'`2020年 10月 01日 星期四 10:10:10 CST[root@localhost day01]# echo `date --date='3 days ago'`2021年 08月 20日 星期五 10:38:23 CST[root@localhost day01]# 

后台运行脚本

在脚本后面加一个&

test.sh &

这样的话虽然可以在后台运行,但是当用户注销(logout)或者网络断开时,终端会收到Linux HUP信号(hangup)信号从而关闭其所有子进程

nohup命令

不挂断的运行命令,忽略所有挂断(hangup)信号

nohup test.sh &
  1. nohup会忽略进程的hangup挂断信号,所以关闭当前会话窗口不会停止这个进程的执行。
  2. nohup会在当前执行的目录生成一个nohup.out日志文件

标准输入/输出重定向

command > file将输出重定向到 file。
command < file将输入重定向到 file。
command >> file将输出以追加的方式重定向到 file。
n > file将文件描述符为 n 的文件重定向到 file。
n >> file将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m将输出文件 m 和 n 合并。
n <& m将输入文件 m 和 n 合并。
<< tag将开始标记 tag 和结束标记 tag 之间的内容作为输入。

crontab 定时器

基本格式 :

* * * * * command# 分 时 日 月 周 命令# 第1列表示分钟1~59 每分钟用*或者 */1表示# 第2列表示小时1~23(0表示0点)# 第3列表示日期1~31# 第4列表示月份1~12# 第5列标识号星期0~6(0表示星期天)# 第6列要运行的命令

img

  • 星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。

  • 逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”

  • 中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”

  • 正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一

编写定时任务

crontab -e

列出目前的定时任务

crontab -l

image-20210823132650740

删除定时任务

crontab -l

示例:

# 每分钟执行执行一次* * * * * /bin/ls# 在 12 月内, 每天的早上 6 点到 12 点,每隔 3 个小时 0 分钟执行一次 /usr/bin/backup:0 6-12/3 * 12 * /usr/bin/backup# 周一到周五每天下午 5:00 寄一封信给 alex@domain.name:0 17 * * 1-5 mail -s "hi" alex@domain.name < /tmp/maildata# 每月每天的午夜 0 点 20 分, 2 点 20 分, 4 点 20 分....执行 echo "haha":20 0-23/2 * * * echo "haha"

具体实例:

# 每两个小时重启一次apache 0 */2 * * * /sbin/service httpd restart# 每天7:50开启ssh服务 50 7 * * * /sbin/service sshd start# 每天22:50关闭ssh服务 50 22 * * * /sbin/service sshd stop#  每月1号和15号检查/home 磁盘 0 0 1,15 * * fsck /home# 每周一至周五3点钟,在目录/home中,查找文件名为*.xxx的文件,并删除4天前的文件。0 3 * * 1-5 find /home "*.xxx" -mtime +4 -exec rm {} \;

**注意:**当程序在你所指定的时间执行后,系统会发一封邮件给当前的用户,显示该程序执行的内容,若是你不希望收到这样的邮件,请在每一行空一格之后加上 > /dev/null 2>&1 即可,如:

# 每两个小时重启一次apache 0 */2 * * * /sbin/service httpd restart > /dev/null 2>&1

ps

ps:用来显示进程的相关信息

ps 显示当前shell启动的所有进程

ps -e 显示系统中所有进程

ps -ef|grep java 查找所有的java进程

shell应用实例

根据时间创建文件夹

需求:创建10个目录,目录名称以当天时间开头,后面拼上目录编码

例如:1970-01-01_1

#!/bin/bashmkdir -p /home/shell/testcd /home/shell/testfor i in {1..10}do   date=`date +%Y-%m-%d`  dirname=${date}_$i  echo $dirname  mkdir $dirnamedone
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值