Linux服务器如何查看软件安装记录?包管理器与系统日志排查

接手一台别人维护过的服务器,或者排查"这个软件到底什么时候装的、谁装的、从哪装的",是运维里再常见不过的需求。Linux 的软件来源五花八门:发行版自带仓库、第三方源、手动编译、脚本一键安装、容器镜像……不同来源的"安装记录"存在不同地方,没有一条命令能通吃所有情况。搞清楚每种来源对应哪套查询方法,才能把账对清楚。

这篇文章按软件来源分类,讲清楚怎么查:发行版仓库安装的软件(apt/dpkg 和 yum/dnf/rpm 两套)、包管理器留下的日志、手动编译安装的软件、以及用容器或脚本装的软件。也会讲怎么从 /var/log 里挖出"什么时候装的"这类时间线信息。

读完你应该能在接到一台陌生服务器时,快速盘出装了什么、装在哪、怎么装的,为后续升级、迁移、安全审计提供依据。文中命令区分 RHEL 系和 Debian 系,需要的地方两套都给。

一、先想清楚:软件可能来自哪里

不同的安装方式,记录在不同的地方,这是排查的总纲。

安装方式 记录位置 查询手段
apt 仓库安装 dpkg 数据库 dpkg -l、apt list --installed
yum/dnf 仓库安装 rpm 数据库 rpm -qa、dnf list installed
包管理器操作历史 日志文件 /var/log/dpkg.log、/var/log/dnf.log、/var/log/yum.log
手动编译安装 无统一记录 查 /usr/local、which、ldd、编译目录的 config.log
脚本一键安装 视脚本而定 查脚本日志、安装目录
容器镜像 容器运行时 docker images、podman images
Snap/Flatpak 各自数据库 snap list、flatpak list
源码包/pip/npm 等 语言自己的管理器 pip list、npm ls -g 等

一条重要经验:rpm/dpkg 数据库只记录通过包管理器安装的软件。手动 make install 装的、脚本解压到 /opt 的,包管理器完全不知道,rpm -qa 里查不到,apt remove 也卸不掉。这类软件最容易在迁移时被遗漏。

二、查包管理器已经装了哪些软件

dpkg / apt(Debian、Ubuntu)

# 列出所有已安装的包
dpkg -l
# 只看包名和版本
dpkg-query -W -f='${Package} ${Version}\n'

# 按名称过滤
dpkg -l | grep nginx
apt list --installed 2>/dev/null | grep nginx

# 看某个包是否安装、装了什么版本
dpkg -s nginx
apt-cache policy nginx

# 看某个包安装了哪些文件(判断安装位置)
dpkg -L nginx

# 反查:某个文件属于哪个包(有助于识别"这文件哪来的")
dpkg -S /usr/sbin/nginx

