通过 COMMAND=abc 或 COMMAND=xyz 过滤 top(1) 显示

通过 COMMAND=abc 或 COMMAND=xyz 过滤 top(1) 显示

我正在尝试 top(1) 程序,并且试图弄清楚如何仅显示指定的程序名称。例如,如果我调用像这样的命令行

$ ssh localhost sleep 15

我希望能够过滤 top 的显示以仅显示程序名称为sshd和 的进程sleep

当 top 运行时,如果我按“O”(大写 oh == 区分大小写的过滤器)并添加一个过滤器COMMAND=sshd,那么我会看到我所期望的:top 仅显示那些程序名称以 开头的进程sshd。如果我删除该过滤器(按“=”)并创建一个新过滤器COMMAND=sleep,我会看到程序以 开头的进程sleep

但是,如果我创建两个过滤器,其中过滤器 1 为COMMAND=sshd,过滤器 2 为COMMAND=sleep,则顶部根本不显示任何内容,即使有正在运行sshdsleep进程也是如此。显然,这种创建过滤器的方法会产生一种AND关系: show if COMMAND=sshd&& COMMAND=sleep

那么如何创建一个产生所需 OR 关系的过滤器(或过滤器集):show if COMMAND=sshd|| COMMAND=sleep

答案1

通过开源,您可以查看代码,看看是否可以轻松地完成您想要的操作。在我旧的基于 rpm 的 Fedora 上,我可以轻松下载并解压源代码

$ rpm -qf /usr/bin/top
procps-ng-3.3.10-11.fc24.x86_64
$ dnf download --source procps-ng
$ rpm -i procps-ng-3.3.10-11.fc24.src.rpm 
$ rpmbuild -bp ~/rpmbuild/SPECS/procps-ng.spec --nodeps
$ cd ~/rpmbuild/BUILD/procps-ng-3.3.10/

代码在top/top.c.寻找这个词筛选最终表明该函数other_selection()正在使用一个小的 C 结构实现oorO命令,其中sel = strcasestrorsel = strstr被设置为输入,例如COMMAND=somestring。您可以看到GitLab此版本的代码。从那时起它已经发生了变化,但很相似。

一种实现方法或者两个字符串之间看起来有点困难,但一个简单的替代方案似乎接受正则表达式,而不仅仅是进行字符串比较。然后,您可以将赋值更改为sel = myfunction并编写一个函数,该函数接受 2 个字符串并执行 aregexec()而不是strstr()

如果您不想下载和编译程序,可以编写一个小垫片在 C 库前面加载,用strstr()您自己的函数覆盖该函数。然而,我发现这个函数在其他地方被使用了top,所以我更喜欢重写strcasestr(),它似乎只用于o命令。创建一个shim_strcasestr.c包含以下内容的文件:

/* capture calls to a routine and replace with your code
 * https://unix.stackexchange.com/a/463461/119298
 * gcc -Wall -O2 -fpic -shared -ldl -o shim_strcasestr.so shim_strcasestr.c */
#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <regex.h>
#define NUMMATCH 1 /* max num matching capture groups in pattern */
char *strcasestr(const char *haystack, const char *needle){
    static char *(*real_strcasestr)(const char *haystack, const char *needle) = NULL;
    regex_t myexpn;
    regmatch_t matches[NUMMATCH] = {0};
    if (!real_strcasestr) {
        real_strcasestr = dlsym(RTLD_NEXT, "strcasestr");
        char *error = dlerror();
        if (error != NULL) {
            fprintf(stderr, "%s\n", error);
            exit(1);
        }
    }
    if(needle[0]!='/') return real_strcasestr(haystack,needle);
    int rc = regcomp(&myexpn, needle+1, REG_EXTENDED);
    if(rc!=0)return NULL;
    rc = regexec(&myexpn, haystack, NUMMATCH, matches, 0);
    regfree(&myexpn);
    if(rc==REG_NOMATCH)return NULL;
    return (char*)haystack;
}

并按照评论中所示进行编译。然后,您可以运行它LD_PRELOAD=./shim_strcstr.so /usr/bin/top,当您键入该o键时,您可以输入,例如,COMMAND=/sshd|sleep并获得所需的结果。我添加了对/字符串中首字母缩写的检查,因此如果省略它,您仍然可以获得原始的任意大小写匹配。显然,可以优化这段代码来缓存结果regcomp()

相关内容