首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将lsof输出格式化为可解析结构

将lsof输出格式化为可解析结构
EN

Stack Overflow用户
提问于 2017-05-29 18:57:20
回答 2查看 2.3K关注 0票数 0

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

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

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

作为字段分隔符,我从NL切换到NUL (并将null替换为"|“以提高可读性)

所以我试着

代码语言:javascript
复制
> /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字段时,它们显然已经是“空”的

代码语言:javascript
复制
> /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“的正确方法是什么?

EN

回答 2

Stack Overflow用户

发布于 2020-01-13 06:49:26

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

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

代码语言:javascript
复制
lsof -F pcuftDsin

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

  • lsof:按process
  • -F:格式获取所有打开文件的列表输出垂直方向而不是horizontal
  • p:将为PID或(进程ID)添加前缀column
  • c:将为命令添加前缀或(进程名称) column
  • u:将为进程正在运行的用户列添加前缀under
  • f:将为文件描述符添加前缀column
  • t:将为类型添加前缀column
  • D:将为设备columnH226<添加前缀文件路径:将为节点添加前缀column
  • i:将为节点添加前缀column
  • n:将为SizeOff添加前缀或(文件路径)

输出:

代码语言:javascript
复制
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项目,所以我用来解析它的代码如下所示:

代码语言:javascript
复制
    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();
        }

    }

输出

代码语言:javascript
复制
p94484,ccom.apple.CoreSimulator.CoreSim,u501,ftxt,tREG,D0x1000004,s239648,i31225967,n/private/var/db/timezone/tz/2019c.1.0/icutz/icutz44l.dat

因为我要存储输出,所以我需要空字段来显示某些内容,我使用了null,您可以使用任何内容作为默认文本,甚至只使用空字符串作为缺少的字段,而不是所有字段都将被填充。如果任何人对我如何提高代码性能有任何建议,我都会洗耳恭听。

票数 3
EN

Stack Overflow用户

发布于 2018-07-12 01:22:19

我是这样算出来的:

代码语言:javascript
复制
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个字段。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44240818

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档