从 proc/pid/cmdline 解析命令行参数

Posted

技术标签:

【中文标题】从 proc/pid/cmdline 解析命令行参数【英文标题】:parsing command-line arguments from proc/pid/cmdline 【发布时间】:2014-06-09 19:23:17 【问题描述】:

我正在尝试使用system() 命令和模拟器的pid 在我的程序中解析另一个程序(这是一个模拟器)的命令行参数。不幸的是,同时使用文件读取和cat,输出格式不正确,所以我无法真正获取数据。命令行上的cat 显示删除了空格的文件内容,整个字符串粘在一起,使用ifstream,它只显示程序的名称(我猜是第一个参数)。有人有什么想法吗?

参数的格式是这样的:

sudo ./src/yse6 -w -f tracefiles/capacity.3Mbps_400RTT_PER_0.0001.txt -at=eth1 -an=eth0

最终我需要显示与上述格式相同的字符串。

这是我到目前为止所做的:(ExecCommand() 获取一个命令,在命令行中运行它并将结果返回为stringSecondary() 尝试使用文件阅读器获取文件内容。)

std::string ExeCommand(const char* cmd) 
    FILE* pipe = popen(cmd, "r");
    if (!pipe) return "ERROR";
    char buffer[128];
    std::string result = "";
    while(!feof(pipe)) 
        if(fgets(buffer, 128, pipe) != NULL)
            result += buffer;
    
    pclose(pipe);
    return result;


void secondary(string addr)

        ifstream file(addr.c_str(),ios::in);
        if (file.good())
        
            string str;
            while(getline(file, str))
            
                istringstream ss(str);
                cout<<str<<endl;
                char num[50];
                while(ss >> num)
                
                    cout<<num;
                
            
        else
            cout<<"no file exists."<<endl;
        


int main (int argc, char* argv[])

    if ((string) argv[1] == "-q") 
        string pid=ExeCommand("ps -A | grep 'yse6' | awk 'print $1'");
        if(pid=="")
            cout<<"No YSE emulator is running."<<endl;
        else
            pid=pid.substr(0,pid.size()-1);
            cout<<pid<<endl;
            string addr="cat /usr/bin/strings /proc/"+pid+"/cmdline";

            cout<<addr<<endl;
//          secondary(addr);

            const char * c = addr.c_str();
            string config=ExeCommand(c);
            //get the config
            cout << config<<endl;
        //end of else
    

【问题讨论】:

该文件的内容是 NULL 分隔的,而不是空格分隔的... 是的,我知道。我猜我应该只玩文件阅读器选项,对吧? 将文件的全部内容读入缓冲区(PAGESIZE 字节应该足够了),然后扫描读取的数据为零字节。除了最后一个(你可以告诉你,因为read() 告诉你它实际读取了多少字节),每个零字节之后的字节是下一个字符串的开头...... 我明白了。感谢您提供的有用信息。我对 C++ 函数不太熟悉,最好能帮我写代码。 【参考方案1】:

类似这样的东西,但有更多的错误检查,应该是一个好的开始(这比 C++ 更多,除了 cout 位):

const int BUFSIZE = 4096; // should really get PAGESIZE or something instead...
unsigned char buffer[BUFSIZE]; // dynamic allocation rather than stack/global would be better

int fd = open("/proc/self/cmdline", O_RDONLY);
int nbytesread = read(fd, buffer, BUFSIZE);
unsigned char *end = buffer + nbytesread;
for (unsigned char *p = buffer; p < end; /**/)
 cout << p << endl;
  while (*p++); // skip until start of next 0-terminated section

close(fd);

特别是,open()read() 应该检查错误情况,但我没有展示那部分......这也可能在命令行长度超过 4096 个字符的极端情况下失败,或者如果由于某些其他原因,read() 不会在一次调用中读取文件,这在当前的/proc 实现中不应该发生,但并不总是保证......

【讨论】:

很公平。我应该为此包含什么库?我猜stdio.h 已经存在了。但是对于 int fd = open(addr, O_RDONLY); 它说:‘O_RDONLY’ was not declared in this scope‘open’ was not declared in this scope 一般来说,man foo 会告诉您#include 需要哪些标头才能使用foo()... 对于open(),在我当前的Linux 系统上,这意味着&lt;sys/types.h&gt;&lt;sys/stat.h&gt;&lt;fcntl.h&gt;。在其他系统上可能会有所不同,C++ 头文件也有些不同...【参考方案2】:

一个简单的解决方法是读取字节,然后迭代以删除以空格结尾的空字符。这是一个基于 C 的实现。但尚未检查错误条件。

char *name = (char *)malloc(MAX_SIZE);
char procfile[MAX_SIZE];
sprintf(procfile, "/proc/%d/cmdline", pid);
int fd = open(procfile, O_RDONLY);
int size = read(fd,name,sizeof(procfile));
close(fd);
for(int i = 0 ; i < size; i++)
 if(!name[i]) name[i] = ' ';

【讨论】:

以上是关于从 proc/pid/cmdline 解析命令行参数的主要内容,如果未能解决你的问题,请参考以下文章

获取有关PID的信息

隐藏与篡改Linux命令行参数

Android:如何在 C 语言中更改进程名称?

从正在运行的 nginx 进程中转储 conf

Python 中最好用的命令行参数解析工具

区别PHP引用传递与值传递的小例子