如何将shell中的strace解析为纯文本?

How to parse strace in shell into plain text?

我跟踪了 strace 命令生成的日志,例如在 运行 PHP 上由:

sudo strace -e sendto -fp $(pgrep -n php) -o strace.log

输出如下:

11208 sendto(4, "set 29170397297_-cache-schema 85 0 127240\r\n72\v[=40=]?[=40=][=40=][=40=]stdClasscidschemadata\n7blockfields\fbidtype 0erialnot nullmodulevarcharlength@\tdefault\rdelta@<em>\v\f \r[=40=]10t 7<code>C@6\r\r ntatus@0int/[=15=]size 2\finyweight ;[=15=]0 region@80Pcustom0,\nvisibility0\tpages 5tex@6 1it 5[=40=]0[=16=]7y\r\ftransl!Nble %ca!a0Q[=40=]n\vprimary key[=17=]\vunique@\tstmd [=17=] 2\v\nindex 0list0[=17=] \n name [=17=]\na7_ro2[=40=]!$[=40=]\n 1[=40=]0[=40=]A4r!4@ \vunsigned@2[=40=]3[=18=]\n 3[=18=] l%!%1[=40=]%@p#$\f0l1b@nM&@Ebod1_\tB\g info .[=19=]a5[=19=]0@q!Lforma12B/!d y[=19=]*y[=40=] 5a;01'\van[=40=]_700[=40=]U =@U@2 2lob@O\n)expire@2[=40=]create1< [=21=]\n3\"7[=21=]dY[=40=] 5small0!a[=40=].0[=22=].00[=22=]00,\vb Skpo\"3s!0\t1q[=22=] ?\tno 3ort\fm\";ine_A321#0!50[=40=]U30[=23=]'ACsourc220[=23=]\v0[=23=]_C60[=23=]74_030\r[=40=]\vmultipliers[=24=]- 3\t1[=24=]B-[=24=]![=24=]03a3[=24=]05\v[=40=]05ac 7Dz\"4 [=40=] [=40=] @3\r6563\nidenti$x\nr66\vadmin_celabel\f4H hook0\r[=40=]_05\fsapiown F[=40=]62CB Himum_v 0$curr m0!2[=40=]02\"5[=40=]220N_groupa7632[=25=] 264 5C%1[=25=]P1062aQA:11 c\"$back#0b[=25=]_0!01C0[=40=]a!2\no 0#0!&}17[=26=][=26=]2e1n;< =0m[=26=]0[=40=] 2XAz\v>G?@A1\tT103[=40=] B0 string#otoolsbDC 0[=40=]D!DCLE!P[=40=]F 1TGckeditor_set%6[=40=]gE3[=40=]%Q[=40=]# 4@5!)\"w#20[=40=]![=40=] [=40=]04#\n0D \rO0\r_input_4+0V+ 0h X[=40=]!;[=40=]# 5[=40=]+ 7[=40=]Q TRcomme#/[=40=]_%6cko Wpane ;@\v[=40=]_3711F !0F3[=40=]21\"1'B[=40=]e@3A4&f`6\"~\vcollap&q%70[=40=]\t04a09[=40=][=40=]#20.[=40=]010L$7enFl4[=40=]60,[=40=]Gview0[=40=]0207 2[=40=] K[=40=]T!"..., 8196, MSG_NOSIGNAL|MSG_MORE, NULL, 0) = 8196

听起来这些都是普通的C escape codes

我试图通过 printf 在 shell 中解码它们,例如:

while read line; do printf "%s" "$line"; done < <(cat strace.log | head -n2)

但是失败了(貌似没有任何意义):

11208 sendto(4, "set 29170397297_-cache-schema 85 0 127240rn257202v0?00022710stdClass247213cid216schema214d37ata25n247215block246216fields24f213bid2425214type 037erial2110not null5216module244167217va37rchar216length6@16t5217defaultr215de2lta@<em>516v16f6 35716r210010215t 207<code>C30@6216rr n4tatus@04213int/760214size 222finy216weight243 ;022300 66region@83405P5custom27300,171623162421nvisibility340t3475pages242 20534tex@206 2611it 365052400377y10r21ftransl!N2ble %1ca!a3403Q01n31vprimary key2416016621vunique@21ts241213tmd243 31020 2vn621616217index 210101214list24524036021 3610266316256416n 164214name 70na3172_ro25205![=41=]n 3341223016340016A2142213r!354@ v222110unsigned5@3320362130n 213016 l6%16!24116%2710%@p516#16f200l241b@n24166M21016&@E4214bod201_53216t41623Bg1634 303info .07a2550200@q!L56forma201332B/!d241637 y0*y0 225a;2402012'21van0_207200251613400U =@U1163@222 2122lob@On2316)216expire@303420267217create24117< 250n2031"1770dY022 30555small240!a320.`2300.240240012402403,21vb S2kpo"3132s246!2202t212241q010...

是否有更好的方法来解析 strace 命令的输出以查看传递给 recvfrom/sendto 的纯字符串?

理想情况下,可以打印包括换行符在内的可打印字符 (\r\n),但会截断 NULL 和其他不可打印字符?

为什么read不起作用的问题,因为shell已经对字符进行了转义,所以字符串进行了双重转义,因此\r\n打印为rn.

ignore escaping of characters by shell,您可以使用 read -r,它允许反斜杠转义任何字符(因此它们按字面意思处理)。这是示例:

while read -r line; do printf "%b\n" "$line"; done < strace.log | strings

由于它是二进制数据,上面的示例还包括 strings 命令以仅显示可打印的字符串。

当指定 -x 时,Strace 还支持以十六进制打印所有字符串,但它的工作方式相同。


这里是实时解析strace输出的版本:

while read -r line;
    do printf "%b\n" "$line" | strings
done < <(sudo strace -e recvfrom,sendto -s 1000 -fp $(pgrep -n php) 2>/dev/stdout)

此外 strings,可以使用 grep 替换为更具体的过滤器,以仅获取双引号内的内容:

grep -o '".\+[^"]"' | grep -o '[^"]\+[^"]'

然而,这仍然可以打印二进制格式。

为避免这种情况,让我们简化整个过程,让我们定义以下格式化程序别名:

alias format-strace='grep --line-buffered -o '\''".\+[^"]"'\'' | grep --line-buffered -o '\''[^"]*[^"]'\'' | while read -r line; do printf "%b" $line; done | tr "\r\n" "56" | tr -d "[:cntrl:]" | tr "56" "\r\n"'

其中:

  • grep -o '".\+[^"]"' - select 带引号的双引号字符串
  • grep -o '[^"]*[^"]' - select 双引号内的文字
  • while read -r line - 将每一行存储到 $linedo 一些动作中 (help read)
  • printf "%b" $line - 通过扩展反斜杠转义序列打印行
  • tr "\r\n" "56" - 暂时将\r\n替换为56
  • tr -d "[:cntrl:]" - 删除所有控制字符
  • tr "56" "\r\n" - 恢复新行结尾

那么跟踪某些命令(例如 php)的完整示例可能如下所示:

strace -e trace=read,write,recvfrom,sendto -s 1000 -fp $(pgrep -n php) 2>&1 | format-strace

检查类似示例:How to view the output of a running process in another bash session? 在 Unix.SE