idea离线安装 HashMap 服务注册中心 makefile oracle Parsley jq触发点击事件 css获取最后一个元素 teamviewer验证被拒绝 jquery关闭当前窗口 python刷题 kubernetes入门 python3下载安装 python自学教程 python打开文件 python设置环境变量 java中的多态 java搭建 java学习文档 java文件路径 linux用户 java游戏开发教程 黑客攻防实战入门 m4a转mp3格式转换器 视频修复工具 苹果放大镜 画图怎么添加文字 语音分析软件 ps镜头校正 cdr怎么画波浪线 firefox绿色版 edquota 爱奇艺视频下载到电脑 linux解压 产品修图 ps怎么去痘痘 cadworx 服务器备份软件 maya骨骼绑定 js压缩图片
当前位置: 首页 > 学习教程  > 编程语言

Shell从入门到看戏——bash十练

2021/1/28 22:54:57 文章标签:

熟悉基本shell操作不仅是运维的基本功,对于开发来说也是多多益善,我在学习的过程中,总结了十个练手的小demo,并附上涉及的知识点,仅供娱乐。 目录 1. 多线程ping监控,检查同一网段的IP是否连通 2.进度条…

熟悉基本shell操作不仅是运维的基本功,对于开发来说也是多多益善,我在学习的过程中,总结了十个练手的小demo,并附上涉及的知识点,仅供娱乐。

目录

1. 多线程ping监控,检查同一网段的IP是否连通

2.进度条功能显示

3. Linux创建进程的三种方式

4. 控制进程数量——文件描述符和命名管道

文件描述符

命名管道

5. 可任意控制进程数量的多线程ping

6. sed爬虫批量下载美女图片

7. sed随机点名器

8.系统性能监控脚本

9.监控网络连接状态

参考


1. 多线程ping监控,检查同一网段的IP是否连通

  • Linux 系统中有一个特殊的设备/dev/null,这是一个黑洞。无论往该文件中写入多少数据,都会被系统吞噬、丢弃。如果有些输出信息是我们不再需要的, 则可以使用重定向将输出信息导入该设备文件中。注意:数据一旦导入黑洞将无法找回。
  • 重定向: > 是覆盖重定向, >> 是累加重定向
  • $0 这个程式的执行名字
    $n 这个程式的第n个参数值,n=1..9
    $* 这个程式的所有参数,此选项参数可超过9个。
    $# 这个程式的参数个数
    $$ 这个程式的PID(脚本运行的当前进程ID号)
    $! 执行上一个背景指令的PID(后台运行的最后一个进程的进程ID号)
    $? 执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)
    $- 显示shell使用的当前选项,与set命令功能相同
    $@ 跟$*类似,但是可以当作数组用
  • &  表示任务在后台执行,如要在后台运行redis-server,则有  redis-server &
    && 表示前一条命令执行成功时,才执行后一条命令 ,如 echo '1‘ && echo '2'
    | 表示管道,上一条命令的输出,作为下一条命令参数,如 echo 'yes' | wc -l
    || 表示上一条命令执行失败后,才执行下一条命令,如 cat nofile || echo "fail"

  • ping 命令语法

    ping [-dfnqrRv][-c<完成次数>][-i<间隔秒数>][-I<网络界面>][-l<前置载入>][-p<范本样式>][-s<数据包大小>][-t<存活数值>][主机名称或IP地址]
#!/bin/bash
#使用&开启后台进程
net="101.200.35"

mult_ping() {
        ping -c2 -i0.2 -W1 $1 &>/dev/null
        if [ $? -eq 0 ];then
                echo "$1 is up"
        else
                echo "$1 is down"
        fi
}

for i in {0..255}
do
        mult_ping $net.$i &
done
wait
                              

2.进度条功能显示

  • 常见系统预设变量
#!/bin/bash

trap 'kill $!' INT
# 定义宽度为50的进度条
# 输出完成后将/r光标切换到行首,准备下一次进度条显示
bar () {
        while :
                pound=""
                for ((i = 47; i>=1; i-- ))
                do      
                        pound += #
                        printf "|%s%${i}s|\r" "$pound"
                        sleep 0.2
                done    
                
        }       
        
# 调用函数,显示进度符号,直到复制结束kill进度函数
bar &
cp -r $1 $2
kill $!
echo "复制结束"

