5.26-5.40 Shell脚本编程

  1. 什么是Shell:

  Shell首先是UNIX/Linux下的脚本编程语言,它是解释执行的,无需提前编译。Shell的语法细节和大部分编程语言都不太一样,需要重点学习。
  Shell同时也是一个程序,它的一端连接着UNIX/Linux内核,另一端连接着用户和其它应用程序;换句话说,Shell是用户和应用程序与内核沟通的桥梁。
  Shell脚本功能非常强大,完全能够胜任Linux的日常管理工作,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。
  Shell虽然没有C/C++、Python、Java、C#等编程语言强大,但也支持了基本的编程元素,例如:
  1)变量、数组、字符串、注释、加减乘除等概念。
  2)if…else选择结构,for、while、until循环等流程控制语句。
  3)为了方便模块化开发,Shell也支持自定义函数。

  1. Shell脚本的结构和执行:

  Linux的Shell种类众多,常见的有:
  1)Bourne Shell(/usr/bin/sh或/bin/sh)
  2)Bourne Again Shell(/bin/bash)
  3)C Shell(/usr/bin/csh)
  4)K Shell(/usr/bin/ksh)
  5)Shell for Root(/sbin/sh)
  由于易用和免费,Bash在日常工作中被广泛使用。同时,Bash也是大多数Linux系统默认的Shell。在一般情况下,人们并不区分Bourne Shell和Bourne Again Shell,所以,像#!/bin/sh同样也可以改为#!/bin/bash#!是一个约定的标记,告诉系统其后路径所指定的程序即是解释此脚本文件的Shell程序。Shell脚本的扩展名为sh(sh代表Shell),扩展名并不影响脚本执行,见名知意就好,如果用php写Shell脚本,扩展名就用php。

  创建第一个Shell脚本:

[root@rice01 ~]# vi test.sh
#!/bin/bash // 通常以/bin/bash作为标头
echo "Forza Milan !" // echo命令用于向窗口输出文本Forza Milan !
[root@rice01 ~]# chmod +x test.sh // Shell脚本必须要有执行权限
[root@rice01 ~]# ./test.sh
Forza Milan !

  注意,Shell脚本作为可执行程序时,一定要写成./test.sh,而不是test.sh,运行其它二进制的程序也一样,直接写test.sh,Linux系统会去PATH里寻找有没有叫test.sh的,存放Shell脚本的当前目录通常不在PATH里,所以写成test.sh是会找不到命令的,要用./test.sh告诉系统说,就在当前目录找,或者写出完整路径,例如/usr/local/tomcat/bin/startup.sh
  当Shell脚本作为解释器参数,直接运行解释器,其参数就是Shell脚本的文件名,如:

/bin/sh test.sh
/bin/php test.php

  这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

  1. date命令:
命令 含义
date +%Y-%m-%d 输出当前时间,格式为2019-03-07
date +%y-%m-%d 输出当前时间,格式为19-03-07
date +%H:%M:%S 输出当前时间,格式为时:分:秒
date +%T 等同于date +%H:%M:%S
date +%s 时间戳,输出值表示当前时间距离1970年1月1日0时0分0间隔了多少秒
date -d @n 时间戳,n为秒数,表示当前时间之前或之后的n秒是什么时间
date -d “±n day” 当前时间的n天前或后
date -d “±n month” 当前时间的n月前或后
date -d “±n min” 当前时间的n分钟前或后
date -d “±n hour” 当前时间的n小时前或后
date -d “±n week” 当前时间的n周前或后
date +%w 当前时间为星期几
date +%W 当前时间为当年的第几个星期
  1. Shell脚本中的变量:

  变量是任何一种编程语言都必不可少的组成部分,变量用来存放各种数据。脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell变量也遵循这个规则。在Bash Shell中,每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。这意味着,Bash Shell在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串,这一点和大部分的编程语言不同。例如在C/C++ 中,变量分为整数、小数、字符串、布尔等多种类型。当然,如果有必要,也可以使用declare关键字显式定义变量的类型,但在一般情况下没有这个需求,Shell开发者在编写代码时自行注意值的类型即可。
  
定义变量:
  Shell 支持以下三种定义变量的方式:
  variable=value
  variable=‘value’
  variable=“value”
  variable是变量名,value是赋给变量的值。如果value不包含任何空白符(例如空格、Tab缩进等),那么可以不使用引号;如果value包含了空白符,那么就必须使用引号包围起来,并且使用单引号和使用双引号也是有区别的。

