





























在我们写.sh文件时要在文档头部做出#!/bin/bash的声明。
#!/bin/bash
echo "Hello World"
……
如上所示,写出声明后我们的bash脚本才可以正常的运行。
其实第一行#!/bin/bash写错或者不写时,系统会有一个默认的解释器进行解释,此处为bash,但是为了标准化我们要加上它!
笔记其余的地方我都会省略这个声明,但是在读者写代码时记得要在你自己写的代码里加上这段声明~
var=Hello World! 就是这么简单就声明了一个全局变量。
varnum=32 但是要注意的是:这样直接声明的变量不论存入的数据是什么类型,都会当做字符串对待。
例如:
varnum=10
varnum2=$varnum + 10
echo $varnum2
输出:10 + 10
可以看出,直接对变量进行增加或进行数学运算是不行的,因为直接声明的变量的类型就是字符串!如果想对变量进行数学运算那么你可能需要declare来帮助你给定义好的变量加上它们应有的“变量类型”
declare [+/-][rxi][变量名称=设置值]
例如:
declare -i numsum
numtest=30
numsum=$numtest+10
echo $numsum
输出:40
可以看出如果我们给numsum这个变量设置好了他的类型,那么在输出的时候就会根据类型对其进行输出。declare也可以更改已经声明好的变量的类型,不是必须要通过declare声明的变量才有效果。
例如:
var=300
declare -i var
也可以将var变量设置为数值型。
注意:假如上面的var这个变量值为文本型或不是数值型或数学表达式的话会将其原有的变量值替换为0,而且无法找回原来的变量内容!
${ variable#[匹配符] } 从这个变量的前面开始删除存储的信息,删除符合匹配条件的第一个。${ variable##[匹配符] } 从这个变量的前面开始删除存储的信息,删除符合匹配条件的最长匹配${ variable%[匹配符] } 从这个变量的后面开始删除存储的信息,删除符合匹配条件的第一个${ variable%%[匹配符] } 从这个变量的后面开始删除存储的信息,删除符合匹配条件的最长匹配var1=${ variable/要替换的内容/替换为 } 从这个变量前面仅寻找要替换的第一个内容,之后替换为新的内容并赋值到一个新变量上。var2=${ variable//要替换的内容/替换为 } 从这个变量前面寻找要替换的全部内容,之后替换为新的内容并赋值到一个新变量上。var1=${ PATH/bin/Bin }
echo $var1
输出 /usr/local/Bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public:/usr/local/mysql/bin
var2=${ PATH//bin/Bin }
echo $var2
输出 /usr/local/Bin:/usr/Bin:/Bin:/usr/sBin:/sBin:/Applications/VMware Fusion.app/Contents/Public:/usr/local/mysql/Bin
不做特殊声明,Shell中变量都是全局变量
定义局部变量时,使用local关键字
如果函数内与函数外变量名重复,那么在函数内会覆盖函数外的全局变量。
局部变量使用local关键字声明
local var_local="Hello World"
例子:
var1="Hello World"
function new
{
local var2="Local Var"
var3="Public Var"
}
new
echo var1=$var1
echo var2=$var2
echo var3=$var3
输出
var1=Hello World
var2=
var3=Public Var
通过例子可以看出用local关键字声明出的var2变量在其所在函数外是无法使用的。
很少会用到,一般来说我们使用if-else来进行替换变量的测试,只不过if-else麻烦一些。变量的检查一般用于初始化变量。
str1=test1
var1=${ str1-default }
echo $var1
test1
var2=${ xxx-default }
echo $var2
default
echo ${ #varstr } 输出varstr字符串变量的字符长度varstr=teststring-HelloWorld!
echo ${ #varstr }
输出 22
${ varstr:num1 } 截取从 num1 开始到末尾的所有字符${ varstr:num1:num2 } 从 num1 开始截取之后的 num2 个字符${ varstr: -num1 } 从末尾向前截取从倒数 num1 个字符开始到末尾的所有字符(注意冒号后有空格)${ varstr: -num1:-num2 } 从末尾向前截取 num2 到 num1 之间的所有字符(注意 -num1 要小于 -num2,下面有例子方便理解)${ varstr: -num1:num2 } 从末尾倒数第num1个字符开始向后截取 num2 个字符${ varstr:num1:-num2 } 从开头第 num1 个的字符截取到倒数第 num2 个字符注意:以这种方式抽取字符串索引是从0开始的,上面所提到的所有数字都是以索引的形式体现。所有符号都是英文,并且在num为负值时在冒号(:)的后面要有一个空格
varstr=Hello,World!
echo ${ varstr:3 }
输出 lo,World!
echo ${ varstr:3:6 }
输出 lo,Wor
echo ${ varstr: -6 }
输出 World!
echo ${ varstr: -6:-3 }
输出 Wor
echo ${ varstr:0:-7 }
输出 Hello
| 实现 | 备注 | |
|---|---|---|
| 方法一 | $() | |
| 方法二 | `` | 注意是反引号,不是单引号 |
在上面已经用到了命令替换,简单来说在用echo输出的时候如果使用命令替换,就会先执行命令,之后把返回值再输出回来。
echo 今年是第 $(date +%Y) 年因为数学计算和命令替换的bash语法很相近,所以一起学习效果会好些吧。
echo 明年是第 $(( $(date +%Y) +1))年比如:
echo "3.14*3.14" | bc
*注意咯,使用bc时默认保留小数点两位,如果可以整除的时候这两位也给你省去了!如果想保留更高精度的数,你需要使用scale。**
浮点数的小数位数是由内建变量scale控制的。必须将这个值设置为你希望在计算结果中保留的小数位,否则无法得到期望的结果
echo "scale=6;3.14*3.14" | bc 定义函数有两种方法:
function f1
{
echo "这是第一种定义函数的方法"
echo "传入参数$1"
}
f2()
{
echo "这是第二种定义函数的方法"
echo "传入参数$1"
}
f1 "lalalal"
f2 "lalallalal"
输出:
这是第一种定义函数的方法
传入参数lalalal
这是第二种定义函数的方法
传入参数lalallalal
函数有两种返回值的方法
| 代码 | 备注 |
|---|---|
| return | return通常用来返回执行状态!执行成功返回 0 执行失败返回 1 ,返回值范围(0~255) |
| echo | echo通常用来返回字符串或一个列表 |
例如现在要定义一个函数库,要满足以下几个函数:
1、加法函数add
2、减法函数reduce
3、乘法函数multiple
4、除法函数divide
5、打印系统的运行情况的函数sys_info,该函数用来显示内存运行情况。
function add
{
echo $(($1+$2))
}
function reduce
{
echo $(($1-$2))
}
function multiple
{
echo $(($1\*$2))
}
function divide
{
echo $(($1/$2))
}
function sys_info
{
echo "内存的情况:"
echo `free -m`
echo "================================="
echo "硬盘剩余空间:"
echo `df -h`
}
OK,我们写好了一个函数库,把它命名为lib_test。现在需要来写一个普通脚本去调用我们的函数库。
#!/bin/bash
. ./lib_test
add 1 3
reduce 5 2
multiple 5 2
divide 9 3
sys_info
if [ 条件语句 ];then
满足条件执行的内容
else if [ 条件语句 ];then
第一个if条件不满足,但第二个条件满足执行的内容
else
都不满足条件后执行内容
fi
现在我们通过一个实例来学习if
要求:
1、检测nginx服务是否正在运行
2、如果检测到nginx服务已经宕掉,那么重新启动它!
3、在测试的时候先把nginx服务手动停止service nginx stop
#!/bin/bash
if [ `ps -ef | grep nginx | grep -v grep | wc -l` -eq 0 ];then
echo "Nginx服务已宕掉!"
service nginx start
echo "Nginx已经重新启动!"
else
echo "Nginx服务正常"
fi
输出:
Nginx服务已宕掉!
Starting nginx... done
Nginx已经重新启动
刚才学习了if条件判断,我们可以来监测nginx服务是否宕掉,但是它需要我们每次都执行它这个脚本才能够去检测nginx。那么如果知道了while循环,是不是就可以循环去监测它了?
while 条件语句
do
满足条件执行的内容
done
例子要求:那么我们在if的例子基础上来完善一下它,让它每隔1分钟就检测一下Nginx服务
while true
do
if [ `ps -ef | grep nginx | grep -v grep | wc -l` -eq 0 ];then
echo "Nginx服务已宕掉!"
service nginx start
echo "Nginx已经重新启动!"
else
echo "Nginx服务正常"
fi
sleep 60
done
我们使用while-true死循环来重复监测Nginx服务,每次循环过后都休眠60s后再次执行循环体!
第一种形式:stdout | sed [option] "pattern command"第二种形式:sed [option] "pattern command" fileaddress stdout意思为通过管道 | 将文本传入给后面的命令。Linux sed 命令是利用脚本来处理文本文件。
sed 可依照脚本的指令来处理、编辑文本文件。
sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。
| 选项 | 含义 |
|---|---|
| -n | 只打印模式匹配行 |
| -e | 直接在命令行进行sed编辑,默认选项 |
| -f | 编辑的操作方式保存在文件中,指定文件执行 |
| -r | 支持扩展正则表达式 |
| -i | 直接修改文件内容(将所作的修改保存到文件中) |
需要注意的是sed在处理文本时默认每一行都会输出出来,如果只想打印与自己设置好的匹行,需要选项中使用-n
echo "I Like python \nI Like Python \nI Like PYTHON" > text.txt
sed n text.txt
输出:
I Like python
I Like Python
I Like PYTHON
sed '/python/p' text.txt
输出:
I Like python
I Like python
I Like Python
I Like PYTHON
你会发现为什么I Like python会输出两行,而且还把其他的输出出来了?
需要注意的是sed在处理文本时默认每一行都会输出出来,如果只想打印与自己设置好的匹行,需要选项中使用`-n`
sed -n '/python/p' text.txt
输出:
I Like python
这回没有问题了,去掉非匹配行,留下的就是我们想要的!
sed -n -e '/python/p' -e '/PYTHON/p' text.txt
输出:
I Like python
I Like PYTHON
使用 -e 可以连接两个或多个匹配规则
| 匹配模式 | 作用 | 注意 |
|---|---|---|
8p |
打印第8行的内容 | |
8,10p |
打印第8行到第10行的内容 | 包含第8行和第10行 |
8,+5p |
打印第8行和其之后的5行 | 包含第8行 |
/正则表达式/p |
打印匹配正则表达式的行 | |
/正则表达式_1/,/正则表达式_2/p |
打印匹配正则表达式1和2之间的行 | |
8,/正则表达式/p |
打印第8行起直到匹配到正则表达式匹配行之间的所有内容 | |
/正则表达式/,8p |
打印从匹配到正则表达式开始到第8行之间的所有内容 |
| 功能 | 指令 | 备注 |
|---|---|---|
| 查 | p |
打印匹配的内容 |
| 删 | d |
删除匹配的内容 |
| 增 | a |
在匹配行的后一行追加内容 |
| 增 | i |
在匹配行的前一行增加一行内容 |
| 改 | s/匹配模式/要修改的内容/ |
查找符合匹配模式的字符串,将其匹配到的第一个字符串进行替换 |
| 改 | s/匹配模式/要修改的内容/g |
查找符合匹配模式的字符串,将匹配到的所有的字符串都进行替换 |
| 改 | s/匹配模式/要修改的内容/2g |
只替换从第二个符合匹配模式后面的所有字符串 |
| 改 | s/匹配模式/要修改的内容/ig |
忽略大小写查找符合匹配模式的字符串,将匹配到的所有字符串都进行替换 |
= 可以显示输出的行号例如:sed = /etc/passwd
以上是sed流编辑器的学习内容和笔记。
awk 是一个文本处理工具,通常用于处理数据或者生成结果报告
第一种形式:awk [BEGIN{ }]匹配模式{ command命令 }[END{ }] 文件路径第二种形式:stdout | awk [BEGIN{ }]匹配模式{ command命令 }[END{ }]stdout意思为通过管道 | 将文本传入给后面的命令。| 语法格式 | 解释 |
|---|---|
BEGIN{ } |
正式处理数据之前执行 |
pattern |
匹配格式 |
{ command } |
处理命令 |
END |
处理完所有匹配数据后执行 |
一行简单的awk命令:awk 'BEGIN{ FS=":" }{ print $1 }' /etc/passwd
它输出的是passwd中所有用户的用户名。那么FS,print,$1…都代表什么意思?这里引入awk的内置变量以及command命令
| 内置变量 | 含义 |
|---|---|
$0 |
整行内容 |
$1-$n |
当前行的第1-n个字段 |
NF |
当前行的字段个数,也就是有多少列 |
NR |
当前行的行号,从1开始计数 |
FNR |
在处理多个文件时,每个文件的行号单独计数不累加,每个文件从1开始计数 |
FS |
输入字段的分隔符。不指定时默认以空格或者tab键分割 |
RS |
输入行的分隔符。不指定时默认为回车换行 |
OFS |
输出字段分隔符。默认为空格 |
ORS |
输出行分隔符。默认为回车换行 |
| 格式符 | 含义 |
|---|---|
%s |
打印字符串 |
%d |
打印10进制数 |
%f |
打印浮点数 |
%x |
打印16进制数 |
%o |
打印8进制数 |
%e |
打印数字的科学技术法格式 |
%c |
打印单个字符的ACSII码 |
| 修饰符 | 含义 |
|---|---|
- |
左对齐 |
+ |
右对齐 |
# |
显示8进制在前面加0,16进制在前面加0x |
例子:
awk 'BEGIN{ FS=":" }{ printf "%s",$7 }' /etc/passwd
awk 'BEGIN{ FS=":" }{ printf "%s\n",$7 }' /etc/passwd
1、匹配/etc/passwd文件行中含有root字符串的所有行awk 'BEGIN{ FS=":" }/root/{ print $0 }' /etc/passwd
2、匹配/etc/passwd文件行中以sshd开头的所有行awk 'BEGIN{ FS=":" }/^sshd/{ print $0 }' /etc/passwd
| 关系运算符 | 解释 |
|---|---|
| < | 小于 |
| > | 大于 |
| <= | 小于等于 |
| >= | 大于等于 |
| == | 等于 |
| != | 不等于(可用于字符串) |
| ~ | 匹配正则表达式 |
| !~ | 不匹配正则表达式 |
| 匹配表达式(只与关系运算符连用) | 解释 |
|---|---|
| || | 或 |
&& |
与 |
! |
非 |
例子:
:为分隔符,匹配/etc/passwd文件中第三个字段小于50的所有行信息awk 'BEGIN{ FS=":" }$3<50{ print $0 }' /etc/passwd:为分隔符,匹配/etc/passwd文件中第三个字段等于0的行信息awk 'BEGIN{ FS=":" }$3==0{ print $0 }' /etc/passwd:为分隔符,匹配/etc/passwd文件中第七个字段不等于/bin/bash所有行信息awk 'BEGIN{ FS=":" }$7!="/bin/bash"{ print $0 }' /etc/passwdawk 'BEGIN{ FS=":" }$1~/^root/{ print $0 }' /etc/passwd:为分隔符,匹配/etc/passwd文件中第一个字段等于root或sshd的所有行信息awk 'BEGIN{ FS=":" }$1=="root"||$1=="sshd"{ print $0 }' /etc/passwdawk的if判断与C语言基本一致。下面是awk中if语句格式的举例:
if($3>50)
{
print $0
}
else
{
printf "%s%s%s\n","该用户:",$1,"的UID小于50"
}
如果现在要求输出UID大于50的用户信息要咋办呢?可以看下面的这个例子。
awk 'BEGIN{ FS=":" }
{
if($3>50)
{
print $0
}
else
{
printf "%s%s%s\n","该用户:",$1,"的UID小于50"
}
}' /etc/passwd
将上面的命令直接复制到终端里便可以运行,但是这样是不是编写起来有些不太方便?
所以我更愿意将上面的一些命令抽象出一个awk脚本,然后让awk -f去运行这个脚本,这样思路和结构也会更清楚一些。
那现在来建立一个awk脚本:vim if-else.awk进入编辑模式,键入以下内容:
BEGIN{ FS=":" }
{
if($3>50)
{
print $0
}
else
{
printf "%s%s%s\n","该用户:",$1,"的UID小于50"
}
}
保存后我们可以使用-f选项来使用这个awk脚本:
awk -f if-else.awk /etc/passwd
这样一来命令也很清晰很多了,舒服的一批!
拿一个从1一直加到100的这个小学问题来当做学习循环的例子吧~
1、while循环:
vim while.awk
BEGIN{
while(i<=100)
{
sum+=i
i++
}
print sum
}
awk -f while.awk
2、do-while循环:
vim do-while.awk
BEGIN{
do{
sum+=i
i++
}
while(i<=100)
print sum
}
3、for循环:
vim for.awk
BEGIN{
for(i=1;i<=100;i++){
sum+=i
}
print sum
}
我是一名Linux初学者,如果你与我一样喜欢折腾,喜欢Linux,那么请加入我的电报群https://t.me/yeefire_blog,在这里畅所欲言,共同学习进步。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。