Linux 笔记 - 第十二章 Shell 脚本
一、前言
常见的编程语言分为两类:一类是编译型语言,如:C、C++ 和 Java等,它们远行前要经过编译器的编译。另一类是解释型语言,不需要编译,执行时,需要使用解释器一行一行地解释执行,如:awk、perl、python 和 shell 等。
Shell 是一种脚本语言,属于上面提到的第二类语言,就必须有对应的解释器来执行这些脚本,最常见的脚本解释器是:bash。
在编写 Shell 脚本时,我们不仅会用到很多的 Linux 命令、正则表达式、管道符、数据流重定向等语法规则,还需要把内部功能模块化后通过逻辑语句进行处理,最终形成常见的 Shell 脚本。
1.1 查看系统支持的 Shell 种类
Linux 的 Shell 种类众多,常见的有:
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)
可以通过查看 /etc/shells,知道当前系统所支持的所有 shell 类型及路径,如下:
[root@ryan ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
……
Bourn Shell 是最早流行起来的一个 Shell 版本,其创始人是 Steven Bourn,为了纪念他而将其命名为 Bourn Shell,简称 sh。RedHat 系列的 Linux 发行版默认也安装了 Bash,也就是 Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。
1.2 查看当前用户使用的 Shell 种类
可以通过执行 echo $SHELL 查看,如下:
[root@ryan ~]# echo $SHELL
/bin/bash
或者查看 /etc/passwd,以查看 root 用户的 Shell 类型为例,如下:
[root@ryan ~]# cat /etc/passwd | grep ^root
root:x:0:0:root:/root:/bin/bash
最后一个:号后显示的字段即为 root 用户的登录 shell 类型,此处为 bash。
也可以直接输入命令 echo $0 查看,但需要注意的是并不是所有的 Shell 都支持,如下:
[root@ryan ~]# echo $0
-bash
当然也可以在当前环境变量中查看,如下:
[root@ryan ~]# env | grep SHELL
SHELL=/bin/bash
其实,查看当前用户 Shell 种类的方法还有很多。
1.3 查看 Shell 版本
在获得当前使用的 shell 的类型后,用户可以直接使用 shell 相关的命令参数获取其版本号,一般都可以使用 --version 参数来获取 shell 的版本号,如下:
[root@ryan ~]# bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
二、常用 Shell 操作
2.1 命令 date
date 命令的常用的格式化选项:
date +%Y:表示以四位数字格式打印年份;
[root@ryan ~]# date +%Y
2018
date +%y:表示以两位数字格式打印年份;
[root@ryan ~]# date +%y
18
date +%m:表示月份;
[root@ryan ~]# date +%m
04
date +%d:表示日期;
[root@ryan ~]# date +%d
14
date +%H:表示小时;
[root@ryan ~]# date +%M
13
date +%M:表示分钟;
[root@ryan ~]# date +%M
04
date +%S:表示秒;
[root@ryan ~]# date +%S
46
date +%w:表示星期,如果结果显示 0 则表示周日;
[root@ryan ~]# date +%w
6
date +%F:表示年月日;
[root@ryan ~]# date +%F
2018-04-14
date +%T:表示时分秒;
[root@ryan ~]# date +%T
14:08:57
date +"%Y-%m-%d %H:%M:%S",显示如下:
[root@ryan ~]# date +"%Y-%m-%d %H:%M:%S"
2018-04-14 14:10:43
date +"%F %T",显示和上面相同。
有时候会用到前一天的日期,如下:
[root@ryan ~]# date -d "-1 day" +"%d"
13
或者后一天的日期,如下:
[root@ryan ~]# date -d "+1 day" +"%d"
15
同理可以设置小时,分钟等。
2.2 数学运算
数学运算的时候要用 [ ] 括起来,并且前面要加符号 $
[root@ryan ~]# a=2;b=3
[root@ryan ~]# ab=$[$a+$b]
[root@ryan ~]# echo $ab
5
定义变量的格式是:
变量名=变量值
定义之后引用该变量时要加上符号 $,如下:
$ab
如果变量的值是 shell 命令,则需要加反引号,它的作用是将引号中的字符串当成 shell 命令来执行。
2.3 和用户交互
read 命令用于和用户交互,它把用户输入的字符串作为变量值。如下:
[root@ryan shelltest]# cat readtest.sh
#!/bin/bash
## This Shell script is used for testing read
read -p "Please input a number:" n
echo $n
[root@ryan shelltest]# ./readtest.sh
Please input a number:5
5
也可添加 -t 选项,设置 3 秒后退出,如下:
read -t 3 -p "Please input a number:" n
2.4 Shell 脚本预设的特殊变量
$* 和 $@ 的区别为: $* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。
$? 可以获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。
2.5 转义字符
在 echo 中可以用于的转义字符有:
2.6 Shell 中的引号
Shell 中的引号主要有单引号,双引号和反引号。
单引号
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
单引号字串中不能出现单引号(对单引号使用转义符后也不行)。
[root@ryan shelltest]# echo '$HOME'
$HOME
双引号
双引号里可以有变量;
双引号里可以出现转义字符。
[root@ryan shelltest]# echo "$HOME"
/root
反引号
反引号中的字符串当成 shell 命令来执行。
[root@ryan shelltest]# echo Today is `date +%F`
Today is 2018-04-14
得到文件名,使用 basename,如下:
[root@ryan shelltest]# basename /root/linux/shelltest/fortest.sh
fortest.sh
得到目录名,使用 dirname,如下:
[root@ryan shelltest]# dirname /root/linux/shelltest/fortest.sh
/root/linux/shelltest
2.7 执行 Shell
有两种方式可以执行 Shell,如下:
第一种:
sh filename.sh
如果想调试你的脚本,bash给我们提供了两个选项:-v 和 -x,如下:
[root@ryan shelltest]# cat iftest.sh
#! /bin/bash
## This shell script is used for testing if
echo "file name $(basename $0)"
echo "Hello $1"
echo "Hello $*"
echo "Args count: $#"
argscount=$#
if [ $argscount -eq ];
then
echo 'args count is correct'
elif [ $argscount -gt ];
then
echo 'args count is more than 3'
else
echo 'args count is less than 3'
fi
如果我们想逐行详细地查看脚本的内容,可以使用 -v 选项。
[root@ryan shelltest]# sh -v iftest.sh a
#! /bin/bash
## This shell script is used for testing if
echo "file name $(basename $0)"
file name iftest.sh
echo "Hello $1"
Hello
echo "Hello $*"
Hello a
echo "Args count: $#"
Args count:
argscount=$#
if [ $argscount -eq ];
then
echo 'args count is correct'
elif [ $argscount -gt ];
then
echo 'args count is more than 3'
else
echo 'args count is less than 3'
fi
args count is correct
更常用的是 -x 选项,它们在执行时显示命令。当我们决定选择分支的时候,更加实用。
[root@ryan shelltest]# sh -x iftest.sh a
++ basename iftest.sh
+ echo 'file name iftest.sh'
file name iftest.sh
+ echo 'Hello 1'
Hello
+ echo 'Hello 1 3 a'
Hello a
+ echo 'Args count: 3'
Args count:
+ argscount=
+ '[' -eq ']'
+ echo 'args count is correct'
args count is correct
第二种:
./filename.sh(需要有执行权限,所以一般要先授予 x 权限)
三、shell 运算符
3.1 算数运算符
原生 bash 不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr。下面使用 expr 进行; expr 是一款表达式计算工具,使用它可以完成表达式的求值操作;
3.2 关系运算符
只支持数字,不支持字符串,除非字符串的值是数字。常见的有:
也可以直接使用符号比较,但要同时使用双括号,如下:
< 小于(需要双括号) (( "$a" < "$b" ))
<= 小于等于(...) (( "$a" <= "$b" ))
> 大于(...) (( "$a" > "$b" ))
>= 大于等于(...) (( "$a" >= "$b" ))
3.3 布尔运算符
-o(--or,也可以用 [ $a -lt 20 ] || [ $b -gt 100 ]),-a(--and,也可以用 [ $a -lt 20 ] && [ $b -gt 100 ])
3.4 字符串运算符
常用的有 -z,判断变量的值是否存在,不存在返回 true,存在则返回 false。
3.5 文件测试运算符
常用的有 -e(--exist,判断文件或目录是否存在),-d(--directory,判断是否目录已经是否存在),-f(--file,判断是否普通文件已经是否存在)
四、Shell 中的流程控制
4.1 if 条件选择
[root@ryan shelltest]# cat iftest.sh
#! /bin/bash
## This shell script is used for testing if
echo "file name $(basename $0)"
echo "Hello $1"
echo "Hello $*"
echo "Args count: $#"
argscount=$#
if [ $argscount -eq 3 ];
then
echo 'args count is correct'
elif [ $argscount -gt 3 ];
then
echo 'args count is more than 3'
else
echo 'args count is less than 3'
fi
运行如下:
[root@ryan shelltest]# sh iftest.sh 3 5 a
file name iftest.sh
Hello 3
Hello 3 5 a
Args count: 3
args count is correct
[root@ryan shelltest]# sh iftest.sh 3 5
file name iftest.sh
Hello 3
Hello 3 5
Args count: 2
args count is less than 3
[root@ryan shelltest]# sh iftest.sh 3 5 a b
file name iftest.sh
Hello 3
Hello 3 5 a b
Args count: 4
args count is more than 3
4.2 case 条件选择
[root@ryan shelltest]# cat casetest.sh
#!/bin/bash
## This shell script is used for testing case
read -p "Input a number:" n
a=$[$n%2]
case $a in
1)
echo "The number is odd."
;;
0)
echo "The number is even."
;;
*)
echo "It's not a number!"
;;
esac
运行如下:
[root@ryan shelltest]# sh casetest.sh
Input a number:4
The number is even.
[root@ryan shelltest]# sh casetest.sh
Input a number:5
The number is odd.
4.3 while 循环
[root@ryan shelltest]# cat whiletest.sh
#!/bin/bash
## This shell script is used for testing while
a=5
while [ "$a" -ge "1" ]; do
echo $a
a=$[$a-1]
done
运行如下:
[root@ryan shelltest]# sh whiletest.sh
5
4
3
2
1
4.4 for 循环
[root@ryan shelltest]# cat fortest.sh
#!/bin/bash
## This shell script is used for testing for
for file in `ls /root/linux/shelltest`;
do
ls -ld /root/linux/shelltest/$file
done
运行如下:
[root@ryan shelltest]# sh fortest.sh
-rwxr-xr-x 1 root root 233 Apr 14 17:33 /root/linux/shelltest/casetest.sh
-rw-r--r-- 1 root root 18 Apr 13 20:49 /root/linux/shelltest/field.properties
-rwxr-xr-x 1 root root 141 Apr 14 17:40 /root/linux/shelltest/fortest.sh
-rwxr-xr-x 1 root root 211 Apr 13 20:48 /root/linux/shelltest/funcomp.sh
-rwxr-xr-x 1 root root 235 Apr 13 20:47 /root/linux/shelltest/funtest.sh
-rwxr-xr-x 1 root root 321 Apr 13 20:46 /root/linux/shelltest/iftest.sh
-rwxr-xr-x 1 root root 101 Apr 14 14:37 /root/linux/shelltest/readtest.sh
-rwxr-xr-x 1 root root 113 Apr 13 20:46 /root/linux/shelltest/whiletest.sh
4.5 引入其他 Shell
方法一:使用 .
#!/bin/bash
. firstshell.sh
echo 'your are in second file'
方法二:使用 source
#!/bin/bash
source firstshell.sh
echo 'your are in second file'
4.6 Shell 中的中断和继续
break,用于循环中,表示退出该层循环到上一层;
continue,用于循环中,表示结束本次循环,开始下次循环;
exit,用在任何地方,表示退出 shell 脚本;
return,用在函数中,表示返回,退出函数;
这几个命令与 C、Java 等语言中对应的关键字的作用一样。
4.7 命令 seq
seq - print a sequence of numbers,用于产生从某个数到另外一个数之间的所有整数。
语法格式为:
seq [选项] 尾数
seq [选项] 首数 尾数
seq [选项] 首数 增量 尾数
常用选项为:
-f, --format=格式 使用 printf 样式的浮点格式;
-s, --separator=字符串 使用指定字符串分隔数字(默认使用:\n);
-w, --equal-width 在列前添加 0 使得宽度相同;
[root@ryan shelltest]# seq 8
1
2
3
4
5
6
7
8
[root@ryan shelltest]# seq 3 8
3
4
5
6
7
8
[root@ryan shelltest]# seq 3 2 8
3
5
7
此处的 2 为增量,也被称为步长。
shell 示例
从 top 命令中提取出 time,cpu 百分比和使用的内存容量三种数据到三个不同的文本中,然后进行合并。
#! /bin/bash
## extract_time_cpu_memory.sh filename
## Extract the time, cpu and memory data from the top output file
## moonxy -- filename=$
if [ -z "${filename}" ]
then
filename=/tmp/top.out
echo "default top output file name is : $filename"
fi if [ ! -e "${filename}" ]
then
echo "Cann't find top output file : $filename, please check it"
exit
fi
echo "top output file is : $filename" ## Extract time data from the top output file
cat ${filename} | grep "top - " | cut -d ',' -f | awk '{print $3}' > /tmp/top_time.out ## Extract cpu data from the top output file
cat ${filename} | grep "%Cpu(s)" | cut -d ',' -f | awk '{print $2}' > /tmp/top_cpu.out ## Extract memeory data from the top output file
cat ${filename} | grep "KiB Mem" | cut -d ',' -f | awk '{print $1}' > /tmp/top_memory.out ## Add the time-cpu table head
echo 'Time,Cpu(%)' > /tmp/time_cpu_memory.out ## Merge the data by one column mapping one column
paste -d',' /tmp/top_time.out /tmp/top_cpu.out >> /tmp/time_cpu_memory.out ## Append five lines for the result
echo >> /tmp/time_cpu_memory.out
echo >> /tmp/time_cpu_memory.out
echo >> /tmp/time_cpu_memory.out
echo >> /tmp/time_cpu_memory.out
echo >> /tmp/time_cpu_memory.out ## Add the time-memory table head
echo 'Time,Memory(Used KiB)' >> /tmp/time_cpu_memory.out ## Append and then Merge the data by one column mapping one column
paste -d',' /tmp/top_time.out /tmp/top_memory.out >> /tmp/time_cpu_memory.out echo 'result file name is : /tmp/time_cpu_memory.out'
exit
注意:
1. 执行 shell 脚本时,事实上是会新开一个 shell 进程,然后逐行执行你的脚本,上面使用 exit 只是退出这个新开的 shell 进程,并不会影响系统原有 shell 环境。
2. return 仅能用于函数中或者使用 source a1.sh(或 . a1.sh)中使用,不能直接用于脚本中。
3. 追加空白行可使用:echo >> /tmp/time_cpu_uatdb.out
Linux 笔记 - 第十二章 Shell 脚本的更多相关文章
- Linux 笔记 - 第二十二章 Nginx 配置 SSL
一.前言 基础知识 1.1 公钥密码体制(public-key cryptography) 公钥密码体制分为三个部分,公钥.私钥.加密解密算法,它的加密解密过程如下: 加密:通过加密算法和公钥对内容( ...
- Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验
Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...
- [CSAPP笔记][第十二章并发编程]
第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟 ...
- o'Reill的SVG精髓(第二版)学习笔记——第十二章
第十二章 SVG动画 12.1动画基础 SVG的动画特性基于万维网联盟的“同步多媒体集成语言”(SMIL)规范(http://www.w3.org/TR/SMIL3). 在这个动画系统中,我们可以指定 ...
- Linux 笔记 - 第十四章 LAMP 之(二) 环境配置
博客地址:http://www.moonxy.com 一.前言 LAMP 环境搭建好之后,其实仅仅是安装上了软件,我们还需要掌握 httpd 和 PHP 的配置. 二.httpd 配置 2.1 创建虚 ...
- Linux学习笔记(第十二章)
grep进阶 grep:以整行为单位进行截取 截取的特殊符号 正规表示法特殊字符 注意: sed用法 格式化打印 awk 用法 diff档案对比: path旧文档升级为新文档
- Linux 笔记 - 第十六章 LNMP 之(一) 环境搭建
博客地址:http://www.moonxy.com 一.前言 LNMP 中的 N 指 Nginx,在静态页面的处理上,Nginx 较 Apache 更胜一筹:但在动态页面的处理上,Nginx 并不比 ...
- Linux 笔记 - 第十五章 MySQL 常用操作和 phpMyAdmin
博客地址:http://www.moonxy.com 一.前言 前面几章介绍了 MySQL 的安装和简单的配置,只会这些还不够,作为 Linux 系统管理员,我们还需要掌握一些基本的操作,以满足日常管 ...
- Linux 笔记 - 第十四章 LAMP 之(一) 环境搭建
博客地址:http://www.moonxy.com 一.前言 LAMP 是 Linux Apache MySQL PHP 的简写,即把 Apache.MySQL 以及 PHP 安装在 Linux 系 ...
随机推荐
- .net软件开发脚本规范-SQL脚本标准
一. SQL脚本标准 各文件夹存放的脚本说明 存储过程:除“基础_”开头的所有存储过程,包含新增.修改.删除.列表.提交.审核. 基础数据:“基础_”开头的存储过程,用于下拉列表的数据加载公共方法. ...
- 教你如何认识人脸识别开发套件中的双目摄像、3D结构光摄像头、单目摄像头的区别及详细讲解
深圳市宁远电子提供的人脸识别模组可支持双目摄像头和3D结构光摄像头,在客户咨询中经常有被问到双目的为什么会比单目的成本高,区别在哪里,他们的适用于哪些场景呢?在此,深圳市宁远电子技术工程师就为大家详细 ...
- 右键新建 .md
右键新建 .md 文件 声明:虽然我成功了,并且右键出来了两个,但是在添加 .html 的过程中又失败了,找不到解决办法. win + r --> regedit --> enter 点击 ...
- import 和from…import
import 和from-import 一.import模块名 import time print(time.time()) import首次导入模块发生了3件事: 使用import time导入的时 ...
- 轻松pick移动开发第二篇,rem布局
一.为什么要使用rem布局 前面我写了flex布局的优点,分配伸缩盒容器中子盒子占的份数及排列方式,使其不受屏幕缩放的影响,使布局变得简单.然而,在有些时候,不可避免要给盒子设置高度的值,怎么让高度也 ...
- JVM知识点总结
JVM总体梳理 一.jvm体系总体概览 JVM体系总体分四大块:类的加载机制.jvm内存结构.GC算法 垃圾回收.GC分析 命令调优 这里画了一个思维导图,将所有的知识点进行了陈列,因为图比较大可以点 ...
- 【CocosBuilder】学习笔记目录
从2019年8月底开始学习CocosBuilder. CocosBuilder 学习笔记(1) CCBReader 解析.ccbi文件流程 CocosBuilder 学习笔记(2) .ccbi 文 ...
- 《阿里巴巴Java开发手册1.4.0》阅读总结与心得(三)
(六)工程结构 (一)应用分层 1. [推荐]图中默认上层依赖于下层,箭头关系表示可直接依赖,如:开放接口层可以依赖于Web 层,也可以直接依赖于 Service 层,依此类推: 开放接口层: ...
- xcode7中搭建python开发环境
1. 双击打开Xcode 2. 点击File->New->New Project 3. 在左边的面板选择Other,右边选择External Build Sytem,点击Next 4. 输 ...
- HDU5988 - 2016icpc青岛 - G - Coding Contest 费用流(利用对数化乘为加
HDU5988 题意: 有n个区域,每个区域有s个人,b份饭.现在告诉你每个区域间的有向路径,每条路有容量和损坏路径的概率.问如何走可以使得路径不被破坏的概率最小.第一个人走某条道路是百分百不会损坏道 ...