随着时间的推移,大多数 Linux 爱好者积累了一个闪闪发光的战争宝箱,里面装满了来之不易的技巧,当情况需要在终端上快速思考时,这些技巧可以派上用场。多年来,每当我有机会在一个非常精通 Linux 的人的肩膀上观看时,我都会把这些知识中的许多东西藏起来。
今天,你在航站楼和我配对。我们正在探索 Linux 文件系统和 shell 工具和技巧的深度。
/proc
Linux 系统中最有用的目录之一是/proc
。从proc
的man
页:
proc 文件系统是一个伪文件系统,它为内核数据结构提供接口。
当man
页显示“伪文件系统”时,这意味着如果您要在磁盘下方窥视,您可能希望找到代表文件的位,就像/tmp/launch-codes.txt
中的文本文件一样,有/proc
什么都没有。它在正在运行的 Linux 系统上存在并存在,但如果您将磁盘拉出并检查它,则完全不存在。 /proc
为您正在运行的内核提供一个控制面板!
如果您现在查看自己的/proc
,您可能会发现很多目录,如下所示:
ls /proc
1 10 10021 10059 10144 ...hundreds more files...
这些数字中的每一个都代表一个进程 ID 或PID
是的,与识别浏览器或终端程序的进程相同的PID
。事实上,您可以询问有关流程本身的大量信息。例如,您可能还记得 Linux 系统上的进程1
传统上是顶级init
进程,在大多数现代系统中它是基于 systemd 的。让我们看看在我的系统上启动PID 1
的命令:
cat /proc/1/cmdline
/run/current-system/systemd/lib/systemd/systemd
cmdline
是一个文件,它告诉我们启动进程1
的命令——在这种情况下,是systemd
本身。
/proc
中有一个特别有用的cmdline
文件 - /proc/cmdline
,它实际上显示了在引导时传递给内核本身的参数。我的很罗嗦,但告诉我我的系统启动时使用的initrd
以及任何其他标志,在我的例子中是init
和loglevel
:
cat /proc/cmdline
initrd=\efi\nixos\hx5g5rmvq748m64r32yjmpjk3pmgqmr1-initrd-linux-5.17.11-initrd.efi init=/nix/store/9zvklk45yx41pak2hdxsxmmnq12n712k-nixos-system-diesel-22.05.20220604.d9794b0/init loglevel=4
我的 NixOS 主机名是diesel
。请注意,我不会在笔记本电脑中放石油。
/proc
也不仅仅是只读的。就像它的手册页所说, /proc
是内核的一个接口,它包括与内核本身的交互。 /proc/sys
目录包含各种旋钮和刻度盘,但我想向您展示/proc/sys/vm
,它可以让我们查看内核的虚拟内存。想要更冒险?
考虑我机器当前的内存使用情况。
free -h
total used free shared buff/cache available Mem: 31Gi 22Gi 3.0Gi 4.4Gi 5.6Gi 3.6Gi Swap: 31Gi 130Mi 31Gi
这里没有什么太不寻常的地方——但是如果我想积极地释放我的记忆怎么办?大多数时候,内核最了解使用内存进行缓存,但在某些情况下,您可能希望清除任何可以安全清除的内存——我们不想破坏任何正在运行的进程,只是如果可能,回收内存。
事实证明,有一个文件。我们通过管道将echo
命令输入sudo tee
,因为/proc/sys/vm
通常是写保护的,只有root
可以写入我们感兴趣的文件。
echo 1 | sudo tee -a /proc/sys/vm/drop_caches
该命令的作用是有效地向内核发出信号,“请删除内存中任何您可以承受的损失,而不会破坏我系统上任何正在运行的进程。”在我的机器上,这会打开大约 500M 的内存:
total used free shared buff/cache available Mem: 31Gi 22Gi 3.5Gi 4.4Gi 5.1Gi 3.6Gi Swap: 31Gi 130Mi 31Gi
凉爽的! /proc
中有各种有用的类似文件的对象,它们可以做这样有趣的事情。如果您想了解更多信息,请随意打开man proc
。
/dev
作为史前curl
/dev/sda
之类的字符设备表示附加的磁盘,但/dev
路径还有另一个用途:发送网络请求的鲜为人知的方式。
路径/dev/tcp
实际上并不是 Linux 内核公开的类似文件的设备,而是您选择的 shell 的一个特性,例如bash
。 Shell 可以拦截此路径上的操作,以便打开到远程端点的低级套接字连接,例如侦听端口80
的 Web 服务器。
首先,打开一个连接到/dev/tcp
中的文件路径的新文件描述符,该文件路径指示所需的端点和端口。就像文件描述符编号 0、1 和 2 分别表示stdin
、 stdout
和stderr
一样,您可以将这个新的文件描述符 3 视为表示到远程网络端点的管道。从这里开始,我们将假设使用bash
。
exec 3<>/dev/tcp/httpbin.org/80
接下来,将简单 HTTP 请求的明文形式发送到打开的文件描述符。这个对/status/200
的GET
请求还需要设置Host
标头,以便大多数反向代理能够正确处理。两个换行符表示请求终止:
echo -e "GET /status/200 HTTP/1.1\r\nHost: httpbin.org\r\n\r\n" >&3
最后,一个简单的读取操作检索 HTTP 响应:
cat <&3
您应该会看到类似于以下的响应:
HTTP/1.1 200 OK Date: Fri, 10 Jun 2022 21:39:43 GMT Content-Type: text/html; charset=utf-8 Content-Length: 0 Connection: keep-alive Server: gunicorn/19.9.0 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true
恭喜!您刚刚发送了一个 HTTP 请求,只使用您的 shell。
/sys
中游泳在深入了解/proc
和/dev
之后,还有一个根级目录可供探索:神秘的/sys
目录。
与/proc
和/dev
一样, /sys
是另一个与操作系统非常接近的低级机制的类似文件的接口。与/proc
- 相对专注于进程 - 和/dev
- 对块设备等建模 - /sys
是内核建模的许多抽象的有用接口。
例如,取目录/sys/class/net
。在此目录中,您将找到代表主机上网络接口的链接列表。这是我的样子:
ls /sys/class/net
enp0s20f0u6u4u1 lo tailscale0 wlan0
如您所见,我的系统管理的活动网络连接包括有线接口(以en
开头的接口)、 lo
环回接口、 Tailscale接口和我的无线接口wlan0
。列出其中一个目录的内容会显示一长串文件,但让我们更仔细地查看两个文件,特别是对于我的有线网络接口:
cat /sys/class/net/enp0s20f0u6u4u1/statistics/rx_bytes cat /sys/class/net/enp0s20f0u6u4u1/statistics/tx_bytes
11281235262 274308842
这些文件中的每一个分别代表接收的字节数和传输的字节数。如果我在几秒钟后使用相同的命令,看看数字是如何变化的:
cat /sys/class/net/enp0s20f0u6u4u1/statistics/rx_bytes cat /sys/class/net/enp0s20f0u6u4u1/statistics/tx_bytes
11289633209 274760138
更大的数字!显然我正在充分利用我的带宽。这有什么用?
你有没有想过网络使用小部件是如何编写的?那么,自己制作怎么样?
查看这个小bash
脚本,它使用上述statistics
目录中的文件来导出网络活动率。
interval=1 interface=$1 rx_bytes=$(cat /sys/class/net/$interface/statistics/rx_bytes) tx_bytes=$(cat /sys/class/net/$interface/statistics/tx_bytes) rx_bytes_rate=0 tx_bytes_rate=0 function fmt() { numfmt --to=iec-i --suffix=B $1 } while true do echo -en " $(fmt $tx_bytes_rate)/s ⬆ $(fmt $rx_bytes_rate)/s ⬇\t\r" sleep $interval old_rx_bytes=$rx_bytes old_tx_bytes=$tx_bytes rx_bytes=$(cat /sys/class/net/$interface/statistics/rx_bytes) tx_bytes=$(cat /sys/class/net/$interface/statistics/tx_bytes) tx_bytes_rate=$(( ($tx_bytes - $old_tx_bytes) / $interval )) rx_bytes_rate=$(( ($rx_bytes - $old_rx_bytes) / $interval )) done
您可以将此脚本放在$PATH
中的某个位置,使用chmod +x <script>
使其可执行,然后使用script.sh <interface name>
进行尝试。这是我机器上的输出:
13KiB/s ⬆ 379KiB/s ⬇
这很酷!您可以想象它的一些用途:例如,作为可以呈现命令输出的工具的小部件或作为查看特定网络接口的网络活动的快速方法。在任何一种情况下,基于文件的数据接口都使得访问和使用它变得异常容易。
当您进一步了解现代 Linux 系统的功能时,这只是对您可用的信息类型的一小部分了解。您可以搜索类似这样的其他指南,或者通过阅读man
man hier
等条目的手册页直接进入源代码,以便阅读/
中各种目录的功能和用途。
尽情探索吧!