惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
O
OpenAI News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
Webroot Blog
Webroot Blog
GbyAI
GbyAI
S
SegmentFault 最新的问题
Cyberwarzone
Cyberwarzone
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
J
Java Code Geeks
Google DeepMind News
Google DeepMind News
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 【当耐特】
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
S
Security Affairs
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
D
DataBreaches.Net
云风的 BLOG
云风的 BLOG
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
Spread Privacy
Spread Privacy
T
Threatpost
Forbes - Security
Forbes - Security
C
Cisco Blogs
Scott Helme
Scott Helme
Attack and Defense Labs
Attack and Defense Labs
Simon Willison's Weblog
Simon Willison's Weblog
腾讯CDC
The Last Watchdog
The Last Watchdog
Cloudbric
Cloudbric
Last Week in AI
Last Week in AI
Recorded Future
Recorded Future
小众软件
小众软件
V
Vulnerabilities – Threatpost
美团技术团队
人人都是产品经理
人人都是产品经理
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
Hacker News - Newest:
Hacker News - Newest: "LLM"
I
Intezer
月光博客
月光博客
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园 - 司徒正美
C
Cybersecurity and Infrastructure Security Agency CISA
Martin Fowler
Martin Fowler
博客园 - 聂微东

Yee's Blog

腾讯云/轻量云 安装ArchLinux的个人记录 记录我的联想M720Q Arch Sway窗口管理器的安装和配置过程 Jenkins Linux安装 腾讯课堂、钉钉在线网课视频直播回放下载离线播放 Ceph块设备对RBD块设备操作LVM创建PV时报错 Ceph映射RBD块设备 2020年9月26日前端部门Vue考核 2020年9月26日后端部门Python考核 Nginx反向代理下载传输超过1G大文件时断开问题 Windows Server 2019 Datacenter M720q 安装记录 Ceph块设备基础及快照、克隆操作 从Ceph集群中删除OSD节点 Centos8配置 chrony NTP服务端及客户端 搭建Ceph集群 Ceph硬件准备 OSD与Pool池的常见操作及管理 Ceph用户管理 MacOS睡眠管理——让你的Mac睡的更香 初中古诗文必背篇目 Ansible 技巧之场 Ansible 包含和导入文件 Ansible 学习文档 Ansible 主机模式 Ansible 角色 Ansible 调整连接数 Splunk数据搜索和报表 Ansible 常用模块 Ansible 变量和事实 Ansible 任务控制 Ansible Playbook Ansible 基础概念 42Team-Flask框架-HTTP协议快速了解 42Team-Flask框架-路由和视图 42Team-Flask框架-请求与响应 42Team-Flask框架 42Team-Flask框架-Flask介绍 42Team-Flask框架-使用Pycharm来构建一个全新的Flask项目 How to install RHEL8(Centos) on Dell R710/R610 server Centos8安装Docker报错解决方案 Centos8安装Docker后容器内无法访问网络 Docker或Podman容器内无法解析DNS问题多种解决方案 使用NetworkManager来管理树莓派Ubuntu系统网络以及个人的体验优化 Linux 存储设备的挂载及识别 Firewalld 防火墙常用指令教程-常用规则(禁止Ping | 放行端口) Linux 查找系统中的文件 Linux 守护进程和控制服务 Linux SSH远程访问 42Team小组_Linux基础培训课件 如何在AmazeUI中当改变select标签后触发Vue方法的问题 使用Docker部署安装WordPress博客平台 在Raspberry树莓派中搭建NFS存储服务器 在 树莓派 Linux 中搭建匿名 danted socks5 代理服务器 HTTP与HTTPS区别随笔
Bash/Shell学习笔记
本文作者: YeeFire · 2020-02-21 · via Yee's Blog
  • Bash/Shell学习笔记
    • Bash脚本的声明
    • 变量
      • 定义变量
      • 定义有类型的变量
      • 变量的删除
      • 变量的替换
      • 局部变量和全局变量
        • 局部变量
      • 变量的测试
    • 字符串的处理
      • 计算字符串的长度
      • 抽取子串
    • 命令替换和数学运算
      • 命令替换
      • 数学计算
        • 1、用$(( ))来表达数学计算,和命令替换一起使用时要注意括号的个数
        • 2、使用bc来处理浮点型数学运算
    • 函数
      • 定义函数
      • 函数的返回值
      • 函数库
    • 条件、判断、分支
      • if判断
      • while循环
    • sed 流编辑器
      • 简介:
      • 选项 option(常用)
      • sed 的匹配模式
      • sed 的增删改查
      • sed 的显示行号
    • awk 文本处理器
      • 语法格式说明
      • 内置变量
      • 格式化输出 printf
      • awk 匹配模式
        • 正则表达式匹配
        • 关系运算符匹配
      • awk中的判断与循环
        • if判断
      • awk的循环

Bash脚本的声明

在我们写.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][变量名称=设置值]

    • 参数说明:
    • +/-:+ 为取消相应的属性 - 为添加相应的属性
    • rxi:r 为只读变量(常量) x 为环境常量(在Bash脚本中也可以使用外面的定义的变量) i 为数值类型
  • 例如:

    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) 年
    • 输出 今年是第 2019 年

数学计算

因为数学计算和命令替换的bash语法很相近,所以一起学习效果会好些吧。

1、用$(( ))来表达数学计算,和命令替换一起使用时要注意括号的个数

  • 比如:获得明年的年数
  • echo 明年是第 $(( $(date +%Y) +1))年
    • 输出 明年是第 2020年

