在日常的服务器管理中,是否经常为忘记曾经使用过的命令而苦恼?本文将分享如何通过编写简单的脚本和前端页面,记录并搜索所有执行过的Linux命令,让你的工作效率倍增。
在日常运维中,随着服务器数量的增加和使用时间的延长,我们可能会忘记一些曾经使用过的有用命令。当需要再次使用时,却苦于找不到。为了解决这个问题,我决定开发一个网页工具,记录所有执行的命令,方便日后查询。
一、收集执行的命令
首先,我们需要在每次执行命令后,收集相关信息并发送到外部接口。我的思路是编写一个Shell脚本,在每个命令执行后异步调用。以下是脚本的内容:
1. 编写收集命令的脚本
创建文件 /root/send_command.sh
,并确保它具有可执行权限:
chmod +x /root/send_command.sh
脚本内容如下:
#!/bin/bash
# 获取传递的命令
COMMAND="$1"
# 获取主机名
HOSTNAME=$(hostname)
# 获取IP地址(取第一个非回环地址)
IP_ADDRESS=$(hostname -I | awk '{print $1}')
# 获取当前用户
USER_NAME=$(whoami)
# 获取执行时间(ISO 8601 格式)
EXECUTION_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# 获取操作系统版本
OS_VERSION=$(grep -E '^PRETTY_NAME=' /etc/os-release | cut -d '"' -f 2)
# 构建JSON数据
JSON_DATA=$(cat <<EOF
{
"command": "$COMMAND",
"hostname": "$HOSTNAME",
"ip_address": "$IP_ADDRESS",
"user": "$USER_NAME",
"execution_time": "$EXECUTION_TIME",
"os_version": "$OS_VERSION"
}
EOF
)
# 发送数据到API
curl -X POST -H "Content-Type: application/json" \
-d "$JSON_DATA" \
https://example.com/send_command >/dev/null 2>&1
exit 0
2. 修改 .bashrc
文件
在 .bashrc
文件末尾添加以下内容,以确保每次命令执行后都会调用上述脚本:
# 定义脚本路径
SEND_COMMAND_SCRIPT="/root/send_command.sh"
# 定义函数,获取最近执行的命令并触发脚本
function send_last_command() {
# 获取最近一条命令
local CMD=$(history 1 | sed 's/^[ ]*[0-9]\+[ ]*//')
# 排除特定命令,避免递归调用
case "$CMD" in
send_command.sh|another_excluded_command)
;;
*)
# 异步调用脚本
nohup "$SEND_COMMAND_SCRIPT" "$CMD" >/dev/null 2>&1 &
disown
;;
esac
}
# 设置PROMPT_COMMAND,每次命令执行后触发函数
PROMPT_COMMAND="send_last_command;$PROMPT_COMMAND"
通过上述步骤,所有执行的命令都会被发送到指定的API接口。
二、展示和搜索命令
为了方便地查询和管理收集到的命令信息,我选择使用 Parse 作为后端服务,并开发了一个简单的前端页面来展示和搜索命令。
1. 前端页面代码
以下是完整的前端页面代码:
<!DOCTYPE html>
<html>
<head>
<title>Linux 命令历史搜索</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/parse/dist/parse.min.js"></script>
</head>
<body>
<div id="app" class="ui container" style="margin-top: 20px;">
<h2 class="ui header">Linux 命令历史搜索</h2>
<div class="ui fluid icon input">
<input type="text" v-model="searchQuery" placeholder="搜索命令、主机名、用户...">
<i class="search icon"></i>
</div>
<div class="ui fluid icon input" style="margin-top: 10px;">
<input type="text" v-model="excludeCommands" placeholder="输入要排除的命令 (例如:ls, echo)">
<i class="filter icon"></i>
</div>
<table class="ui celled table" style="margin-top: 20px;">
<thead>
<tr>
<th>命令</th>
<th>主机名</th>
<th>IP 地址</th>
<th>用户</th>
<th>执行时间</th>
<th>操作系统版本</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr v-for="command in filteredCommands" :key="command.id">
<td>{{ command.get('command') }}</td>
<td>{{ command.get('hostname') }}</td>
<td>{{ command.get('ip_address') }}</td>
<td>{{ command.get('user') }}</td>
<td>{{ formatBeijingTime(command.get('execution_time')) }}</td>
<td>{{ command.get('os_version') }}</td>
<td>
<div class="ui action input">
<input type="text" v-model="command.updatedRemark" :placeholder="command.get('remark') || '输入备注...'">
<button class="ui primary button" @click="saveRemark(command)">保存</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<script type="module">
const { createApp, ref, computed } = Vue;
// 初始化 Parse
Parse.initialize("your-app-id");
Parse.serverURL = 'https://your-parse-server.com/parse';
const LinuxCommand = Parse.Object.extend("LinuxCommand");
createApp({
setup() {
const searchQuery = ref('');
const excludeCommands = ref('ls, echo, pwd'); // 默认排除常用命令
const commands = ref([]);
// 获取命令数据
async function fetchCommands() {
const query = new Parse.Query(LinuxCommand);
query.descending("execution_time");
commands.value = await query.find();
commands.value.forEach(command => {
command.updatedRemark = command.get('remark') || '';
});
}
// 格式化时间为北京时间
function formatBeijingTime(utcTime) {
const date = new Date(utcTime);
return date.toLocaleString('zh-CN', { hour12: false });
}
// 保存备注信息
async function saveRemark(command) {
command.set('remark', command.updatedRemark);
await command.save();
fetchCommands();
}
// 过滤命令
const filteredCommands = computed(() => {
let filtered = commands.value;
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase();
filtered = filtered.filter(command => {
return (
command.get('command').toLowerCase().includes(query) ||
command.get('hostname').toLowerCase().includes(query) ||
command.get('ip_address').toLowerCase().includes(query) ||
command.get('user').toLowerCase().includes(query) ||
(command.get('remark') && command.get('remark').toLowerCase().includes(query))
);
});
}
if (excludeCommands.value) {
const excludes = excludeCommands.value.toLowerCase().split(',').map(cmd => cmd.trim());
filtered = filtered.filter(command => {
return !excludes.includes(command.get('command').toLowerCase());
});
}
return filtered;
});
// 初始获取数据
fetchCommands();
return {
searchQuery,
excludeCommands,
commands,
filteredCommands,
formatBeijingTime,
saveRemark
};
}
}).mount('#app');
</script>
</body>
</html>
2. 代码说明
- 前端框架:使用了 Vue 3 和 Semantic UI,简单易用,界面美观。
- 数据交互:通过 Parse SDK 与后端进行数据交互,获取并展示命令信息。
功能特点:
- 搜索:可以根据命令、主机名、用户等关键词进行搜索。
- 排除命令:支持输入要排除的命令,避免常用命令干扰搜索结果。
- 备注:可以为每条命令添加备注,方便日后参考。
三、总结
通过以上步骤,我们成功地创建了一个能够记录并搜索所有执行过的Linux命令的工具。它不仅解决了遗忘命令的困扰,还提高了服务器管理的效率。后续我会继续完善这个工具,欢迎大家提出建议和意见。