接手一台别人维护过的服务器,或者排查"这个软件到底什么时候装的、谁装的、从哪装的",是运维里再常见不过的需求。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反查。 - 接手陌生服务器时用组合脚本一次性摸清发行版、已装包、启用服务、监听端口和第三方源,效率最高。
企业QQ咨询