url=https://bbs.riceyoung.com
name='RiceYoung'
author="测试"

  注意,赋值号=的周围不能有空格,这和大部分编程语言都不一样。Shell 变量的命名规范和大部分编程语言都一样:变量名由数字、字母、下划线组成;必须以字母或者下划线开头;不能使用Shell里的关键字(通过help命令可以查看保留关键字)。

使用变量:
  使用一个定义过的变量,只要在变量名前面加符号$即可,例如:

test="RiceYoung"
echo $test
echo ${test}

  变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

test="Rice"
echo "My name is ${test}Young"

  如果不给test变量加花括号,写成echo "My name is $testYoung",解释器就会把$testYoung当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
  推荐给所有变量加上花括号{ },这是个良好的编程习惯。

修改变量的值:
  已定义的变量,可以被重新赋值,如:

test="Rice"
echo ${test}
test="RiceYoung"
echo ${test}

  第二次对变量赋值时不能在变量名前加$,只有在使用变量时才能加$

单引号和双引号的区别:

#!/bin/bash
name="RiceYoung"
website1='我的名字是:${name}'
website2="我的名字是:${name}"
echo $website1
echo $website2

  运行结果:

我的名字是:${name}
我的名字是:RiceYoung

  以单引号' '包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。
  以双引号" "包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。
  建议:如果变量的内容是数字,那么可以不加引号;如果真的需要原样输出就加单引号;其他没有特别要求的字符串等最好都加上双引号,定义变量时加双引号是最常见的使用场景。

将命令的结果赋值给变量:
  Shell 也支持将命令的执行结果赋值给变量,常见的有以下两种方式:

variable=`command`
variable=$(command)

  第一种方式把命令用反引号``(位于 Esc 键的下方)包围起来,反引号和单引号非常相似,容易产生混淆,所以不推荐使用这种方式;第二种方式把命令用$()包围起来,区分更加明显,所以推荐使用这种方式。
  例如,在tmp目录中创建一个名为test.txt的文本文件,使用cat命令将test.txt的内容读取出来,并赋值给一个变量,然后使用echo命令输出。

[root@rice01 ~]# vi /tmp/test.txt
Linux学习笔记
[root@rice01 ~]# vi test.sh
#!/bin/bash
cd /tmp/
test=$(cat test.txt)
echo $test
test=`cat test.txt`
echo $test
[root@rice01 ~]# ./test.sh
Linux学习笔记
Linux学习笔记

只读变量:
  使用readonly命令可以将变量定义为只读变量,只读变量的值不能被改变。

[root@rice01 ~]# vi test.sh
#!/bin/bash
myUrl="https://bbs.riceyoung.com"
readonly myUrl
myUrl="https://blog.riceyoung.com"
[root@rice01 ~]# ./test.sh
./test.sh:行4: myUrl: 只读变量

删除变量:
  使用unset命令可以删除变量。语法:unset variable_name
  变量被删除后不能再次使用,unset命令不能删除只读变量。

#!/bin/sh
myUrl="https://bbs.riceyoung.com"
unset myUrl
echo $myUrl

  上面的脚本没有任何输出。

  1. Shell中的逻辑判断:
    格式1:
    if ······; then ······; fi
    格式2:
    if ······; then ······; else ······; fi
    格式3:
    if ······; then ······; elif ······; then ······; else ······; fi

逻辑判断表达式:

字段 含义
if [ $a -gt $b ] 如果a大于b
if [ $a -lt 5 ] 如果a小于5
if [ $b -eq 10 ] 如果b=10
-gt >
-lt <
-ge
-le
-eq =
-ne
&& 并且
|| 或者
  1. if判断文件、目录属性:
字段 含义
[ -f filename ] 判断是否是普通文件,且存在
[ -d filename ] 判断是否是目录,且存在
[ -e filename ] 判断文件或目录是否存在
[ -r filename ] 判断文件是否可读
[ -w filename ] 判断文件是否可写
[ -x filename ] 判断文件是否可执行

  注意:root用户对文件的读写比较特殊,即使一个文件没有给root用户读或者写的权限,root用户照样可以读或者写,但是如果要执行,文件必须要有执行权限。

  1. if判断的一些特殊用法:
字段 含义
if [ -z "$a" ] 如果变量a的值为空
if [ -n "$a" ] 如果变量a的值不为空
if grep -q '123' test.sh 如果test.sh中含有’123’,-q表示不打印结果
if [ ! -e filename ] 如果文件不存在

  注意:[ ]中不能使用< , > , == , != , >= , <=,但是可以使用(())来代替[ ],如:
