我试图以更易解析的方式格式化lsof输出。
背景:由于并非所有具有开放句柄的进程都具有线程ID,因此不一定确定由空格分隔的字段数(空白AFAIS)。
作为输出字段,我需要PID,UID /用户名和路径(如果它是一个文件 - 由于+ D非常慢,我正在寻找路径。)
作为字段分隔符,我从NL切换到NUL(并用&#34替换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" ?
答案 0 :(得分:3)
由于我从未在网上找到对此的好答案,因此我花了很多时间来解决这个问题。我希望我可以减轻别人的痛苦。 lsof本身将打印出缺少值的水平输出,从而无法正确解析
要格式化lsof,您需要使用以下命令:lsof -F pcuftDsin,添加-F将垂直打印结果,让我解释一下每个部分。
输出:
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,可以将任何内容用作默认文本,甚至可以对缺少的字段使用空字符串,并非所有字段都会被填充。如果有人对我如何提高代码性能有任何建议,我会耳熟能详。
答案 1 :(得分:0)
寻找同样的事情发现,即使我指定-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 /
答案 2 :(得分:0)
我是这样解决的:
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个字段。