bash手册

(20231102更新)

资料来源

shell脚本面试题 | 张贺贺呀 | cnblogs

shell

基础知识

三种引号区分

在Shell脚本中,有三种常见的引号用于包围字符串,它们是单引号(' ')、双引号(" ")和反引号(` `),它们各自有不同的用途和作用范围。

  1. 单引号(' '):
    • 单引号是最简单的引号形式,它会完全保留字符串中的原始内容,不对其中的特殊字符进行转义,也不进行变量替换。例如,'Hello World!' 中的内容将会作为字面字符串输出,不进行任何处理。
    • 单引号的作用范围仅限于单引号内部,不会扩展成其他字符。
  2. 双引号(" "):
    • 双引号可以对字符串中的特殊字符进行转义,例如使用双引号可以直接表示换行符(\n)、制表符(\t)等特殊字符。例如,"Hello\nWorld!" 中的内容会转义为两行,第一行是 "Hello",第二行是 "World!"。
    • 双引号可以进行变量替换,即将变量的值嵌入到字符串中。例如,"My name is $name" 中的 $name 会被替换为变量 name 的值。
  3. 反引号(` `):
    • 反引号用于执行命令替换,将反引号内的命令执行后的结果作为字符串返回。
    • 例如,`ls` 将会执行 ls 命令,并将输出作为字符串返回。
    • 注意,反引号已经不再推荐使用,一般使用更加现代的命令替换方式 $( ) 来替代。

单引号保留原样,双引号适合变量替换和处理特殊字符,反引号用于命令替换(推荐使用 $( ))。根据需要选择合适的引号来包围字符串。

配置文件的启动顺序

四个常见的配置文件,其启动顺序如下:

  1. /etc/profile:这是系统级的配置文件,对所有用户生效。当用户登录时,会首先读取并执行该文件中的配置,用于设置系统范围的环境变量和执行系统级的配置操作。
  2. /etc/bashrc:同样是系统级的配置文件,对所有用户生效。当用户打开一个新的终端窗口或者执行一个新的bash shell时,会读取并执行该文件中的配置,用于设置系统范围的bash shell的环境变量和执行系统级的bash shell配置。
  3. ~/.bash_profile:这是每个用户的个人配置文件,对特定用户生效。当用户登录时,会读取并执行该文件中的配置,用于设置用户级的环境变量和执行用户级的配置操作。该文件一般包含了一些用户级别的环境变量设置和个人化的操作。
  4. ~/.bashrc:同样是每个用户的个人配置文件,对特定用户生效。当用户打开一个新的终端窗口或者执行一个新的bash shell时,会读取并执行该文件中的配置,用于设置用户级的bash shell的环境变量和执行用户级的bash shell配置。该文件一般包含了一些用户级别的环境变量设置和个人化的操作。

启动顺序为:/etc/profile -> /etc/bashrc -> ~/.bash_profile -> ~/.bashrc。
当用户登录时,会执行系统级的配置文件(/etc/profile和/etc/bashrc),然后再执行用户级的配置文件(~/.bash_profile和~/.bashrc)。

read的交互

在Shell脚本中,"read"命令用于与用户进行交互,可以读取用户的输入并将其赋值给一个变量。以下是使用"read"命令进行交互的一般用法和常见选项:
一般用法:

read variable_name

上述命令将提示用户输入,并将用户的输入赋值给变量 variable_name。
常见选项:

  • "-p":指定一个提示信息,用于提示用户输入。
read -p "Please enter your name: " name

上述命令将提示用户输入,并将用户输入的内容赋值给变量 name。

  • "-s":使输入内容不回显到终端上,通常用于输入密码等敏感信息。
read -s -p "Please enter your password: " password

上述命令将提示用户输入,并将用户输入的内容赋值给变量 password,同时不回显输入内容。

  • "-t":设置一个超时时间,若用户在指定时间内未输入,则"read"命令会自动退出。
read -t 5 -p "Please enter your name within 5 seconds: " name

