我想监视一个不断更改特定行的文件。具体来说,我正在监视/ proc / [PID] / smaps中的进程内存使用情况。
现在,我检查了smaps:
fp = popen("/bin/cat /proc/19596/smaps | grep stack --after-context=1", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit;
}
/* Read the output a line at a time - output it. */
while(1){
while (fgets(path, sizeof(path)-1, fp) != NULL) {
printf("%s", path);
}
}
/* close */
pclose(fp);
但这不是更新。如何在文件打开时保持打印出来的文件?我是否需要每次都关闭文件或更快的方式?
答案 0 :(得分:1)
/proc/
是由伪文件组成的Linux特定文件系统,您应该按顺序访问它们。见proc(5)。
因此在实践中,您需要重新打开/proc/19596/smaps
文件。阅读它非常快,不涉及任何磁盘I / O!它与从pipe(7)读取的速度一样快。
使用popen
(无用地使用cat
)是错误的。您应该更好地打开(使用fopen(3))/proc/19596/smaps
文件,循环读取每一行(例如使用fgets(3)),比较它(使用例如strstr(3))和{{1文字字符串,然后读取下一行,最后是"stack"
。
答案 1 :(得分:0)
老实说,我不明白你为什么要在C中这样做。
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <unistd.h>
enum { ERR = -1 };
static int s_running = 1;
static void sigintHandler(int s) {
(void)s;
s_running = 0;
}
int main(int argc, char *argv[]) {
int pid = -1, sleepMsec = 1000;
char optchr, buf[260];
FILE *fp;
signal(SIGINT, sigintHandler);
while (ERR != (optchr = getopt(argc, argv, "p:s:"))) {
switch (optchr) {
case 'p': pid = strtol(optarg, NULL, 0); break;
case 's': sleepMsec = strtol(optarg, NULL, 0); break;
default:
fprintf(stderr, "USAGE: smap -p pid [-s msec]\n");
return -10;
}
}
snprintf(buf, sizeof buf, "/proc/%d/smaps", pid);
buf[sizeof buf - 1] = '\0';
fp = fopen(buf, "r");
if (NULL == fp) {
char buf1[sizeof buf];
snprintf(buf1, sizeof buf1, "fopen for [%s]", buf);
buf1[sizeof buf1 - 1] = '\0';
perror(buf1);
return -20;
}
for (;;) {
if (ERR == fseek(fp, 0, SEEK_SET)) {
perror("fseek(3)");
return -30;
}
while (fgets(buf, sizeof buf, fp)) {
if (strstr(buf, "stack")) {
printf("%s", buf);
if ( ! fgets(buf, sizeof buf, fp)) {
fprintf(stderr, "fgets(3) found EOF\n");
return -40;
}
printf("%s", buf);
}
}
usleep(1000 * sleepMsec);
if ( ! s_running)
break;
}
printf("Bye!\n");
return 0;
}
我建议您使用Python等脚本语言来完成此类任务。
#! /usr/bin/env python
from __future__ import print_function
import time
import sys
import getopt
def main(args):
pid = -1
sleepMsec = 1000
opts, _ = getopt.getopt(args, "p:s:")
for (k,a) in opts:
if "-p" == k:
pid = int(a)
elif "-s" == k:
sleepMsec = int(a)
try:
with open("/proc/{}/smaps".format(pid)) as fp:
while True:
fp.seek(0)
while True:
line = fp.readline()
if not line:
break
if 0 <= line.find("stack0"):
print(line, fp.readline(), sep='', end='')
break
time.sleep(1e-3 * sleepMsec)
except KeyboardInterrupt:
print("Bye!")
if "__main__" == __name__:
main(sys.argv[1: ])
Bash和标准Linux命令的组合也是一种选择。事实上,您已经使用grep作为初始版本。
请注意,您不能对管道使用fseek(3)
(严格意义上说它是一个流),但/proc/PID/smaps
伪文件系统支持它。
答案 2 :(得分:0)
不确定这是否与/proc
中的文件最佳匹配,但您可以使用Linux的inotify
系统让内核通知您已观看文件的更改,以便您不必轮询。
您可以使用C访问系统,但是使用inotifywait
工具在shell中尝试它应该是一个很好的起点(以下应该比您的问题中的C代码更有效)。
pid=19596
file=/proc/$pid/smaps
cmd="grep stack --after-context=1"
while intofitywait -e modify "$file"; do $cmd "$file"; done