if (($a<1)); then ······等同于if [ $a -lt 1 ]; then ······

在判断指令有没有执行成功时,除了使用echo %?外,还可以像如下方法判断:

[root@rice01 ~]# if ! ls test; then echo "指令执行错误!"; fi
// 如果ls test执行不成功,则输出‘指令执行错误!'
ls: 无法访问test: 没有那个文件或目录
// 不管指令有没有执行成功,ls test本身都会有输出
指令执行错误!
[root@rice01 ~]# if ! ls test &>/dev/null; then echo "指令执行错误!"; fi
// &>为重定向,不管指令有没有执行成功都不输出内容
指令执行错误!
  1. shell中的case判断:

格式:

case  变量名 invalue1)command;;value2)command;;*)commond;;
esac

案例:

#!/bin/bash
read -p "Please input a number: " n
if [ -z "$n" ]
thenecho "Please input a number."exit 1
fin1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ]
thenecho "Please input a number."exit 1
fiif [ $n -lt 60 ] && [ $n -ge 0 ]
thentag=1
elif [ $n -ge 60 ] && [ $n -lt 80 ]
thentag=2
elif [ $n -ge 80 ]  && [ $n -lt 90 ]
thentag=3
elif [ $n -ge 90 ] && [ $n -le 100 ]
thentag=4
elsetag=0
ficase $tag in1)echo "not ok";;2)echo "ok";;3)echo "ook";;4)echo "oook";;*)echo "The number range is 0-100.";;
esac
  1. for循环:
    语法:for 变量名 in 条件; do ······; done

案例1:

#!/bin/bash
sum=0
for i in `seq 1 100`
dosum=$[$sum+$i]echo $i
done
echo $sum

案例2:

#!/bin/bash
cd /etc/
for a in `ls /etc/`
doif [ -d $a ]thenls -d $afi
done
  1. while循环:
    语法:while 条件; do ······; done

案例1:

#!/bin/bash
while :
doload=`w|head -1|awk -F 'load average: ' '{print $2}'|cut -d. -f1`if [ $load -gt 10 ]thentop|mail -s "load is high: $load" asldkfls@11.comfisleep 30
done

案例2:

#!/bin/bash
while :
doread -p "Please input a number: " nif [ -z "$n" ]thenecho "you need input sth."continuefin1=`echo $n|sed 's/[0-9]//g'`if [ -n "$n1" ]thenecho "you just only input numbers."continuefibreak
done
echo $n
  1. break跳出循环:
#!/bin/bash
for i in `seq 1 5`
doecho $iif [ $i == 3 ]thenbreak // 跳出当前循环fiecho $i
done
echo aaa
  1. continue结束本次循环:
#!/bin/bash
for i in `seq 1 5`
doecho $iif [ $i == 3 ]thencontinue // 忽略当前循环continue后面的代码,直接进行下一次循环fiecho $i
done
echo $i
  1. exit直接退出脚本:
#!/bin/bash
for i in `seq 1 5`
doecho $iif [ $i == 3 ]thenexitfiecho $i
done
echo aaa
  1. 函数:
    函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段代码时直接调用这个小单元的名字即可,函数必须要放在脚本的最前面。

格式:

