声明
学习视频来自 B 站UP主泷羽sec,如涉及侵权马上删除文章。
笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。
✍🏻作者简介:致力于网络安全领域,目前作为一名学习者,很荣幸成为一名分享者,最终目标是成为一名开拓者,很有趣也十分有意义
🤵♂️ 个人主页: @One_Blanks
欢迎评论 💬点赞👍🏻 收藏 📂加关注+
文章目录
- shell脚本编写基础
- 使用的脚本解析器/bin/bash(声明)
- shell脚本的执行
- 第一种方法给权限
- 第二种方法直接使用解释器
- 第三种方法使用source命令
- shell脚本语法
- 变量
- 变量声明和定义
- 变量拼接
- 变量的命名规则
- 变量的查看与删除
- 常见的变量
- 永久变量
- 脚本程序传递参数怎么实现
- 如何在编程中进行数学运算
- shell中利用expr进行运算
- 输入与输出
- 函数的封装
- 条件判断语句
- 条件符号
- 循环语句
- 模块化编程
- Linux进程操作
- 查看寻找进程
- 终止进程
- 暂停与恢复进程
- 后台运行
- shell脚本编写(病毒编写)
- 系统内存资源占用
shell脚本编写基础
使用的脚本解析器/bin/bash(声明)
#! /bin/bash
#!
,由 “#” 和 “!” 两个字符组成的特殊标记。当一个可执行文件以这两个字符开头时,内核会将该行的其余部分作为解释器的路径来读取,并使用该解释器来执行这个文件的后续内容。/bin/bash
是指 bash解释器的路径。- 所以
#!/bin/bash
整体的意思就是指定这个脚本文件应该由 Bash 解释器来执行。
#! /bin/dash
#! /bin/sh
不管使用哪种脚本解释器最后还是调用的dash
shell脚本的执行
第一种方法给权限
是否拥有执行的权限,表示脚本是否可以进行执行
- 使用
ls -liah
进行详细目录查看 - 权限修改可以使用
chmod 777 www.sh
用户、用户组、其他用户都给最高权限(读、写、执行)
第二种方法直接使用解释器
-
sh www.sh
-
bash www.sh
第三种方法使用source命令
-
source www.sh
执行和sh命令差不多,就是这个命令对颜色加深标注了
shell脚本语法
变量
变量声明和定义
eg:定义一个name变量,然后用echo打印出来
name=“xiaoyu”
age=27
echo $name
echo my name is $name,and my age is $age years old
echo “my name is $name,and my age is $age years old”
echo ‘my name is $name,and my age is $age years old’
- 一般来说加双引号和不加的效果是一样的
- 但是加单引号就不会解析变量直接输出所有字符串
变量拼接
echo “my name is $name,and my age is $ageyears old”
这个例子中years与age之间没有空格,所以打印出来为空,因为两个连起来系统会认为变量没有被定义,所以输出为空
- 解决办法
echo “my name is n a m e , a n d m y a g e i s " name,and my age is " name,andmyageis"age"years old”
将变量用双引号括起来,这样就会做一个区分,系统就会识别出这是一个变量
除了用"",用{}花括号也是可以的
echo “my name is KaTeX parse error: Expected '}', got 'EOF' at end of input: …and my age is {age}years old”
变量的命名规则
变量由数字、字符、下划线组成,但是不能以数字开头
变量命名对于大小写是敏感的 如: man Man 就是两个变量
变量的查看与删除
set | grep name
- 查看变量名为name的变量
unset name
- 删除变量名为name的变量
常见的变量
echo $HOME
echo $PATH
-
可以将我们写好的shell脚本移动到/usr/bin/目录下,让它存在变量中然后就可以直接运行使用
vim 33.sh
chmod +x 33.sh
mv 33.sh /usr/bin/
33.sh
-
也可以将一整个目录都添加到环境变量中去使一整个目录的文件都可以直接执行
export PATH=/root:PATH
然后输出变量PATH查看是否添加成功
echo $PATH
-
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
原有默认变量,当然也可以重启终端进行恢复
- export 是一个用于设置环境变量的关键字,使变量在当前的shell终端中生效,重启一个终端设置的环境变量就会失效
永久变量
export写的只是临时变量,把变量写到配置文件中才是永久变量
cd /
usr/bin/vi .bashrc
export PATH=/root:PATH
加入之后使用source命令使变量生效
source usr/bin/ .bashrc
脚本程序传递参数怎么实现
echo 执行的文件名是:$0
echo 第一个参数是:$1
echo 传递的参数作为一个字符显示:$*
echo 传递的参数作为每个字符串显示:$@
echo 传递到脚本的参数个数是:$#
echo 最后命令的退出状态:$?
echo 脚本运行的当前进程ID:$$
- 可以向脚本程序传递一个或多个参数,脚本中的$1,里面的数字是可以依次递增的,比如$1,$2,$3等
- 执行结果
执行的文件名是:w.sh
第一个参数是:
传递的参数作为一个字符显示:
传递的参数作为每个字符串显示:
传递到脚本的参数个数是:0
最后命令的退出状态:0
脚本运行的当前进程ID:718191
- 指定一个参数再执行
sh w.sh name
执行的文件名是:w.sh
第一个参数是:name
传递的参数作为一个字符显示:name
传递的参数作为每个字符串显示:name
传递到脚本的参数个数是:1
最后命令的退出状态:0
脚本运行的当前进程ID:719286
- 指定多个参数
sh w.sh name sdf dfas
执行的文件名是:w.sh
第一个参数是:name
传递的参数作为一个字符显示:name sdf dfas
传递的参数作为每个字符串显示:name sdf dfas
传递到脚本的参数个数是:3
最后命令的退出状态:0
脚本运行的当前进程ID:719990
参数传递一般为 n ( n 表示数字可递增 ) 。 n(n表示数字 可递增)。 n(n表示数字可递增)。*就是将参数作为同一的字符串显示出来,而 @ 是将每个字符串当作独立的字符串显示这也是 @是将每个字符串当作独立的字符串显示 这也是 @是将每个字符串当作独立的字符串显示这也是*和&@的区别,KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲表示参数的个数,?是查看命令执行状态的 如果显示为0 那么命令就是正常执行的,其他数字就是出错了,$$就是查看脚本当前进程的ID
如何在编程中进行数学运算
shell中利用expr进行运算
错误:expr 5+10 会回显 5+10
正确:expr 5 + 10 就会显示15了
以上方法适用于加法减法
乘法:
错误:expr 5 * 10 会报错
正确:expr 5 * 10 就会显示50了 需要使用\进行转义
除法:
正确:expr 10 / 5 会显示2
取余:
正确:expr 10 % 4 会显示2
-
使用
$(( ))
语法product=$((num1 * num2))
这样就直接进行运算了,不用去管什么转义字符什么的
输入与输出
- 输入
read name
输入一个值,并赋值给name- 赋值给
name
后需要使用$
进行解析如$name
- 输出
echo
对于字符进行整行输出printf
类似与C语言
printf "My name is %s and I am %d years old.\n" $name $age
前面""中需要有格式化符号,后面才是变量.
函数的封装
- 不含参数函数定义调用
greet () {
echo "Hello, World!"
}
函数调用
#!/bin/bash
greet
- 含参函数定义调用
add_numbers () {
sum=$(($1 + $2))
echo "The sum of $1 and $2 is $sum"
}
函数调用
#!/bin/bash
add_numbers 3 5
-
当然也可以存在
rutern
返回值 -
$() 与 反引号``的异同
都可以用于获取指令结果,但建议使用$(),因为它可以嵌套,而反引号不支持。
条件判断语句
- if 语句基本结构
- 在 Bash 编程中,
if
语句用于条件判断。基本结构如下:
- 在 Bash 编程中,
if [ condition ]; then
# 条件为真时执行的命令
commands
fi
- 其中,
[ condition ]
是条件表达式部分,;
用于分隔条件表达式和then
关键字(也可以将;
换成换行)。then
后面的commands
是当条件为真时要执行的命令序列。 fi
是一个关键字,用于标识if
语句块的结束- 例如,判断一个变量是否大于 10:
#!/bin/bash
num=15
if [ $num -gt 10 ]; then
echo "$num is greater than 10"
fi
- 这里的
$num -gt 10
是条件表达式,-gt
是用于比较大小的操作符,表示 “大于”。当num
的值大于 10 时,就会执行echo
命令。 - 除了只在条件为真时执行命令,还可以在条件为假时执行其他命令,这就用到了
if - else
语句。结构如下:
if [ condition ]; then
commands1
else
commands2
fi
- 例如,判断一个数是偶数还是奇数:
#!/bin/bash
num=7
if [ $((num % 2)) -eq 0 ]; then
echo "$num is even"
else
echo "$num is odd"
fi
- 这里使用
$((num % 2)) -eq 0
作为条件表达式,%
是取余运算,-eq
是 “等于” 操作符。如果num
除以 2 的余数为 0,则为偶数,执行echo
偶数相关的命令;否则为奇数,执行echo
奇数相关的命令。
- if - elif - else 语句
- 当需要判断多个条件时,可以使用
if - elif - else
语句。结构如下:
if [ condition1 ]; then
commands1
elif [ condition2 ]; then
commands2
……
else
commandsn
fi
- 例如,根据分数范围输出等级:
#!/bin/bash
score=85
if [ $score -ge 90 ]; then
echo "A"
elif [ $score -ge 80 ]; then
echo "B"
elif [ $score -ge 70 ]; then
echo "C"
elif [ $score -ge 60 ]; then
echo "D"
else
echo "F"
fi
- 这里依次判断分数是否大于等于 90、80、70、60,根据不同的范围输出相应的等级。如果分数小于 60,则输出
F
。
条件符号
-
数值比较操作符
- -lt:小于。
- -le:小于等于。
- -eq:等于。
- -ne:不等于。
- -ge:大于等于。
- -gt:大于。
-
字符串比较操作符
- = 或 ==:相等(在多数 Bash 环境下,不过 “==” 可能在某些版本中不被支持)。
- !=:不相等。
- -z:判断字符串长度是否为 0。
- if - else 语句
-
文件判断使用到的参数
-e 文件名 如果文件存在则为真
-f 文件名 如果文件存在且为普通文件则为真
-d 文件名 如果文件存在且为目录则为真
-r 文件名 如果文件存在且可读则为真
-w 文件名 如果文件存在且可写则为真
-x 文件名 如果文件存在且可执行则为真
-s 文件名 如果文件存在且至少有一个字符则为真
-c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真 -
条件判断使用到的逻辑操作符
①与 的表示方法:&&、-a
要求所有条件为真,则条件为真
②或 的表示方法:||、-o
要求任意条件为真,则条件为真
③非 的表示方法:!
要求条件反转为真时,条件为真
循环语句
- for 循环
- 基本语法:
for
循环用于遍历一系列的值,通常是一个列表。基本格式为:
- 基本语法:
for variable in list; do
commands
done
- 其中
variable
是循环变量,用于依次存储list
中的每个元素;list
可以是一个用空格分隔的值列表、一个数组或者是一个由命令生成的结果集;commands
是在每次循环中要执行的命令。 - 遍历列表示例:
- 例如,遍历一个数字列表并打印每个数字:
for number in 1 2 3 4 5; do
echo $number
done
- 这里
number
会依次取1
、2
、3
、4
、5
,并在每次循环中通过echo
命令输出。 - 遍历数组示例:
- 假设定义了一个数组
fruits
,并使用for
循环遍历它:
- 假设定义了一个数组
fruits=("apple" "banana" "cherry")
for fruit in "${fruits[@]}"; do
echo $fruit
done
- 在这个例子中,
${fruits[@]}
表示数组fruits
的所有元素,fruit
会依次取数组中的每个元素并输出。 - 使用命令生成列表示例:
- 可以使用命令的输出作为
for
循环的列表。例如,通过ls
命令列出当前目录下的文件,并逐个打印文件名:
- 可以使用命令的输出作为
for file in $(ls); do
echo $file
done
- 不过要注意,这种方式如果文件名中有空格等特殊字符可能会出现问题,更安全的做法是使用
while
循环和read
命令结合来处理有特殊字符的文件名。
- while 循环
- 基本语法:
while
循环在条件为真时持续执行命令块。基本格式为:
while [ condition ]; do
commands
done
- 其中
[ condition ]
是条件表达式,commands
是每次循环要执行的命令。 - 简单计数示例:
- 例如,从 1 开始计数,直到数字达到 5:
count=1
while [ $count -le 5 ]; do
echo $count
count=$((count + 1))
done
- 在这里,
count
初始值为 1,每次循环判断count
是否小于等于 5,如果是则打印count
的值,然后将count
的值加 1。当count
大于 5 时,循环结束。 - 读取文件内容示例:
- 假设要逐行读取一个文件的内容,可以这样做:
while read line; do
echo $line
done < file.txt
- 这个循环会不断读取
file.txt
文件中的一行内容存储到line
变量中,然后通过echo
命令输出该行内容,直到文件结束。
- until 循环
- 基本语法和特点:
until
循环与while
循环相反,它在条件为假时持续执行命令块,直到条件变为真。基本格式为:
until [ condition ]; do
commands
done
- 例如,计算从 1 加到某个数,直到总和大于等于 10:
sum=0
num=1
until [ $sum -ge 10 ]; do
sum=$((sum + num))
num=$((num + 1))
done
echo $sum
- 在这里,开始时
sum
为 0,num
为 1,每次循环将num
累加到sum
中,并将num
加 1,直到sum
大于等于 10,循环结束后输出sum
的值。
- 循环控制语句
- break 语句:用于立即跳出循环。例如,在
for
循环中,如果满足某个条件就跳出循环:
for i in 1 2 3 4 5; do
if [ $i -eq 3 ]; then
break
fi
echo $i
done
- 这个循环在
i
等于 3 时就会跳出,所以只会输出 1 和 2。 - continue 语句:用于跳过当前循环的剩余部分,直接进入下一次循环。例如:
for i in 1 2 3 4 5; do
if [ $i -eq 3 ]; then
continue
fi
echo $i
done
- 当
i
等于 3 时,continue
语句会跳过echo
命令,直接进入下一次循环,所以会输出 1、2、4、5。
模块化编程
就是在本脚本中调用其他脚本的函数,以此来实现模块化编程
#!/bin/bash
source update.sh
update $n1 $n1
echo 在$0文件中运行update.sh的函数update
$0
是一个特殊的变量,它代表当前脚本的文件名。当脚本被执行时,$0
会被自动赋值为脚本文件的名称。(类似与Windows系统dos编程中的%0)source
是一个命令(也可以用 “.” 来代替,如 “.”filename
与source filename
效果相同)。它的主要作用是在当前脚本环境中读取并执行另一个文件中的命令。(相当于文件包含)
Linux进程操作
查看寻找进程
- ps 命令
- 基本语法:
ps [options]
。例如,ps -ef
是最常用的查看进程的命令组合。-e
选项表示显示所有进程,-f
选项用于显示完整格式的信息。 - 详细解释:它会列出进程的 UID(用户 ID)、PID(进程 ID)、PPID(父进程 ID)、C(CPU 使用率)、STIME(进程启动时间)、TTY(终端类型)、TIME(累计 CPU 时间)和 CMD(命令行)等信息。例如,在命令行输入
ps -ef
后,会看到类似如下的输出:
- 基本语法:
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 11:00? 00:00:01 /sbin/init
root 2 0 0 11:00? 00:00:00 [kthreadd]
- 其他常用选项:
ps -aux
:显示所有包含其他用户的进程,并且以 BSD 风格输出。其中a
选项表示显示所有终端下的进程,包括其他用户的进程;u
选项以用户为中心组织输出;x
选项表示显示没有控制终端的进程。
- top 命令
- 基本语法:
top
。直接在命令行输入top
后,会进入一个实时显示系统进程状态的界面。 - 详细解释:它会按照 CPU 使用率、内存使用率等对进程进行排序,并动态更新。在这个界面中,可以看到系统的负载情况(
load average
),包括 1 分钟、5 分钟和 15 分钟的平均负载。每一行代表一个进程,显示的信息和ps -ef
有一些重叠,如 PID、USER、PR(优先级)、NI(Nice 值)、VIRT(虚拟内存大小)、RES(物理内存大小)等。 - 操作方式:在
top
界面中,可以通过按键来进行操作。例如,按P
键可以按照 CPU 使用率排序进程,按M
键可以按照内存使用率排序进程,按q
键可以退出top
界面。
- pgrep 命令
- 基本语法:
pgrep [options] pattern
。例如,pgrep -l firefox
用于查找名称中包含firefox
的进程并显示其 PID 和名称。 - 详细解释:它是通过进程名称或者其他属性来查找进程的 PID。
-l
选项表示在输出中同时显示进程名称。如果只需要 PID,可以不使用-l
选项。
终止进程
- kill 命令
- 基本语法:
kill [signal] PID
。例如,kill -9 1234
表示强制终止 PID 为 1234 的进程。 - 详细解释:
signal
是发送给进程的信号,默认信号是TERM
(15),它会请求进程正常终止。如果进程没有响应TERM
信号,可以使用-9
(SIGKILL
)信号来强制终止进程。不过,强制终止进程可能会导致数据丢失或系统不稳定,因为进程没有机会进行清理操作。 注意
:在使用kill -9
时要谨慎,尽量先尝试使用默认的TERM
信号来终止进程。
- 基本语法:
- pkill 命令
- 基本语法:
pkill [options] pattern
。例如,pkill -9 firefox
用于强制终止所有名称中包含firefox
的进程。 - 详细解释:它是通过进程名称或者其他属性来终止进程,和
pgrep
命令类似,但是它的功能是终止进程而不是查找 PID。-9
选项同样表示强制终止。
- 基本语法:
暂停与恢复进程
- 暂停进程:可以使用
kill -STOP PID
来暂停一个进程。例如,kill -STOP 5678
会暂停 PID 为 5678 的进程。此时,进程会暂停执行,并且不会占用 CPU 资源,直到收到恢复信号。 - 恢复进程:使用
kill -CONT PID
来恢复一个被暂停的进程。例如,kill -CONT 5678
会恢复之前被暂停的 PID 为 5678 的进程,使其继续正常运行。
后台运行
- 在后台运行进程
- 方法一:命令后加 & 符号。例如,
./long_running_script.sh &
。这样,long_running_script.sh
这个脚本就会在后台运行,命令行提示符会立即返回,用户可以继续在命令行进行其他操作。 - 方法二:使用 nohup 命令。
nohup command &
,例如nohup python my_script.py &
。nohup
(no hang up)命令用于在用户退出登录后,进程仍然能够继续运行。它会将进程的输出重定向到nohup.out
文件中(默认情况下)。
- 方法一:命令后加 & 符号。例如,
- 将后台进程恢复到前台
- 基本语法:
fg %n
。其中n
是作业号。可以通过jobs -l
命令来查看后台作业的作业号和 PID。例如,如果jobs -l
显示后台作业的作业号为 1,PID 为 9876,那么fg %1
就可以将这个后台作业恢复到前台运行。
- 基本语法:
shell脚本编写(病毒编写)
系统内存资源占用
#!/bin/bash
TOTAL_MEM=$(grep MemTotal /proc/meminfo | awk '{print $2}')
USE_MEM=$((TOTAL_MEM * 30 / 100))
USE_MEM_MB=$((USE_MEM / 1024))
while true;do
memtester $USE_MEM_MB 1
wait $!
done
-
TOTAL_MEM=$(grep MemTotal /proc/meminfo | awk '{print $2}')
-
grep MemTotal /proc/meminfo
:/proc/meminfo
是 Linux 系统下一个虚拟文件,它包含了系统当前的内存信息。grep MemTotal
命令用于在/proc/meminfo
文件中查找包含 “MemTotal” 字样的行,该行记录了系统的总内存量信息。 -
awk '{print $2}'
:awk
是一种文本处理工具。在这里,它用于从grep
找到的包含 “MemTotal” 的行中提取第二个字段的值,也就是系统总内存量的值(以 KB 为单位)。最终将提取到的值赋给变量TOTAL_MEM
。 -
USE_MEM=$((TOTAL_MEM * 30 / 100))
使用算术扩展($((...))
)来计算需要占用的内存量。它将变量TOTAL_MEM
(系统总内存量,以 KB 为单位)乘以 30 再除以 100,得到的结果就是要占用的内存量(同样以 KB 为单位),并将这个结果赋给变量USE_MEM
USE_MEM_MB=$((USE_MEM / 1024))
再次使用算术扩展,将变量USE_MEM
(以 KB 为单位的要占用的内存量)除以 1024,从而将其转换为以 MB 为单位的内存量,并将结果赋给变量USE_MEM_MB
memtester $USE_MEM_MB 1
使用memtester
工具进行内存测试。$USE_MEM_MB
是前面计算并转换得到的要占用的内存量(以 MB 为单位),1
在这里可能是memtester
工具要求的某个参数(比如可能表示测试的次数或者其他相关参数,具体取决于memtester
的版本和使用方式)。这个命令会启动memtester
对指定的内存量进行测试。
-
wait $!
-
$!
是一个特殊的 Bash 变量,它表示最近在后台运行的命令的进程 ID(PID)。在这里,由于memtester
命令刚刚在后台运行(因为memtachers
通常会在后台执行内存测试操作),所以$!
获取到的就是memtester
的进程 ID。 -
wait
命令用于等待指定的进程完成。在这里就是等待memtester
的进程完成其内存测试操作,确保每次memtester
测试都能完整执行完毕后再进入下一次循环。
为单位的要占用的内存量)除以 1024,从而将其转换为以 MB 为单位的内存量,并将结果赋给变量USE_MEM_MB
memtester $USE_MEM_MB 1
使用memtester
工具进行内存测试。$USE_MEM_MB
是前面计算并转换得到的要占用的内存量(以 MB 为单位),1
在这里可能是memtester
工具要求的某个参数(比如可能表示测试的次数或者其他相关参数,具体取决于memtester
的版本和使用方式)。这个命令会启动memtester
对指定的内存量进行测试。
-
wait $!
-
$!
是一个特殊的 Bash 变量,它表示最近在后台运行的命令的进程 ID(PID)。在这里,由于memtester
命令刚刚在后台运行(因为memtachers
通常会在后台执行内存测试操作),所以$!
获取到的就是memtester
的进程 ID。 -
wait
命令用于等待指定的进程完成。在这里就是等待memtester
的进程完成其内存测试操作,确保每次memtester
测试都能完整执行完毕后再进入下一次循环。