我正在尝试 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
,则顶部根本不显示任何内容,即使有正在运行sshd
和sleep
进程也是如此。显然,这种创建过滤器的方法会产生一种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 结构实现o
orO
命令,其中sel = strcasestr
orsel = 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()
。