3. Linux创建进程的三种方式

  1. fork
    通常情况下在系统中通过相对路径或绝对路径执行一个命令时,都会由父进程开启一个子进程,当子进程结束后再返回父进程,这种行为过程就叫作fork。当脚本中正常调用一个外部命令 1或其他脚本时,都会fork一个子Shell进程,我们的命令会运行在这个子Shell中。
  2. exec
    使用 exec 方式调用其他命令或脚本时,系统不会开启子进程,而是使用新的程序替换当前的 Shell 环境,因为当前 Shell 环境被替换了,所以当 exec 调用的程序结束后,当前环境会被关闭。但是有一个特例,当 exec 后面的参数是文件重定向时,不会替换当前 Shell 环境,脚本后续的其他命令也不会受到任何影响。
  3. source或 . (点)
    使用 source 命令或.(点)可以不开启子 Shell,而在当前 Shell 环境中将需要执行的命令加载进来,执行完加载的命令后,继续执行脚本中后续的指令。

分析工具:pstree 进程树

4. 控制进程数量——文件描述符和命名管道

文件描述符

文件描述符是一个非负整数,而内核需要通过这个文件描述符才可以访问文件。当我们在系统中打开已有的文件或新建文件时,内核每次都会给特定的进程返回一个文件描述符,当进程需要对文件进行读或写操作时,都要依赖这个文件描述符进行。文件描述符就像一本书的目录页数(也叫索引),通过这个索引可以找到需要的内容。在 Linux 或类 UNIX系统中内核默认会为每个进程创建三个标准的文件描述符,分别是 0(标准输入)、 1(标准输出)和 2(标准错误)。通过查看/proc/PID 号/fd/目录下的文件,就可以查看每个进程拥有的所有文件描述符。

创建文件描述符:

exec 文件描述符 <> 文件名

调用文件描述符语法格式:

&文件描述符

关闭文件描述符:

exec 文件描述符<&-
exec 文件描述符>&-

命名管道

管道是进程间通信的一种方式,匿名管道,使用|符号就可以创建一个匿名管道,顾名思义,系统会自动创建一个可以读写数据的管道,但是这个管道并没有名称。一个程序往管道中写数据,另一个程序就可以从管道中读取数据。但是匿名管道仅可以实现父进程与子进程之间的数据交换,能不能实现任意两个无关的进程之间的通信呢?答案是肯定的,使用命名管道,也叫FIFO1文件。

命名管道的特征:

  •  FIFO 文件由命令创建(mknod 或 mkfifo 命令),可以在文件系统中直接看到。
  • 写入管道的数据一旦被读取后,就不可以再重复读取。
  • 进程往命名管道中写数据时,如果没有其他进程读取数据,则写进程会被阻塞。
  • 进程尝试从命名管道中读取数据时,如果管道中没有数据,则读进程会被阻塞。
  • 命名管道中的数据常驻内存,并不实际写入磁盘,读写效率会更高。

5. 可任意控制进程数量的多线程ping

第一个demo中,通过 & 开启任意数量线程进行ping,但是这里的线程不可控。我们用上面的文件描述符和命名管道的知识,写一段可控的多线程ping。

#!/bin/bash
  
pipefile=/tmp/procs_$$.temp
num=10
net="101.200.35"

multi_ping() {
        ping -c2 -i0.2 -W1 $1 &>/dev/null
        if [ $? -eq 0 ];then
                echo "$1 is up"
        else
                echo "$1 is down"
        fi
}
# 创建命名管道文件,创建其文件描述符,通过重定向将数据导入管道文件
mkfifo $pipefile
exec 12<>$pipefile
for i in `seq $num`
do
        echo "" >&12 &
done
# 成功读取命名管道中的数据后开启新的进程
# 所有内容读取完之后read被阻塞,无法再启动新的进程
# 等待前面启动的线程结束后,继续往管道文件中写入数据,释放阻塞,再次开启新的线程
for j in {1..254}
do
        read -u12
        {
                multi_ping $net.$j
                echo "" >&12
        } &
done
wait
rm -rf $pipfile

6. sed爬虫批量下载美女图片

  • sed命令汇总




  • sed 是逐行处理软件,我们可能仅输入了一条 sed 指令,但系统会将该指令应用在所有匹配的数据行上,因此相同的指令会被反复执行 N 次,这取决于匹配到的数据有几行。
  • 默认 sed 不支持扩展正则,如果希望使用扩展正则匹配数据,可以使用-r 参数。
  • sed 程序使用=指令可以显示行号,结合条件匹配,可以显示特定数据行的行号。
  • 在 sed 中支持使用感叹号(!)对匹配的条件进行取反操作。

