【问题标题】:formatting lsof output into parsable structure将 lsof 输出格式化为可解析的结构
【发布时间】:2017-05-29 10:57:19
【问题描述】:

我正在尝试以更可解析的方式格式化 lsof 输出。

背景:由于并非所有具有打开句柄的进程都有线程 ID,因此不一定确定由空格(空白 AFAIS)分隔的字段数。

作为输出字段,我需要 PID、UID/用户名和路径(如果它是一个文件 - 我正在寻找路径,因为 +D 非常慢)。

作为字段分隔符,我从 NL 切换到 NUL(为了便于阅读,将 null 替换为“|”)

所以我尝试了

> /usr/sbin/lsof -F pnuf0 | sed 's/\x0/|/g' | grep "cvmfs" | tail -n 2
 ftxt|n/usr/bin/cvmfs2|
 fmem|n/usr/lib64/libcvmfs_fuse.so.2.3.5|

它只产生文件描述符和名称(不是按照给定的顺序?)但不产生 PID 或 UID?

作为旁注,PID 和 UID 字段在单独选择时显然已经“空”

> /usr/sbin/lsof -F u0 | sed 's/\x0/|/g' | grep "cvmfs" | tail -n 2
> /usr/sbin/lsof -F p0 | sed 's/\x0/|/g' | grep "cvmfs" | tail -n 2
> /usr/sbin/lsof -F n0 | sed 's/\x0/|/g' | grep "cvmfs" | tail -n 2
  n/usr/bin/cvmfs2|
  n/usr/lib64/libcvmfs_fuse.so.2.3.5|

将 lsof 的输出解析为 "PD,NAME,UID,FILEDESC" 的正确方法是什么?

【问题讨论】:

    标签: formatting lsof


    【解决方案1】:

    由于我从来没有在网上找到一个好的答案,所以我花了很多时间来解决这个问题。我希望我能减轻别人的痛苦。 lsof 本身会打印出缺少值的水平输出,因此无法正确解析

    要格式化lsof,需要使用命令:

    lsof -F pcuftDsin
    

    添加-F会垂直打印结果,让我解释每个部分。

    • lsof: 按进程获取所有打开文件的列表
    • -F:格式化输出垂直而不是水平
    • p:将在 PID 或(进程 ID)列前添加前缀
    • c: 将作为 COMMAND 或(进程名称)列的前缀
    • u: 将作为进程运行所在的用户列的前缀
    • f: 将作为文件描述符列的前缀
    • t: 为类型列添加前缀
    • D: 将作为设备列的前缀
    • s: 将为 SizeOff 列添加前缀
    • i: 会在 Node 列前加前缀
    • n: 将前缀名称或(文件路径)

    输出:

    p3026
    ccom.apple.appkit.xpc.openAndSavePanelService
    u501
    fcwd
    tDIR
    D0x1000004
    s704
    i2
    n/
    ftxt
    tREG
    D0x1000004
    s94592
    i1152921500312434319
    n/System/Library/Frameworks/AppKit.framework/Versions/C/XPCServices/com.apple.appkit.xpc.openAndSavePanelService.xpc/Contents/MacOS/com.apple.appkit.xpc.openAndSavePanelService
    ftxt
    tREG
    D0x1000004
    s27876
    i45156619
    n/Library/Preferences/Logging/.plist-cache.usI0gbvW
    ftxt
    tREG
    D0x1000004
    s28515184
    i1152921500312399135
    n/usr/share/icu/icudt64l.dat
    ftxt
    tREG
    D0x1000004
    s239648
    i31225967
    n/private/var/db/timezone/tz/2019c.1.0/icutz/icutz44l.dat
    ftxt
    tREG
    D0x1000004
    s3695464
    i1152921500312406201
    n/System/Library/CoreServices/SystemAppearance.bundle/Contents/Resources/SystemAppearance.car
    ftxt
    tREG
    D0x1000004
    s136100
    i38828241
    n/System/Library/Caches/com.apple.IntlDataCache.le.kbdx
    

    如您所见,每一行都以上面分配的正确字母作为前缀。另一个需要注意的重要事情是,“进程 ID”、“进程名称”和用户将只打印一次每组打开的文件,对于数据库存储,我需要这些字段用于打印的每一行。我正在执行一个java项目,所以我用来解析它的代码如下所示:

        public static void main(String[] args) {
    
            String command = "lsof -F pcuftDsin";
            String captureBody = "";
            Process proc = null;
            try {
                proc = Runtime.getRuntime().exec(command);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line = "";
    
            String ProcessID = "";
            String ProcessName = "";
            String User = "";
            String FD = "null";
            String Type = "null";
            String Device = "null";
            String SizeOff = "null";
            String Node = "null";
            String File = "null";
    
            while(true) {
                try {
                    line = reader.readLine();
                    if (line == null) {
                        break;
                    } else {
                        if (line.startsWith("p")) {
                            ProcessID = line;
                        }  else if (line.startsWith("c")) {
                            ProcessName = line;
                        } else if (line.startsWith("u")) {
                            User = line;
                        } else if (line.startsWith("f")) {
                            FD = line;
                        } else if (line.startsWith("t")) {
                            Type = line;
                        } else if (line.startsWith("D")) {
                            Device = line;
                        } else if (line.startsWith("s")) {
                            SizeOff = line;
                        } else if (line.startsWith("i")) {
                            Node = line;
                        } else if (line.startsWith("n")){
                            File = line;
    
                            System.out.println(ProcessID  + "," + ProcessName + "," + User + "," + FD + "," + Type  + "," + Device  + "," + SizeOff  + "," + Node  + "," + File);
    
                            FD = "null";
                            Type = "null";
                            Device = "null";
                            SizeOff = "null";
                            Node = "null";
                            File = "null";
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                proc.waitFor();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    

    输出

    p94484,ccom.apple.CoreSimulator.CoreSim,u501,ftxt,tREG,D0x1000004,s239648,i31225967,n/private/var/db/timezone/tz/2019c.1.0/icutz/icutz44l.dat
    

    因为我正在存储输出,所以我需要空字段来显示某些内容,我使用了 null,您可以使用任何内容作为默认文本,或者甚至只是为缺少的字段使用空字符串,并非所有字段都会被填充。如果有人对我如何提高代码性能有任何建议,我会全力以赴。

    【讨论】:

      【解决方案2】:

      寻找相同的东西发现即使我指定 -F 0 它也会将结果分成几行,这使得 lsof 几乎无法使用 -F 选项:

      # lsof -F pnuf0 /tmp/aaa | tr '\0' '|' p19677|u1000| f4|n/tmp/aaa|

      该死的。 我已经结束使用 find 或简单地 grepping stat -c"%u %N" /proc/[0-9]/fd/

      【讨论】:

        【解决方案3】:

        我是这样解决的:

        lsof |awk ' { if ( NF == 12) { x=$10; y=$4 } else if ( NF == 11 && $11 != "(deleted)" ) { x=$10; y=$4 } else { x=$9; y=$3}; print $2,y, x }'
        

        如果有 TID 并且文件被删除,则字段数将为 12。 如果没有 TID 并且文件被删除,则字段数将为 11。 最后,如果没有 TID 并且文件没有被删除,那么将有 10 个字段。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-07-05
          • 1970-01-01
          • 2012-10-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多