暗无天日

=============>DarkSun的个人博客

实现shell版的pv

https://blogs.oracle.com/linux/solving-problems-with-proc-v2 上看到的。

pv 能够显示数据处理的进度,非常神奇。而借助 /proc/$pid/fdinfo/$fd 我们能够用 shell 实现类似的功能。

我们都知道在 /proc/$pid/fd/ 中可以察看各个进程打开的文件描述符实际指向的文件, 而今天我才知道,原来在 /proc/$pid/fdinfo/ 目录下我们还能查看各个文件描述符的状态信息

for fdinfo in /proc/$(pgrep emacs)/fdinfo/*
do
    echo ---------------${fdinfo}----------------
    cat ${fdinfo}
done |head -n 20
---------------/proc/1301/fdinfo/0----------------
pos:    0
flags:  0100000
mnt_id: 23
---------------/proc/1301/fdinfo/1----------------
pos:    0
flags:  02
mnt_id: 9
---------------/proc/1301/fdinfo/10----------------
pos:    184
flags:  0100001
mnt_id: 26
---------------/proc/1301/fdinfo/11----------------
pos:    0
flags:  0100002
mnt_id: 26
lock:   1: POSIX  ADVISORY  WRITE 1301 00:17:2899622 0 EOF
---------------/proc/1301/fdinfo/12----------------
pos:    0
flags:  0100001

这些信息的意义可以通过 man 5 proc 来获得,其中 pos 表示的是文件的偏移位置。 因此我们可以实现一个简陋的pv

#!/usr/bin/env bash
file="$1"
cat <"${file}" &                # 文件内容输出到stdout,这样方便通过管道传递出去.
pid=$!
fd=/proc/${pid}/fd/0
fdinfo=/proc/${pid}/fdinfo/0
size=$(stat --format=%s "${file}") # 获取文件的总大小
while [ -e ${fd} ]; do
    progress=$(cat ${fdinfo} | grep ^pos | awk '{print $2}') # 获取偏移量
    echo $((100*${progress} / ${size}))                      # 计算百分比
    sleep 0.1
done | dialog --gauge "Progress reading ${file}" 7 100 >&2 # 进度条输出到stdout

效果如下图所示:

shell_pv.gif