上述命令将提示用户在5秒钟内输入姓名,如果超过5秒未输入,则"read"命令会自动退出。

  • "-a":将用户的输入作为数组元素。
read -a fruits

上述命令会提示用户输入多个水果名称,然后将每个水果名称作为数组 fruits 的元素。

bash调试

在Bash脚本中,可以通过使用bash -x命令来启动调试模式。该命令会逐行执行脚本,并将执行过程以及执行结果输出到终端上,方便定位和解决问题。
以下是使用bash -x进行脚本调试的示例:

bash -x scriptname.sh

上述命令将以调试模式运行名为scriptname.sh的脚本。
在调试模式下,Bash脚本会按照以下方式进行执行:

  1. 打印出每一行要执行的命令。
  2. 将变量的值打印出来(使用${}标记法)。
  3. 展示实际执行的命令行及其输出结果。
    调试模式会将每一行执行后的结果输出,以及未定义的变量,语法错误等信息。通过观察输出结果,您可以判断脚本的执行流程和问题所在,进而进行调试和修正。
    需要注意的是,调试模式会在终端上产生大量的输出信息,可能会导致输出过多以致看不清楚。因此,在调试模式下,您可以将输出重定向到一个文件中,以便于查看和分析。
bash -x scriptname.sh > debug.log

使用bash -x命令进行脚本调试可以方便地跟踪脚本的执行过程,帮助定位问题并解决错误。

$0、$1、$#、$@、$* 、$?、$$

在Bash脚本中,以下是常见的特殊变量含义:

  • $0 :代表脚本本身的名称(即脚本的文件名)。
  • $1 :代表第一个参数。
  • $# :代表传递给脚本的参数个数。
  • $@ :代表所有传递给脚本的参数,每个参数都用双引号引起来,可以作为一个单独的参数进行引用。
  • $* :代表所有传递给脚本的参数,每个参数都用单个空格分隔开,作为一个连续的字符串进行引用。
  • $? :代表上一个命令(或脚本)的退出状态,如果命令执行成功则为0,否则为非零值。
  • $$ :代表当前脚本执行时的进程ID。
    下面是一个示例来说明这些特殊变量的含义和用法:
#!/bin/bash
echo "脚本名称为:$0"
echo "第一个参数为:$1"
echo "传递给脚本的参数个数为:$#"
echo "传递给脚本的参数列表为:$@"
echo "传递给脚本的参数列表为:$*"
echo "上一个命令的退出状态为:$?"
echo "当前脚本的进程ID为:$$"

如果保存为test.sh并执行 bash test.sh arg1 arg2,将会得到以下输出:

脚本名称为:test.sh
第一个参数为:arg1
传递给脚本的参数个数为:2
传递给脚本的参数列表为:arg1 arg2
传递给脚本的参数列表为:arg1 arg2
上一个命令的退出状态为:0
当前脚本的进程ID为:1234 (假设进程ID为1234)

通过使用这些特殊变量,可以方便地在脚本中获取脚本名、接收传递的参数、获取命令执行的结果等信息,进行进一步的处理和判断。

$(( ))、$[ ]、expr

在Bash脚本中,有多种方式可以进行变量运算:

  1. $(( )):这种方式用于进行算术运算,支持基本的算术运算符(如加法、减法、乘法、除法、取余等)和比较运算符(如等于、不等于、大于、小于等)。示例如下:
num1=10
num2=5
result=$((num1 + num2))
echo "Result: $result"  # Output: 15
  1. $[ ]:与$(( ))类似,也用于进行算术运算,但在一些较旧的Bash版本中仍然被支持。示例如下:
num1=10
num2=5
result=$[num1 + num2]
echo "Result: $result"  # Output: 15
  1. expr命令:这是一个用于进行基本算术运算和字符串处理的命令。它使用一种特定的语法,并将结果输出到标准输出。示例如下:
num1=10
num2=5
result=$(expr $num1 + $num2)
echo "Result: $result"  # Output: 15