# 列出某个包的所有版本历史(若还在缓存)
apt-get install --reinstall --dry-run nginx 2>/dev/null
# 按安装时间排序(实用:找"最近装了啥")
# 用 dpkg 数据库的 mtime 近似排序
ls -lt --time-style=long-iso /var/lib/dpkg/info/*.list | head -20

# 或用 dpkg-query 加脚本按安装时间列(较新 dpkg 支持)
dpkg-query -W -f='${Package}\t${Version}\t${db:Status-Abbrev}\n' | head

rpm / yum / dnf(RHEL、CentOS、Rocky、Alma)

# 列出所有已安装的包
rpm -qa
rpm -qa | sort
rpm -qa | grep nginx

# 看某包的详细信息(版本、安装时间、来源、签名)
rpm -qi nginx
# 输出里 Install Date 就是安装时间!

# 看某包安装了哪些文件
rpm -ql nginx

# 反查:文件属于哪个包
rpm -qf /usr/sbin/nginx

# 查某包由哪个仓库提供、是否改动过
rpm -q --whatprovides /usr/bin/python3
rpm -V nginx          # 校验文件是否被修改

# dnf 视角
dnf list installed | grep nginx
dnf info nginx

# 按安装时间排序(找最近安装的包)——非常实用
rpm -qa --last | head -20

rpm -qa --last 是最快的"最近装了什么"命令,它按安装时间倒序列出所有包。排查"这台机器最近被改了什么"时非常好用。

三、从日志里还原操作时间线

包管理器会把每次操作写进日志,这是还原"谁在什么时候装了什么"的关键。

Debian / Ubuntu:/var/log/dpkg.log 与 apt 日志

# dpkg 操作日志,记录 install/remove/upgrade 及时间
cat /var/log/dpkg.log
# 只看安装动作
grep ' status installed' /var/log/dpkg.log
grep -E 'install |upgrade ' /var/log/dpkg.log | tail -50

# 历史轮转的日志(.1 .2.gz 是更早的)
ls -l /var/log/dpkg.log*
zcat /var/log/dpkg.log.2.gz | grep install

# apt 的命令历史(记录执行过的 apt 命令)
cat /var/log/apt/history.log
zcat /var/log/apt/history.log.*.gz 2>/dev/null
# 内容包含:Start-Date、Commandline、Requested-By、Install、Upgrade 等

# apt 的 term.log 记录详细终端输出
cat /var/log/apt/term.log

/var/log/apt/history.log 尤为有用,它会记录执行命令的用户(Requested-By)和完整命令行,能回答"是谁装的、用的什么命令"。

RHEL 系:/var/log/dnf.log 与 yum.log

# dnf 日志(RHEL8+)
cat /var/log/dnf.log
cat /var/log/dnf.rpm.log

# 老系统 yum 日志
cat /var/log/yum.log
grep -iE 'Installed|Updated|Erased' /var/log/yum.log

# 轮转日志
ls -l /var/log/dnf*.log* /var/log/yum.log*

/var/log/dnf.rpm.log 里会有类似 Installed: nginx-1.x.x 的记录,配合时间戳能还原安装顺序。

通用:从 systemd journal 看

# journal 里也能找到包管理相关的记录
sudo journalctl -u dnf --no-pager | tail
sudo journalctl -u apt-daily-upgrade --no-pager | tail

# 按时间范围看
sudo journalctl --since "2026-10-01" --until "2026-10-05" | grep -i install

四、手动编译/脚本安装的软件怎么查

这类软件包管理器管不着,得从文件系统和进程入手。

# 1. 看常见的第三方安装目录
ls -l /usr/local/bin /usr/local/sbin
ls -l /opt
ls -l /usr/local/lib

# 2. 看命令的实际路径,判断是不是 /usr/local 下的自编译
which -a nginx
type -a python3
command -v nginx

# 3. 看二进制文件的时间(近似安装时间)
ls -l --time-style=full-iso /usr/local/bin/nginx
stat /usr/local/bin/nginx

# 4. 看进程的实际执行路径(含删除但仍运行的)
ps -eo pid,user,etime,cmd | grep -i nginx
sudo ls -l /proc//exe

# 5. 看服务单元里指向的可执行文件
systemctl cat nginx
cat /etc/systemd/system/nginx.service

# 6. 找编译痕迹
find /usr/local -name 'config.log' 2>/dev/null
find / -maxdepth 3 -name 'Makefile' 2>/dev/null | head

# 7. 判断二进制依赖了什么库
ldd /usr/local/bin/nginx
file /usr/local/bin/nginx

# 8. 看包的安装用户和构建信息(若保留了)
strings /usr/local/bin/nginx | grep -i 'gcc\|GCC:' | head

经验上,自编译软件常见落点是 /usr/local/、/opt/、以及业务自定的 /data、/srv 下。排查时重点扫这几个目录,配合 stat 看时间。

五、语言级包管理器和容器

现代服务器上,很多"软件"其实是通过语言包管理器或容器装的。

# Python
pip list                       # 当前环境
pip3 list --user               # 用户级
sudo -u appuser pip list       # 指定用户
find / -name "site-packages" -type d 2>/dev/null | head

# Node.js
npm ls -g --depth=0
npm root -g                    # 全局模块目录
yarn global list 2>/dev/null

# Java(多版本留意 alternatives)
update-alternatives --list java
ls -l /usr/lib/jvm

# Go
ls -l $(go env GOPATH)/bin 2>/dev/null

# 容器
docker images                  # 有哪些镜像
docker ps -a                   # 有哪些容器
podman images
ctr -n k8s.io images ls 2>/dev/null   # containerd

# Snap / Flatpak
snap list
flatpak list

容器场景要特别注意:容器里装了什么,宿主机用 rpm/dpkg 是查不到的,必须进容器或用镜像历史查。

# 看镜像每一层的构建历史(能看出装了什么)
docker history <镜像名>
# 进容器查
docker exec -it <容器名> sh -c 'dpkg -l | head'

六、快速盘点的组合拳

接手陌生服务器时,可以用一段脚本快速摸清底细:

#!/bin/bash
echo "=== 发行版 ==="
cat /etc/os-release | head -3

echo "=== 包管理器 ==="
command -v apt && command -v dpkg
command -v dnf && command -v rpm

echo "=== 最近安装的包(rpm 系)==="
rpm -qa --last 2>/dev/null | head -15

echo "=== 最近安装的包(deb 系,按 info 文件时间)==="
ls -lt /var/lib/dpkg/info/*.list 2>/dev/null | head -15

echo "=== /usr/local 与 /opt 下的软件 ==="
ls -l /usr/local/bin /usr/local/sbin /opt 2>/dev/null

echo "=== 启用的 systemd 服务 ==="
systemctl list-unit-files --state=enabled --type=service | head -30

echo "=== 监听端口及对应进程 ==="
ss -tulnp 2>/dev/null | head -30

echo "=== 第三方源 ==="
cat /etc/apt/sources.list 2>/dev/null
ls /etc/apt/sources.list.d/ 2>/dev/null
dnf repolist 2>/dev/null

这段脚本把"发行版、装了什么、跑着什么、从哪装的"几个维度一次性摸清,是接手排查的高效起点。

注意事项

  • 日志会被轮转:/var/log 下的日志会按大小或时间轮转并压缩,老记录可能已经被删。要查久远的历史,得依赖中央日志(rsyslog 转发、journal 持久化)或配置更长的保留期。
  • journal 默认不持久化:很多系统默认把 journal 存在内存里,重启即丢。需要持久化要建 /var/log/journal/ 目录或改 /etc/systemd/journald.conf 的 Storage=persistent。
  • 手动安装的软件是审计盲区:rpm -qa 和 dpkg -l 都查不到。做安全审计或迁移时,必须额外扫 /usr/local、/opt 和进程列表。
  • 注意第三方源的软件:从非官方源装的包,来源和可信度要单独评估,升级时也可能冲突。

七、从运行中的系统反查软件来源

除了静态地看包列表和日志,还有一种逆向思路:从"机器上正在跑什么"反推"装了什么"。这在接手陌生服务器或做安全审计时特别有效,往往能发现包管理器根本不知道的软件。

先看监听端口和对应进程。ss -tulnp 能列出所有监听中的 TCP/UDP 端口以及占用它们的进程,据此可以知道机器对外暴露了哪些服务。再看 systemd 里启用的服务,systemctl list-unit-files --state=enabled 列出所有开机自启的服务,逐个用 systemctl cat <服务名> 查看它指向哪个可执行文件、加载哪个配置文件。接着看进程列表,ps -eo pid,user,cmd --sort=-%mem | head 能看出哪些程序在吃内存、它们的启动参数是什么。把这些信息交叉比对,常常能挖出"包管理器里查不到、但确实在运行"的手动安装软件。

还有两个容易遗漏的地方值得专门扫一遍:一是计划任务,把各用户的 crontab 和系统级任务目录都过一遍,for u in $(cut -f1 -d: /etc/passwd); do echo "== $u =="; crontab -l -u $u 2>/dev/null; done,再加上 /etc/cron.d/、/etc/cron.daily/、/etc/cron.hourly/ 这些目录,可能藏着别人装的定时脚本;二是 shell 启动文件,~/.bashrc、~/.bash_profile、/etc/profile.d/ 里可能被加了别名、函数或启动脚本,用来拉起某些程序。审计时把这两块也扫一遍,能避免遗漏。

经验上,接管一台来源不明的服务器,先做一遍"包列表 + 已启用的服务 + 监听端口 + 计划任务"这四件套盘点,通常十几分钟就能摸清大体情况,比逐个目录翻找高效得多。摸清之后再决定哪些需要升级、哪些需要迁移、哪些需要重点审计。

日志保留与审计的两个前提

要想让上面这些排查手段在关键时刻真的可用,有两个前提必须提前满足,否则真到追溯的时候往往会"查无实据"。

第一是保证日志不会被过早清理。/var/log 下的日志会按 logrotate 策略轮转和删除,默认保留时间不长,包管理日志在日志量大时更容易被挤掉。对需要长期追溯的环境,应该调大保留份数,或把关键日志转发到中央日志服务器(rsyslog、syslog-ng、ELK 等)。systemd 的 journal 默认存在内存里、重启即丢,要长期保存必须先把 /var/log/journal/ 目录建出来,或在 /etc/systemd/journald.conf 里设 Storage=persistent 并调整 SystemMaxUse 控制占用上限。

第二是让包管理操作本身留下可追溯的记录。企业环境常见的做法是:给 dnf/yum 或 apt 操作统一走堡垒机或审计脚本,记录执行人和时间;同时开启系统级审计(auditd、acct/psacct),这样即便 /var/log/dnf.log 被轮转掉了,也能从别的渠道还原出"谁在什么时候装了什么"。把这两件事做在前面,等真正需要审计或排障时,才不会面对一台"干干净净、什么都没留下记录"的机器束手无策。对涉及合规的业务,这两项通常还是硬性要求。

常见问题

Q1:怎么知道某个软件是什么时候安装的?
rpm 系用 rpm -qi <包名> 看 Install Date,或 rpm -qa --last 排序;deb 系查 /var/log/dpkg.log 和 /var/log/apt/history.log。手动编译的靠 stat 二进制文件时间近似。

Q2:为什么 dpkg -l 或 rpm -qa 里找不到我装的软件?
多半是手动编译或脚本解压安装的,包管理器不记录这类安装。去 /usr/local、/opt 找,或用 which/ps/systemctl cat 从命令和进程反查。

Q3:怎么知道一个文件是哪个软件包的?
deb 系用 dpkg -S /路径/文件,rpm 系用 rpm -qf /路径/文件。查不到就说明不是包管理器装的。

Q4:apt 的 history.log 能看出是谁执行的吗?
能,里面有 Requested-By 字段记录执行用户(通常是 root 或 sudo 用户)。但它不记录来源 IP,若要精确追人需要结合 SSH 登录日志(/var/log/auth.log 或 /var/log/secure)。

Q5:容器里装的软件在宿主机怎么查?
宿主机查不到,容器的文件系统是独立的。用 docker exec 进容器查,或通过 docker history 看镜像构建历史。

总结

  • Linux 软件来源多样,先按"仓库安装 / 手动编译 / 脚本 / 容器 / 语言包管理器"分类,再对号使用对应查询手段。
  • 仓库安装的软件用 dpkg -l、rpm -qa,装了什么文件用 dpkg -L、rpm -ql,反查文件归属用 dpkg -S、rpm -qf。
  • 安装时间和操作人从日志还原:deb 系看 /var/log/dpkg.log 和 /var/log/apt/history.log,rpm 系看 /var/log/dnf.log、/var/log/yum.log 和 rpm -qa --last。
  • 手动编译/脚本安装的软件是包管理器的盲区,必须扫 /usr/local、/opt,用 which、ps、systemctl cat、stat 反查。
  • 接手陌生服务器时用组合脚本一次性摸清发行版、已装包、启用服务、监听端口和第三方源,效率最高。