function f_name()
{ command
}
  1. 数组:
    定义数组:a=(1 2 3 4 5); echo ${a[@]}
    获取数组中元素的个数:echo ${#a[@]}
    读取第三个元素,数组从0开始:echo ${a[2]}
    显示数组的所有元素:echo ${a[*]}等同于${a[@]}
    数组赋值:a[1]=100,给数组里第二个元素赋值为100,如果下标不存在则会自动添加一个元素
    数组的删除:unset a; unset a[1]删除属组或删除数组中某个元素
    数组分片:a=(`seq 1 5`)
    从第一个元素开始,截取3个:echo ${a[@]:0:3}
    从第二个元素开始,截取4个:echo ${a[@]:1:4}
    从倒数第3个元素开始,截取2个echo ${a[@]:0-3:2}
    数组替换:
    将数组中第4个元素的打印结果替换为100:echo ${a[@]/3/100}
    将数组中第4个元素的值替换为100:a=(${a[@]/3/100})

Linux学习笔记(3月6日)相关推荐

  1. Linux学习笔记5月22日任务

    18.6 负载均衡集群介绍 18.7 LVS介绍 18.8 LVS调度算法 轮询:轮着分配,比较均衡: 加权轮询:根据主机配置来,高配轮询多点,低配轮询少点: 最小连接:根据连接数,连接最少的先分配: ...

  2. Linux学习笔记6月1日任务

    20.16/20.17 shell中的函数 $1为第一个参数的值:$2为第二个参数的值:$0为脚本名:$#为参数个数: 获取主机IP地址命令,#ifconfig | grep -A1 "$1 ...

  3. 分享Silverlight/WPF/Windows Phone/HTML5一周学习导读(1月16日-2月5日)

    分享Silverlight/WPF/Windows Phone/HTML5一周学习导读(1月16日-2月5日) 本周Silverlight学习资源更新 WIn2003部署Silverlight coo ...

  4. LINUX学习笔记:31个常用LINUX命令和相关解释

    LINUX学习笔记三: 最近在带新同事,是一个刚入行的萌新,对于linux不是很熟悉,问我怎么来学习. 所以今天接着之前的部分,继续分享一些linux学习资料.有需要的点点保存,没有跳过呗.PS:内容 ...

  5. Linux学习笔记-随即更新-慢速学习

    Linux学习笔记 Linux系统简介 UNIX发展历史和发行版本 开源软件简介 支撑互联网的开源技术 Linux应用领域 Linux学习方法 Linux系统安装 给初学者的建议 学习linux的注意 ...

  6. 史上最牛最强的linux学习笔记 10.shell基础

    史上最牛最强的linux学习笔记 10.shell基础 写在最前面: 本文是基于某站的视频学习所得,第一个链接如下: https://www.bilibili.com/video/BV1mW411i7 ...

  7. Linux学习笔记---命令篇

    Linux学习笔记-命令篇 本笔记是根据尚硅谷的Linux视频,经过自己的总结得出来的笔记,分为两个大章节,一-四章讲的是Linux的文件目录结构.vim编辑器.网络配置和系统管理.进程和服务.第二个 ...

  8. 大数据开发工程师基本功修炼之史上最全Linux学习笔记(建议)

    我正在参加年度博客之星评选,请大家帮我投票打分,您的每一分都是对我的支持与鼓励. 2021年「博客之星」参赛博主:Maynor大数据 (感谢礼品.红包免费送!) https://bbs.csdn.ne ...

  9. 【黑马程序员新版Linux学习笔记】Linux系统实用操作命令——操作演示

    [黑马程序员新版Linux学习笔记]Linux 零基础快速入门: (一)Linux基本命令--操作演示 (二)Linux用户和权限 -- 操作演示 (三)Linux 小技巧快捷键 (四)Linux系统 ...

最新文章

  1. linux svn 重新定位SVN URL
  2. RunLoop总结与面试
  3. [Bootstrap]bootstrap的简单原理
  4. 特斯拉奔驰宝马沃尔沃团灭!安全的半自动驾驶?不存在的
  5. 基础总结篇之六:ContentProvider之读写联系人
  6. iOS应用内付费详解
  7. 【重点BFS】LeetCode 127. Word Ladder
  8. javascript 获得本地 IP 地址
  9. java项目源码分享_ssm项目分享600套
  10. 数字信号处理之均值、方差、均方值、均方差计算和它们的物理意义
  11. 中科大自主招生2018年笔试数学之二
  12. mysql amoeba 配置_mysql amoeba安装配置步骤
  13. 手把手教会你视频转文字怎么弄,这个方法建议收藏备用
  14. 数据结构---树和二叉树03
  15. 计算机网络协议,以太网帧格式
  16. P1139 再分麦粒
  17. 2023年某科技公司前端开发初级岗的面试笔试真题(含选择题答案、问答题解析、机试题源码)
  18. 鱼眼相机的成像模型与畸变校正
  19. 那么问题来了:谷歌为何要出高价旗舰Nexus?
  20. cdns个人博客asp_实学:Java开发自己的博客系统-第十三篇(静态资源和后台模板)...

热门文章

  1. Python小姿势 - #
  2. c语言 队列---->链表实现
  3. 2020更新,Vue模仿探探拖拽卡片的效果
  4. 计算机考研英语题型分值,考研英语题型及分值介绍
  5. 通俗全面理解图卷积与GCN网络(一):图与图卷积
  6. 磁盘/SD/U盘恢复软件推荐:得力数据恢复软件
  7. 5G NR物理层各个步骤各项参数梳理记录
  8. 自学编程后在家兼职靠谱吗?
  9. Mybatis报错ORA-00911: 无效字符
  10. 气传导耳机什么牌子的好,最好的气传导耳机排行榜