下载思路:用curl获取网站源代码+sed数据清洗获取图片地址+wget下载保存

#!/bin/bash
# 爬取美女图片

# 定义要爬取的网站和保存的文件
page="https://tieba.baidu.com/p/4420470629"
URL="beau.txt"
# 将网站源代码保存到文件中
curl -s https://tieba.baidu.com/p/4420470629 > $URL
# 对源代码数据过滤清洗,获取种子的URL链接
echo -e "\033[32m 正在获取种子 URL,请稍后...\033[0m"
sed -i '/<img/!d' $URL #删除不包含<img 的行
sed -i 's/.*src="//' $URL #删除 src="及其前面的所有内容
sed -i 's/".*//' $URL #删除双引号及其后面的所有内容
echo

#利用循环批量下载所有图片数据
#wget 为下载工具,其参数选项描述如下:
# -P 指定将数据下载到特定目录(prefix)
# -c 支持断点续传(continue)
# -q 不显示下载过程(quiet)
echo -e "\033[32m 正在批量下载种子数据,请稍后...\033[0m"
for i in $(cat $URL)
do
        wget -P tempPhoto/ -c $i
done

这种知识最基本的爬虫,对于反爬虫的网站就嗝屁了,对于那种异步加载的也没办法,总之,就是比较弱。

7. sed随机点名器

做一个互联网大佬的随机点名器

#!/bin/bash
#按 Ctrl+C 组合键时:恢复光标,恢复终端属性,清屏,退出脚本
#防止程序意外中断导致的终端混乱
trap 'tput cnorm;stty $save_property;clear;exit' 2
#定义变量:人员列表文件名,文件的行数,屏幕的行数,屏幕的列数
name_file="name.txt"
line_file=$(sed -n '$=' $name_file)
line_screen=`tput lines`
column_screen=`tput cols`
#设置终端属性
save_property=$(stty -g) #保存当前终端所有属性
tput civis #关闭光标
#随机抽取一个人名(随机点名)
while :
do
        tmp=$(sed -n "$[RANDOM%line_file+1]p" $name_file)
        #随机获取文件的某一行人名
        tput clear #清屏
        tput cup $[line_screen/4] $[column_screen/4]
        echo -e "\033[3;5H 随机点名器(按 P 停止): "
        echo -e "\033[4;5H#############################"
        echo -e "\033[5;5H# #"
        echo -e "\033[6;5H#\t\t$tmp\t\t#"
        echo -e "\033[7;5H# #"
        echo -e "\033[8;5H#############################"
        sleep 0.1
        stty -echo
        read -n1 -t0.1 input
        if [[ $input == "p" || $input == "P" ]];then
                break
        fi
done
tput cnorm #恢复光标
stty $save_property #恢复终端属性

8.系统性能监控脚本

  • awk语法格式
  • awk变量
  • awk条件匹配
  • awk 可以通过-v(variable) 选项设置或者修改变量的值,我们可以使用-v 定义新的变量,也可以使用该选项修改内置变量的值。
  • 使用[]定义分隔符集合,同时设置多个分隔符。比如使用[:,-]表示以冒号(:)、逗号(,)或者横线(-)为分隔符
  • [-F|-f|-v]   大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value

 

9.监控网络连接状态

  • ss语法格式
