shell脚本入门+fork炸弹+批文件处理

版权声明:学海无涯,来点干货 https://blog.csdn.net/Jackponwong/article/details/81259491
  • 前言

    ​ 本系列文章是基于《Linux Shell 脚本攻略》 的知识点以及个人的一些想法构成,旨在写成简单明了的shell教程,也希望通过 Learning by doing 学会shell基本操作,由于水平有限,如果写错也在所难免,希望读者指正。

  • 目标

    ​ 学完本章你将对shell有基本的了解,学会编写简单的shell脚本,例如对文件的操作,还将理解鼎鼎有名的Fork炸弹;以及编写一个简单的程序,实现直至文件下载成功才停止运行,这对于现实工作应该是非常有用的小技巧了。


  • 简介

    ​ 什么是 shell ?你可以理解为,shell就是一门用于高效处理文件的脚本语言,当然远不止于此;shell是什么并不重要,重要的是我们可以用它来做什么。直接上代码吧,Learning by doing!

    #输出Hello World
    vim test.sh	#建立test脚本
    
    #这句的意思就是告诉系统,我将调用bash程序,也就是shell
    #!/bin/bash		
    echo "Hello World"
    
    #保存退出
    chmod +x test.sh #改变test权限,使其可执行
    ./test.sh	#你将在终端看到Hello World
    
    #课后题,测试下以下代码区别
    num=123
    echo "$num"
    echo '$num'
    

    写完上面的程序,基本上也对shell有个印象,接下来就跟学习其他语言差不多了,让我们来了解shell 的基本知识。

  • 基础

  • 定义一个变量

    num=1	#跟python很类似,直接定义就行,不需要写类型,注意“=”
    declare -i num	#当然也可以用这种方式
    str='hello'	#字符串,用双引号也可以
    #数组
    array=(1 2 3)	#数组,元素之间用空格隔开
    declare -a array=([1]=1 [2]=2 [hello]=3)	#“索引-值”数组
    ${array[*]}		#表示访问全部元素
    ${#array[*]}	#表示数组元素个数
    #我们还可以这么操作
    array=(${array[*]} 'world') #向数组添加元素
    
  • if语句

    a=1
    b=2
    if [ $a -lt $b ] && [ $a -eq 1 ]
    #引用变量需要用"$"符号,可以写成 $a ,也可以 ${a},
    #复杂语句建议用后者,“and/or”==>"&&/||"
    then
    	echo "a<b" 
    elif [ $a -eq $b ]
    then
    	echo "a=b"
    else
    	echo "a>b"
    fi
    
    
    #比较符号
    -lt #less then		<
    -le #less equal 		<=
    -gt #greater then 	>
    -ge #greater equal 	>=
    -eq #equal 			=
    -ne #not equal 		!=
    

    可以看到,样式跟其他语言很不一样,“( )”改成“[ ]”;而且两边还要有空格隔开;
    if 后要紧随 then,结束要用 fi ;

    扫描二维码关注公众号,回复: 6106101 查看本文章
  • for 和 while 循环

a=(1 2 3)
for i in ${a[*]}
	do
		echo $i
	done
	
i=1
while [ $i -le 5 ]
	do
		echo $i
		let i++
	done

可以看到,两个循环语句都始于do,终于done;让数字做加减可以用 let 语句;

  • 数学运算
a=1
b=2
c=$a+$b	#这种操作是错误的,以下才是正确操作
let c=$a+$b
((c=$a+$b))
c=$(($a+$b))	#这些方法只能用于整数,不能用于浮点数
#bc是一个用于数学运算的高级工具,或许我们可以试试
  • 重定向
echo "Hello world" > 1.txt		#将字符串覆盖写入到文件
echo "Who are you?" >> 1.txt	#将字符串追加写入到文件
cat 1.txt 2.txt > 3.txt		    #读取文件1和2的内容,并将其写入到文件3
  • 别名
alias install='sudo apt install '	#为命令起别名,下次直接install就行了
  • 时间
date		#直接获取时间
date +%s 	#获取纪元时
#有时候我们要统计下程序运行多久,我们可以这样
#!/bin/bash
start=$(date +%s)
i=1
while [ $i -le 10 ]
do
	echo $i
	let i++
	sleep 1
done
end=$(date +%s)
diff=$(($end-$start))
echo "Time: $diff s"

  • 函数
hello(){
    echo "hello"
}
hello	#直接调用函数名字就行
#如果有参数,又该怎么做
hello(){
    echo "hello $1,welcome to $2"
}
hello Jack BeiJing

是的,在shell中 ‘$1’ 就是代表第一个参数,以此类推;shell 也可以编写递归函数,其中最典型的案例就是Fork炸弹,其本质其实就是调用本身,几何增长地产生进程,最终导致服务器崩溃!所以不要轻易尝试。


  • 拓展应用

  • Fork炸弹

:(){ :|:& };:		#史上最简的Fork炸弹就是这样啦

看起来很像外星文,其实只要这样分解,就很容易看得懂了;

#调用函数本身,然后利用管道调用一个新进程,&就是我们linux用于将进程放在后台的操作
:(){
	:|:&	
};
:

防范其实也简单,因为该程序其实就是产生大量进程导致系统崩溃,那么我们只需要限制最大进程数就行。

ulimit -u 50 	#设置最大进程数为 50
#当然还可以在配置 /etc/security/limits.conf 来限制最大进程数
  • 下载文件
#!/bin/bash
repeat(){
	while true
	do
		$@ && return 	# $@ 代表传递的语句,如果执行成功就返回退出
	done
}

由于true是作为 /bin 的一个二进制文件来实现的,这就意味着每执行一次,就要产生一个进程;
所以我们可以改为shell内建的 “ : ” ;我们还应该添加延时操作,不然服务器会任务你在发送垃圾信息,可能把你拉黑。

#最终版
repeat(){ while :; do $@ && return ; sleep 30; done }
#调用
repeat wget -c http://www.example.com/software.tar.gz
  • 批处理文件名
#!/bin/bash
f="format" #format为修改后的格式,例如mp4
cd path #path为要修改的文件目录
for file in $(ls *)
do
	name=$(ls $file | cut -d . -f 1) #获取文件名
	mv $file $name.$f
done

猜你喜欢

转载自blog.csdn.net/Jackponwong/article/details/81259491