MST
星途 面试题库

面试题:Bash历史命令与脚本结合的深度应用

编写一个Bash脚本,该脚本能够读取当前用户的Bash历史命令记录,筛选出所有在过去一小时内执行过的包含 `sudo` 的命令,并将这些命令以时间倒序排列输出到一个新文件 `sudo_commands_last_hour.log` 中。在脚本中需要处理可能出现的权限问题及历史命令记录格式不一致的情况,简要说明脚本的设计思路及关键代码段的作用。
40.3万 热度难度
编程语言Bash

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 读取Bash历史命令记录文件,通常位于 ~/.bash_history
  2. 解析每条命令记录,提取时间戳(如果存在)。
  3. 判断命令是否在过去一小时内执行且包含 sudo
  4. 将符合条件的命令以时间倒序排列并输出到指定文件 sudo_commands_last_hour.log
  5. 处理权限问题,确保脚本有读取历史文件和写入输出文件的权限。

关键代码段及作用

  1. 读取历史文件
history_file=~/.bash_history
if [ -r "$history_file" ]; then
    while IFS= read -r line; do
        # 后续处理每一行命令
    done < "$history_file"
else
    echo "无法读取历史文件 $history_file"
    exit 1
fi

这段代码检查历史文件是否可读,如果可读则逐行读取文件内容,否则输出错误信息并退出。

  1. 解析时间戳和命令
timestamp_pattern='^[0-9]{10}:[0-9]{6} '
if [[ $line =~ $timestamp_pattern ]]; then
    timestamp=${BASH_REMATCH[0]% }
    command=${line#* }
else
    # 处理没有时间戳的情况,假设是当前时间
    timestamp=$(date +%s):000000
    command=$line
fi

这段代码尝试从命令记录行中提取时间戳,如果提取失败则假设命令是当前时间执行的。

  1. 判断时间和命令内容
current_time=$(date +%s)
one_hour_ago=$((current_time - 3600))
timestamp_value=${timestamp%%:*}
if ((timestamp_value >= one_hour_ago)) && [[ $command =~ sudo ]]; then
    echo "$line" >> temp_file
fi

这里计算当前时间和一小时前的时间戳,对比命令记录的时间戳是否在过去一小时内,并且命令是否包含 sudo,如果符合条件则将命令写入临时文件。

  1. 排序并输出到结果文件
sort -r temp_file > sudo_commands_last_hour.log
rm temp_file

将临时文件中的命令按时间倒序排序并输出到最终结果文件,然后删除临时文件。

完整脚本

#!/bin/bash

history_file=~/.bash_history
if [ -r "$history_file" ]; then
    temp_file=$(mktemp)
    while IFS= read -r line; do
        timestamp_pattern='^[0-9]{10}:[0-9]{6} '
        if [[ $line =~ $timestamp_pattern ]]; then
            timestamp=${BASH_REMATCH[0]% }
            command=${line#* }
        else
            timestamp=$(date +%s):000000
            command=$line
        fi
        current_time=$(date +%s)
        one_hour_ago=$((current_time - 3600))
        timestamp_value=${timestamp%%:*}
        if ((timestamp_value >= one_hour_ago)) && [[ $command =~ sudo ]]; then
            echo "$line" >> $temp_file
        fi
    done < "$history_file"
    if [ -w "sudo_commands_last_hour.log" ]; then
        sort -r $temp_file > sudo_commands_last_hour.log
    else
        echo "无法写入文件 sudo_commands_last_hour.log"
    fi
    rm $temp_file
else
    echo "无法读取历史文件 $history_file"
    exit 1
fi