#!/bin/bash
# 监控网络连接状态
#所有 TCP 连接的个数
TCP_Total=$(ss -s | awk '$1=="TCP"{print $2}')
#所有 UDP 连接的个数
UDP_Total=$(ss -s | awk '$1=="UDP"{print $2}')
#所有 UNIX sockets 连接个数
Unix_sockets_Total=$(ss -ax | awk 'BEGIN{count=0} {count++} END{print
count}')
#所有处于 Listen 监听状态的 TCP 端口个数
TCP_Listen_Total=$(ss -antlpH | awk 'BEGIN{count=0} {count++} END{print
count}')
#所有处于 ESTABLISHED 状态的 TCP 连接个数
TCP_Estab_Total=$(ss -antpH | awk 'BEGIN{count=0} /^ESTAB/{count++}
END{print count}')
#所有处于 SYN-RECV 状态的 TCP 连接个数
TCP_SYN_RECV_Total=$(ss -antpH | awk 'BEGIN{count=0} /^SYN-RECV/{count++}
END{print count}')
#所有处于 TIME-WAIT 状态的 TCP 连接个数
TCP_TIME_WAIT_Total=$(ss -antpH | awk 'BEGIN{count=0} /^TIME-WAIT/{count++}
END{print count}')
#所有处于 TIME-WAIT1 状态的 TCP 连接个数
TCP_TIME_WAIT1_Total=$(ss -antpH | awk 'BEGIN{count=0}
/^TIME-WAIT1/{count++} END{print count}')
#所有处于 TIME-WAIT2 状态的 TCP 连接个数
TCP_TIME_WAIT2_Total=$(ss -antpH | awk 'BEGIN{count=0}
/^TIME-WAIT2/{count++} END{print count}')
#所有远程主机的 TCP 连接次数
TCP_Remote_Count=$(ss -antH | awk '$1!~/LISTEN/{IP[$5]++} END{ for(i in
IP){print IP[i],i} }' | sort -nr)
#每个端口被访问的次数
TCP_Port_Count=$(ss -antH | sed -r 's/ +/ /g' | awk -F"[ :]"
'$1!~/LISTEN/{port[$5]++} END{for(i in port){print port[i],i}}' | sort -nr)
#定义输出颜色
SUCCESS="echo -en \\033[1;32m" #绿色
NORMAL="echo -en \\033[0;39m" #黑色
#显示 TCP 连接总数
tcp_total(){
        echo -n "TCP 连接总数: "
        $SUCCESS
        echo "$TCP_Total"
        $NORMAL
} 
#显示处于 LISTEN 状态的 TCP 端口个数
tcp_listen(){
        echo -n "处于 LISTEN 状态的 TCP 端口个数: "
        $SUCCESS
        echo "$TCP_Listen_Total"
        $NORMAL
} 
#显示处于 ESTABLISHED 状态的 TCP 连接个数
tcp_estab(){
        echo -n "处于 ESTAB 状态的 TCP 连接个数: "
        $SUCCESS
        echo "$TCP_Estab_Total"
        $NORMAL
} 
#显示处于 SYN-RECV 状态的 TCP 连接个数
tcp_syn_recv(){
        echo -n "处于 SYN-RECV 状态的 TCP 连接个数: "
        $SUCCESS
        echo "$TCP_SYN_RECV_Total"
        $NORMAL
} 
#显示处于 TIME-WAIT 状态的 TCP 连接个数
tcp_time_wait(){
        echo -n "处于 TIME-WAIT1 状态的 TCP 连接个数: "
        $SUCCESS
        echo "$TCP_TIME_WAIT1_Total"
        $NORMAL
} 
#显示处于 TIME-WAIT2 状态的 TCP 连接个数
tcp_time_wait2(){
        echo -n "处于 TIME-WAIT2 状态的 TCP 连接个数: "
        $SUCCESS
        echo "$TCP_TIME_WAIT2_Total"
        $NORMAL
} 
#显示 UDP 连接总数
udp_total(){
        echo -n "UDP 连接总数: "
        $SUCCESS
        echo "$UDP_Total"
        $NORMAL
} 
#显示 UNIX sockets 连接总数
unix_total(){
        echo -n "Unix sockets 连接总数: "
        $SUCCESS
        echo "$Unix_sockets_Total"
        $NORMAL
} 
#显示每个远程主机的访问次数
remote_count(){
        echo "每个远程主机与本机的并发连接数: "
        $SUCCESS
        echo "$TCP_Remote_Count"
        $NORMAL
} 
#显示每个端口的并发连接数
port_count(){
        echo "每个端口的并发连接数: "
        $SUCCESS
        echo "$TCP_Port_Count"
        $NORMAL
}

print_info(){
        echo -e "------------------------------------------------------"
        $1
}
print_info tcp_total
print_info tcp_listen
print_info tcp_estab
print_info tcp_syn_recv
print_info tcp_time_wait
print_info tcp_time_wait1
print_info tcp_time_wait2
print_info udp_total
print_info unix_total
print_info remote_count
print_info port_count
echo -e "------------------------------------------------------"

 

 

参考

  • https://www.runoob.com/linux/linux-comm-wc.html
  • https://www.cnblogs.com/zhuozige/p/14050529.html
  • 《Linux Shell核心编程指南》

 


本文链接: http://www.dtmao.cc/news_show_650108.shtml

附件下载

上一篇:知识体系构建

下一篇:2021.1.28学习日志

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?