请注意,expr命令在执行算术运算时,需要使用反斜杠\对一些特殊字符进行转义,比如乘法运算符*,如下示例:

num1=10
num2=5
result=$(expr $num1 \* $num2)
echo "Result: $result"  # Output: 50

但是,对于整数运算,建议使用$(( ))$[ ],因为它们更简洁和易读,并且不需要对特殊字符进行转义。

变量的替换和删除

在Bash脚本中,可以使用变量的替换和删除操作来修改或删除变量的值:

  1. 前向删除:${变量#模式} 或者 ${变量##模式}。这种操作会从变量的开头匹配并删除最短或最长的指定模式。如果使用#,则删除最短匹配模式;如果使用##,则删除最长匹配模式。示例如下:
name="Hello World"
echo ${name#Hello }     # Output: World  (删除最短匹配模式)
echo ${name##Hello }    # Output: World  (删除最长匹配模式)
  1. 后向删除:${变量%模式} 或者 ${变量%%模式}。这种操作会从变量的末尾匹配并删除最短或最长的指定模式。如果使用%,则删除最短匹配模式;如果使用%%,则删除最长匹配模式。示例如下:
filename="test.tar.gz"
echo ${filename%.gz}     # Output: test.tar (删除最短匹配模式)
echo ${filename%%.tar.gz}  # Output: test (删除最长匹配模式)
  1. 变量替换:${变量/模式/替换} 或者 ${变量//模式/替换}。这种操作会从变量中找到并替换指定的模式。如果使用单斜杠/,则只会替换第一个匹配;如果使用双斜杠//,则会替换所有匹配。示例如下:
str="I love apples, apples are delicious."
echo ${str/apple/orange}    # Output: I love oranges, apples are delicious. (替换第一个匹配)
echo ${str//apple/orange}   # Output: I love oranges, oranges are delicious. (替换所有匹配)
  1. 变量默认值:${变量:-默认值} 或者 ${变量:=默认值}。这种操作在变量为空或未设置时,默认使用指定的默认值。如果使用:-,则只有在变量为空或未设置时才使用默认值;如果使用:=,则设置变量的同时,若变量为空或未设置,也使用默认值。示例如下:
value=""
echo ${value:-"Default Value"}   # Output: Default Value (变量为空,使用默认值)
echo ${value:="Default Value"}   # Output: Default Value (变量为空,设置默认值)

使用这些变量替换和删除的操作,我们可以轻松地修改和处理变量的值,以满足脚本的需求。

for循环打印一个序列

for (( i=10;i>=1;i-- ));do echo $i;done

脚本范例

文件中删除所有空行

#!/bin/bash
# 要处理的文件
file_path="path/to/file.txt"
# 判断文件是否存在
if [ -f "$file_path" ]; then
  # 使用sed命令删除空行,并将结果保存到临时文件
  sed '/^\s*$/d' "$file_path" > "$file_path.tmp"
  # 将临时文件替换原始文件
  mv "$file_path.tmp" "$file_path"
  echo "空行已删除!"
else
  echo "文件不存在!"
fi

备份一个目录中的所有文件到另一个目录

#!/bin/bash
# 源目录和目标目录
source_dir="/path/to/source_directory"
target_dir="/path/to/target_directory"
# 创建目标目录(如果不存在)
mkdir -p $target_dir
# 备份源目录中的所有文件
cp -r $source_dir/. $target_dir
echo "备份完成!"

查找某个字符串,并将包含该字符串的行输出到另一个文件中

#!/bin/bash
# 源文件和目标文件
source_file="/path/to/source_file.txt"
target_file="/path/to/target_file.txt"
# 要查找的字符串
search_string="search_string"
# 查找包含字符串的行并输出到目标文件
grep "$search_string" $source_file > $target_file
echo "查找完成!结果已保存到 $target_file"

监控一个指定的进程是否在运行,并在进程停止时发送邮件通知

#!/bin/bash
# 要监控的进程名
process_name="process_name"
# 发送邮件的配置
email_recipient="email@example.com"
email_subject="进程停止通知"
email_message="进程 $process_name 已停止运行!"
# 检查进程是否在运行
check_process() {
  if pgrep -x "$process_name" > /dev/null; then
    return 0
  else
    return 1
  fi
}
# 发送邮件通知
send_email_notification() {
  echo "$email_message" | mail -s "$email_subject" "$email_recipient"
  echo "邮件通知已发送至 $email_recipient"
}
# 持续监控进程状态
while true; do
  if check_process; then
    sleep 10
  else
    send_email_notification
    break
  fi
done

统计history的top10

#!/bin/bash
# 统计history命令使用记录
output=$(history | awk '{print $2}' | sort | uniq -c | sort -nr)
# 找出前10个使用最频繁的命令
top_ten=$(echo "$output" | head -n 10)
# 输出结果
echo "前10个使用最频繁的命令:"
echo "$top_ten"
  1. history | awk '{print $2}':运行history命令并使用awk仅获取每行的第二列,即命令本身。
  2. sort:对命令进行排序,以便可以对其进行统计。
  3. uniq -c:统计命令出现的次数并添加到每行前面。
  4. sort -nr:按照出现次数进行逆序排序,使最常用的命令位于前面。
  5. head -n 10:截取前10行,即前10个使用最频繁的命令。
  6. 最后将结果输出。

备份并压缩/etc目录里面所有的内容,存放在/root/bak目录里面,备份完成的文件格式为:“yymmdd_etc”,脚本名称为backup.sh存放在/server/scripts目录下

#!/bin/bash
# 获取当前日期
current_date=$(date "+%y%m%d")
# 检查是否为每月第一天
if [ $(date "+%d") -eq 01 ]; then
    # 备份并压缩/etc目录
    backup_file="/root/bak/${current_date}_etc.tar.gz"
    tar -czvf $backup_file /etc
    # 打印备份完成信息
    echo "备份完成,备份文件在: $backup_file"
else
    # 打印非每月第一天的信息
    echo "今天不是每月第一天,不进行备份"
fi
  1. #!/bin/bash:指定脚本使用Bash shell进行解析。
  2. current_date=$(date "+%y%m%d"):使用date命令获取当前日期,格式为yymmdd
  3. if [ $(date "+%d") -eq 01 ]; then:使用date命令获取当前日期的天数,当天数等于01时,表示为每月第一天。
  4. backup_file="/root/bak/${current_date}_etc.tar.gz":指定备份文件的路径和文件名格式。
  5. tar -czvf $backup_file /etc:使用tar命令备份并压缩/etc目录,并将结果保存为指定的备份文件。
  6. echo "备份完成,备份文件在: $backup_file":打印备份完成的信息,包括备份文件的路径和名称。
  7. echo "今天不是每月第一天,不进行备份":打印非每月第一天的信息。
    保存脚本为backup.sh,将其放置在/server/scripts目录下。然后,在终端中切换到脚本所在的目录,并使用以下命令为脚本添加执行权限:
chmod +x backup.sh

最后,通过以下命令执行脚本:

./backup.sh

脚本将检查当前日期是否为每月第一天,如果是,则执行备份并压缩/etc目录;如果不是,则只打印相应的提示信息。成功备份后,将输出备份完成的信息。备份文件将保存在/root/bak目录下,并以指定的文件名格式进行命名。

当内存/磁盘用量达到80%的时候触发邮件报警

#!/bin/bash
# 内存使用量阈值,单位为百分比
memory_threshold=80
# 磁盘使用量阈值,单位为百分比
disk_threshold=80
# 获取内存使用率(百分比)
memory_usage=$(free | awk '/Mem/{printf("%d"), $3/$2*100}')
# 获取磁盘使用率(百分比)
disk_usage=$(df -h | awk '/\/$/{print $5}' | sed 's/%//')
# 检查内存使用率是否超过阈值
if [ $memory_usage -ge $memory_threshold ]; then
    # 发送邮件报警
    echo "Warning: Memory usage exceeds ${memory_threshold}%!" | mail -s "Memory Usage Alert" your_email@example.com
fi
# 检查磁盘使用率是否超过阈值
if [ $disk_usage -ge $disk_threshold ]; then
    # 发送邮件报警
    echo "Warning: Disk usage exceeds ${disk_threshold}%!" | mail -s "Disk Usage Alert" your_email@example.com
fi

解释:

  1. memory_threshold:设置内存使用量的阈值,单位为百分比,在本例中为80%。
  2. disk_threshold:设置磁盘使用量的阈值,单位为百分比,在本例中为80%。
  3. memory_usage=$(free | awk '/Mem/{printf("%d"), $3/$2*100}'):使用free命令获取内存使用情况,并通过awk命令计算出内存使用率(使用的内存量除以总内存量再乘以100)。
  4. disk_usage=$(df -h | awk '/\/$/{print $5}' | sed 's/%//'):使用df命令获取磁盘使用情况,并通过awk命令提取根目录的使用率(即/的行),再通过sed命令去除百分号。
  5. if [ $memory_usage -ge $memory_threshold ]; then:检查内存使用率是否超过阈值。
  6. echo "Warning: Memory usage exceeds ${memory_threshold}%!" | mail -s "Memory Usage Alert" your_email@example.com:如果内存使用率超过阈值,则发送邮件报警,内容包含警告信息,并使用mail命令发送给指定的邮箱地址。
  7. if [ $disk_usage -ge $disk_threshold ]; then:检查磁盘使用率是否超过阈值。
  8. echo "Warning: Disk usage exceeds ${disk_threshold}%!" | mail -s "Disk Usage Alert" your_email@example.com:如果磁盘使用率超过阈值,则发送邮件报警,内容包含警告信息,并使用mail命令发送给指定的邮箱地址。
    将脚本保存为usage_alert.sh,然后在终端上运行该脚本。如果内存或磁盘使用量超过设定的阈值,脚本将触发邮件报警并将相应的警告信息发送到指定的邮箱地址。

批量添加用户,提示输入前缀和用户个数,随机密码

#!/bin/bash
# 提示输入前缀和用户个数
read -p "请输入用户前缀:" prefix
read -p "请输入用户个数:" count
# 循环添加用户
for ((i=1; i<=count; i++)); do
    # 生成随机密码
    password=$(date +%s%N | sha256sum | head -c12)
    # 添加用户
    username="${prefix}${i}"
    useradd -m -s /bin/bash $username
    # 设置用户密码
    echo $password | passwd --stdin $username
    # 打印用户信息
    echo "已添加用户:${username},密码:${password}"
done

以上脚本会提示用户输入前缀和需要创建的用户个数。然后,它会使用循环逐个添加用户,并为每个用户生成一个随机密码。最后,脚本会打印用户的用户名和对应的密码。

批量探测主机

#!/bin/bash
# 输入主机网段
read -p "请输入主机网段(例如:192.168.0.0/24): " subnet
# 遍历网段中的所有IP地址
for ip in $(nmap -sn $subnet | grep "Nmap scan report" | awk '{print $NF}'); do
    # Ping测试
    ping -c1 $ip >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "$ip is alive"
    else
        echo "$ip is unreachable"
    fi
done

这个脚本使用了nmap命令来扫描指定的主机网段,并遍历网段中的所有IP地址。然后,使用ping命令来对每个IP地址进行Ping测试。如果Ping成功,则输出相应的IP地址为"alive",如果Ping失败,则输出相应的IP地址为"unreachable"。

分库分表备份

分库分表备份是一种数据库备份策略,用于处理大型数据库的备份需求。在分库分表架构下,数据被分散存储在多个数据库和表中,这样可以提高数据库的性能和扩展能力。然而,由于数据分布在多个地方,备份变得更加复杂。以下是一个简单的分库分表备份脚本示例:

#!/bin/bash
# 定义数据库列表
databases=("database1" "database2" "database3")
# 定义分表列表
tables=("table1" "table2" "table3")
# 定义备份目录
backup_dir="/path/to/backup"
# 获取当前日期和时间
current_date=$(date +%Y%m%d)
current_time=$(date +%H%M%S)
# 创建备份目录
mkdir -p $backup_dir/$current_date/$current_time
# 循环备份数据库
for db in "${databases[@]}"; do
    # 循环备份分表
    for table in "${tables[@]}"; do
        # 构建备份文件路径
        backup_file="$backup_dir/$current_date/$current_time/$db.$table.sql"
        # 执行备份命令
        mysqldump -u username -p password $db $table > $backup_file
        # 检查备份是否成功
        if [ $? -eq 0 ]; then
            echo "备份 $db.$table 成功"
        else
            echo "备份 $db.$table 失败"
        fi
    done
done

这个脚本使用了mysqldump命令来备份MySQL数据库的指定表。首先,定义了要备份的数据库列表和分表列表。然后,定义了备份目录,这是存储备份文件的位置。接下来,获取当前的日期和时间,并创建对应的备份目录。接下来,使用嵌套的循环来备份每个数据库的每个分表。备份文件的命名方式是数据库名.表名.sql,备份文件路径是备份目录/日期/时间/数据库名.表名.sql。最后,使用mysqldump命令来备份指定的数据库表,并将备份结果保存到相应的备份文件中。备份完成后,检查备份命令的退出状态码是否为0,以判断备份是否成功。

主从状态监测

#!/bin/bash
# 主服务器
master_host="主服务器IP"
master_port="主服务器端口"
master_user="主服务器用户名"
master_password="主服务器密码"
# 从服务器列表
declare -A slave_servers=(
    [slave1]="从服务器1IP"
    [slave2]="从服务器2IP"
    [slave3]="从服务器3IP"
)
# 遍历从服务器列表
for server in "${!slave_servers[@]}"; do
    echo "检查从服务器 $server"
    slave_host="${slave_servers[$server]}"
    # 检查从服务器与主服务器的连接状态
    slave_status=$(mysql -h $slave_host -u $master_user -p$master_password -e "SHOW SLAVE STATUS\G" 2>/dev/null)
    if [ $? -ne 0 ]; then
        echo "无法连接到从服务器 $slave_host"
        continue
    fi
    # 检查主从复制状态是否正常
    replication_status=$(echo "$slave_status" | grep "Slave_IO_Running:\|Slave_SQL_Running:" | awk '{print $2}')
    if [[ "$replication_status" != "Yes" ]]; then
        echo "主从复制状态异常 on $slave_host"
    else
        echo "主从复制状态正常 on $slave_host"
    fi
    echo
done

该脚本使用了mysql命令在从服务器上执行SHOW SLAVE STATUS命令,以获取主从复制的状态信息。脚本首先定义了主服务器和从服务器的相关参数,包括主服务器IP、端口、用户名和密码,以及从服务器列表。
然后,使用for循环遍历从服务器列表,通过mysql命令连接到每个从服务器,并执行SHOW SLAVE STATUS命令获取复制状态信息。如果无法连接到从服务器,脚本输出连接错误信息并继续下一个服务器。
在连接成功后,脚本从SHOW SLAVE STATUS的输出中提取Slave_IO_RunningSlave_SQL_Running字段的值,这两个字段分别表示主从复制的IO进程和SQL进程是否正常运行。如果其中任何一个字段的值不是"Yes",则表示主从复制状态异常,脚本输出相应的错误信息。否则,脚本输出主从复制状态正常的信息。

监控网站

#!/bin/bash
# 网站URL
website_url="http://www.example.com"
# 发送邮件的邮箱配置
from_email="example@gmail.com"
to_email="admin@example.com"
smtp_server="smtp.gmail.com"
smtp_port="587"
smtp_username="example@gmail.com"
smtp_password="password"
# 日志文件路径
log_file="/path/to/log/file.log"
# 检查网站状态函数
check_website() {
    response=$(curl -Is "$website_url" | head -n 1 | awk '{print $2}')
    if [ "$response" != "200" ]; then
        send_alert_email
    fi
}
# 发送邮件函数
send_alert_email() {
    echo "Website is down at $(date)" >> "$log_file"
    (echo "Subject: Website is down"; echo "Website $website_url is down at $(date)") | \
        msmtp -t -a default -d -h "$smtp_server" -p "$smtp_port" -f "$from_email" -r "$from_email" \
        -x -au "$smtp_username" -ap "$smtp_password" "$to_email" >> "$log_file"
}
# 检查网站状态并发送报警邮件
check_website

该脚本用于监控指定网站的状态,并在网站挂掉时发送邮件报警。脚本中的相关参数需要根据实际情况进行修改。

  • website_url:需要监控的网站的URL。将此变量更改为实际的网站URL。
  • from_email:发送邮件的邮箱地址。将此变量更改为实际的发送邮箱地址。
  • to_email:接收报警邮件的邮箱地址。将此变量更改为实际的接收邮箱地址。
  • smtp_serversmtp_port:SMTP服务器名称和端口号。将这两个变量更改为实际的SMTP服务器信息。
  • smtp_usernamesmtp_password:SMTP服务器的用户名和密码。将这两个变量更改为实际的SMTP用户名和密码。
  • log_file:日志文件的路径。将此变量更改为实际的日志文件路径。
    脚本通过使用curl命令发送HTTP请求并检查响应状态码来检查网站的状态。如果响应状态码不是"200",即网站挂掉,脚本将调用send_alert_email函数发送报警邮件。
    send_alert_email函数会将网站挂掉的时间记录到日志文件中,并使用msmtp命令发送报警邮件。脚本通过echo命令构造邮件的主题和内容,然后将邮件内容通过管道传递给msmtp命令发送邮件。msmtp命令通过提供SMTP服务器的相关参数和身份验证信息来发送邮件。

SSH

#bin/bash
Ssh -t -t test@127.0.0.1	# remotessh 进入远程系统
Source /etc/profile	#刷新配置文件,可以跳过,这一步就是在远程系统上执行命令了
Echo “test”
Cp /etc/a /etc/b	#这里就是你需要执行的命令,和正常的操作一样的。
Exit	#如果你执行完了,就可以退出了,一定要退出。
Remotessh	#这个命令是结束的意思,一定要有。

防火墙

iptables

#!/bin/bash
# 删除已有规则
iptables -F
# 设置链的默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# 阻止指定的IP地址(这里以192.168.1.100为例)
iptables -A INPUT -s 192.168.1.100 -j DROP
# 使用multiport将ssh,http,https的流量访问连接
iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT
iptables -A OUTPUT -p tcp -m multiport --sports 22,80,443 -j ACCEPT
# 允许本地发起的SSH请求
iptables -A OUTPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
# 做好负载平衡传入的网络流量(这里以两台服务器进行负载均衡为例)
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 2 --packet 0 -j DNAT --to-destination 192.168.1.10:80
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 1 --every 2 --packet 0 -j DNAT --to-destination 192.168.1.11:80
# 内部网络与外部网络的通信
iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
# 出站的DNS连接(这里以Google Public DNS为例)
iptables -A OUTPUT -p udp --dport 53 -d 8.8.8.8 -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -d 8.8.4.4 -j ACCEPT
# 指定网络的mysql连接(这里以192.168.1.0/24为例)
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 3306 -j ACCEPT
iptables -A OUTPUT -p tcp -d 192.168.1.0/24 --sport 3306 -m state --state ESTABLISHED -j ACCEPT
# 允许IMAP和IMAPS
iptables -A INPUT -p tcp --dport 143 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 143 -j ACCEPT
iptables -A INPUT -p tcp --dport 993 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 993 -j ACCEPT
# 防止DoS攻击(这里以synflood为例)
iptables -N synflood
iptables -A synflood -m limit --limit 1/s --limit-burst 3 -j RETURN
iptables -A synflood -j DROP
iptables -A INPUT -p tcp --syn -j synflood
# 422端口的流量全部转移到22端口
iptables -A PREROUTING -t nat -p tcp --dport 422 -j REDIRECT --to-port 22

解释

1. 第一行“#!/bin/bash”指定了这个脚本使用的解释器是Bash。
2. “iptables -F”命令会清空iptables中的所有规则,相当于删除已有规则。
3. “iptables -P INPUT DROP”命令设置INPUT链的默认策略为DROP,即拒绝所有传入的数据包;“iptables -P FORWARD DROP”命令设置FORWARD链的默认策略为DROP,即拒绝所有转发的数据包;“iptables -P OUTPUT ACCEPT”命令设置OUTPUT链的默认策略为ACCEPT,即允许所有传出的数据包。
4. “iptables -A INPUT -s 192.168.1.100 -j DROP”命令添加一条规则,将源IP地址为192.168.1.100的数据包丢弃。
5. “iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT”命令添加一条规则,允许TCP协议的ssh、http、https流量访问连接;“iptables -A OUTPUT -p tcp -m multiport --sports 22,80,443 -j ACCEPT”命令添加一条规则,允许TCP协议的ssh、http、https流量访问连接的回复数据包。
6. “iptables -A OUTPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT”命令添加一条规则,允许TCP协议的ssh连接的发起数据包;“iptables -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT”命令添加一条规则,允许TCP协议的ssh连接的回复数据包。
7. “iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 2 --packet 0 -j DNAT --to-destination 192.168.1.10:80”和“iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 1 --every 2 --packet 0 -j DNAT --to-destination 192.168.1.11:80”命令添加了两条规则,将传入的80端口的TCP流量进行负载均衡,分别转发到两台服务器上。
8. “iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT”和“iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT”命令添加了两条规则,允许eth0和eth1之间的数据包转发。
9. “iptables -A OUTPUT -p udp --dport 53 -d 8.8.8.8 -j ACCEPT”和“iptables -A OUTPUT -p udp --dport 53 -d 8.8.4.4 -j ACCEPT”命令添加了两条规则,允许向Google Public DNS发送DNS查询请求。
10. “iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 3306 -j ACCEPT”和“iptables -A OUTPUT -p tcp -d 192.168.1.0/24 --sport 3306 -m state --state ESTABLISHED -j ACCEPT”命令添加了两条规则,允许192.168.1.0/24网段的主机通过TCP协议访问本机的3306端口,并允许本机向192.168.1.0/24网段的主机发送TCP连接的回复数据包。
11. “iptables -A INPUT -p tcp --dport 143 -j ACCEPT”和“iptables -A OUTPUT -p tcp --sport 143 -j ACCEPT”命令添加了两条规则,允许IMAP协议的流量访问连接和回复连接。
12. “iptables -N synflood”命令添加了一个名为synflood的用户自定义链。
13. “iptables -A synflood -m limit --limit 1/s --limit-burst 3 -j RETURN”命令向synflood链中添加了一条规则,限制每秒最多处理一个syn数据包,每次处理不超过三个syn数据包。
14. “iptables -A synflood -j DROP”命令向synflood链中添加了一条规则,将超出限制的syn数据包丢弃。
15. “iptables -A INPUT -p tcp --syn -j synflood”命令向INPUT链中添加了一条规则,将所有的syn数据包传递到synflood链中进行处理。
16. “iptables -A PREROUTING -t nat -p tcp --dport 422 -j REDIRECT --to-port 22”命令添加了一条规则,将422端口的流量全部转发到22端口上。
posted @ 2023-10-17 17:16  Mugetsukun  阅读(29)  评论(0编辑  收藏  举报