2、使用bc来处理浮点型数学运算

  • 比如:

  • echo "3.14*3.14" | bc

    • 输出:9.85 (黑人问号?不对啊,怎么精度只有2位?)
  • *注意咯,使用bc时默认保留小数点两位,如果可以整除的时候这两位也给你省去了!如果想保留更高精度的数,你需要使用scale。**

浮点数的小数位数是由内建变量scale控制的。必须将这个值设置为你希望在计算结果中保留的小数位,否则无法得到期望的结果

  • 比如:
  • echo "scale=6;3.14*3.14" | bc
    • 输出:9.8596
    • 精度设置为小数点后6位,但是后两位位是0,所以隐藏掉了。

函数

定义函数

定义函数有两种方法:


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判断

if [ 条件语句 ];then
满足条件执行的内容
else if [ 条件语句 ];then
第一个if条件不满足,但第二个条件满足执行的内容
else
都不满足条件后执行内容
fi
  • bash/shell 对空格非常敏感
  • 如果按照下面的例子练习if语句时运行报错那么请耐心仔细检查空格或语法。

现在我们通过一个实例来学习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已经重新启动

while循环

刚才学习了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后再次执行循环体!

sed 流编辑器

  • 第一种形式:stdout | sed [option] "pattern command"
  • 第二种形式:sed [option] "pattern command" fileaddress
    stdout意思为通过管道 | 将文本传入给后面的命令。

简介:

Linux sed 命令是利用脚本来处理文本文件。
sed 可依照脚本的指令来处理、编辑文本文件。
sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。

选项 option(常用)

选项 含义
-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 可以连接两个或多个匹配规则

sed 的匹配模式

匹配模式 作用 注意
8p 打印第8行的内容
8,10p 打印第8行到第10行的内容 包含第8行和第10行
8,+5p 打印第8行和其之后的5行 包含第8行
/正则表达式/p 打印匹配正则表达式的行
/正则表达式_1/,/正则表达式_2/p 打印匹配正则表达式1和2之间的行
8,/正则表达式/p 打印第8行起直到匹配到正则表达式匹配行之间的所有内容
/正则表达式/,8p 打印从匹配到正则表达式开始到第8行之间的所有内容

sed 的增删改查

功能 指令 备注
p 打印匹配的内容
d 删除匹配的内容
a 在匹配行的后一行追加内容
i 在匹配行的前一行增加一行内容
s/匹配模式/要修改的内容/ 查找符合匹配模式的字符串,将其匹配到的第一个字符串进行替换
s/匹配模式/要修改的内容/g 查找符合匹配模式的字符串,将匹配到的所有的字符串都进行替换
s/匹配模式/要修改的内容/2g 只替换从第二个符合匹配模式后面的所有字符串
s/匹配模式/要修改的内容/ig 忽略大小写查找符合匹配模式的字符串,将匹配到的所有字符串都进行替换

sed 的显示行号

  • = 可以显示输出的行号

例如:
sed = /etc/passwd

以上是sed流编辑器的学习内容和笔记。

awk 文本处理器

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 输出行分隔符。默认为回车换行

格式化输出 printf

格式符 含义
%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

awk 匹配模式

  • 第一种匹配模式:正则表达式匹配
  • 第二种匹配模式:关系运算匹配

正则表达式匹配

1、匹配/etc/passwd文件行中含有root字符串的所有行
awk 'BEGIN{ FS=":" }/root/{ print $0 }' /etc/passwd
2、匹配/etc/passwd文件行中以sshd开头的所有行
awk 'BEGIN{ FS=":" }/^sshd/{ print $0 }' /etc/passwd

关系运算符匹配

关系运算符 解释
< 小于
> 大于
<= 小于等于
>= 大于等于
== 等于
!= 不等于(可用于字符串)
~ 匹配正则表达式
!~ 不匹配正则表达式
匹配表达式(只与关系运算符连用) 解释
&#124&#124
&&
!

例子:

  • 1、以:为分隔符,匹配/etc/passwd文件中第三个字段小于50的所有行信息
    awk 'BEGIN{ FS=":" }$3<50{ print $0 }' /etc/passwd
  • 2、以:为分隔符,匹配/etc/passwd文件中第三个字段等于0的行信息
    awk 'BEGIN{ FS=":" }$3==0{ print $0 }' /etc/passwd
  • 3、以:为分隔符,匹配/etc/passwd文件中第七个字段不等于/bin/bash所有行信息
    awk 'BEGIN{ FS=":" }$7!="/bin/bash"{ print $0 }' /etc/passwd
  • 4、通过匹配正则表达式,匹配/etc/passwd中以root开头的所有行信息
    awk 'BEGIN{ FS=":" }$1~/^root/{ print $0 }' /etc/passwd
  • 5、以:为分隔符,匹配/etc/passwd文件中第一个字段等于root或sshd的所有行信息
    awk 'BEGIN{ FS=":" }$1=="root"||$1=="sshd"{ print $0 }' /etc/passwd

awk中的判断与循环

if判断

awk的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

这样一来命令也很清晰很多了,舒服的一批!

awk的循环

拿一个从1一直加到100的这个小学问题来当做学习循环的例子吧~

1、while循环:

vim while.awk

BEGIN{ 
while(i<=100)
{
sum+=i
i++
}
print sum
}

awk -f while.awk

  • 输出:5050

2、do-while循环:

vim do-while.awk

BEGIN{ 
do{
sum+=i
i++
}
while(i<=100)
print sum
}
  • 输出:5050

3、for循环:

vim for.awk

BEGIN{ 
for(i=1;i<=100;i++){
sum+=i
}
print sum
}
  • 输出:5050

我是一名Linux初学者,如果你与我一样喜欢折腾,喜欢Linux,那么请加入我的电报群https://t.me/yeefire_blog,在这里畅所欲言,共同学习进步。