devinteske

Optimizing awk filters

May 16th, 2018
448
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.51 KB | None | 0 0
  1. https://www.commandlinefu.com/commands/view/22588/kill-all-zombie-processes-one-liner
  2.  
  3. The above link suggests the following recipe for cleaning up zombie processes:
  4.  
  5. ps axo state,ppid | awk '!/PPID/$1~"Z"{print $2}' | xargs -r kill -9
  6.  
  7. This is functionally inefficient because awk is instructed to test each/every line for "PPID" when only the first line matches this criterion.
  8.  
  9. Here is some sample output:
  10.  
  11. $ ps axo state,ppid
  12. STAT PPID
  13. SsJ 1
  14. SsJ 1
  15. IsJ 1
  16. SsJ 1
  17. IsJ 1
  18. SsJ 1
  19. IJ 2140
  20. IsJ 2145
  21. SJ 43653
  22. IJ 2140
  23. IJ 2140
  24. SJ 2140
  25. IJ 2140
  26. IJ 2140
  27. IJ 2140
  28. IJ 2140
  29. IJ 2140
  30. IJ 2140
  31. SsJ 43655
  32. TJ 43656
  33. SZJ 1
  34. R+J 43656
  35.  
  36. There's no reason to test every line for PPID when you can either:
  37.  
  38. 1. Instruct ps to not print the header.
  39.  
  40. The "-o field1[,field2,...]" option of ps supports alternative syntax "-o field1=field1_header [-o field2=field2_header ...]". Thus, the following incantation tells ps to not print the header:
  41.  
  42. $ ps ax -o state= -o ppid=
  43. SsJ 1
  44. SsJ 1
  45. IsJ 1
  46. SsJ 1
  47. IsJ 1
  48. SsJ 1
  49. IJ 2140
  50. IsJ 2145
  51. SJ 43653
  52. IJ 2140
  53. IJ 2140
  54. SJ 2140
  55. IJ 2140
  56. IJ 2140
  57. IJ 2140
  58. IJ 2140
  59. IJ 2140
  60. IJ 2140
  61. SsJ 43655
  62. TJ 43656
  63. SZJ 1
  64. R+J 43656
  65.  
  66. But this can be shortened using shell brace-expansion features:
  67.  
  68. $ ps ax -o{state,ppid}=
  69.  
  70.  
  71. We can shorten this by one more letter, because the "state" field in ps can also be addressed as "stat":
  72.  
  73. $ ps ax -o{stat,ppid}=
  74. SsJ 1
  75. SsJ 1
  76. IsJ 1
  77. SsJ 1
  78. IsJ 1
  79. SsJ 1
  80. IJ 2140
  81. IsJ 2145
  82. SJ 43653
  83. IJ 2140
  84. IJ 2140
  85. SJ 2140
  86. IJ 2140
  87. IJ 2140
  88. IJ 2140
  89. IJ 2140
  90. IJ 2140
  91. IJ 2140
  92. SsJ 43655
  93. TJ 43656
  94. SZJ 1
  95. R+J 43656
  96.  
  97. Since there is no more header produced from ps, you can shorten the awk from this:
  98.  
  99. awk '!/PPID/$1~"Z"{print $2}'
  100.  
  101. to this:
  102.  
  103. awk '$1~"Z"{print $2}'
  104.  
  105. Transforming the initial command to:
  106.  
  107. $ ps ax -o{stat,ppid}= | awk '$1~"Z"{print $2}' | xargs -r kill -9
  108.  
  109. NOTE: Avoide the temptation to do "ps axo stat=,ppid=" because on some Operating Systems this tells ps that you want the field "stat" with a header of ",ppid=" (you won't get the ppid field).
  110.  
  111. 2. The other technique is to let ps produce the header but have awk eat it immediately before processing the remainder of the lines on stdin.
  112.  
  113. awk's "getline" built-in will read a line from stdin and set $0, NF, and $num (where num is a number from 1 to NF). Simply doing the following is enough to get awk to eat the header so that the remainder of the lines can be processed without the unnecessary check for "PPID" (to skip the header).
  114.  
  115. $ ps axo stat,ppid | awk 'BEGIN{getline}$1~"Z"{print $2}' | xargs -r kill -9
  116.  
  117. ===
  118.  
  119. Now, given the two potential options:
  120.  
  121. $ ps ax -o{stat,ppid}= | awk '$1~"Z"{print $2}' | xargs -r kill -9
  122. or
  123. $ ps axo stat,ppid | awk 'BEGIN{getline}$1~"Z"{print $2}' | xargs -r kill -9
  124.  
  125. Compared to the original:
  126.  
  127. $ ps axo state,ppid | awk '!/PPID/$1~"Z"{print $2}' | xargs -r kill -9
  128.  
  129. Any/all of these can be optimized slightly further.
  130.  
  131. The output of ps is such that the second column will only-ever be numeric and thus the only column that could potentially carry a "Z" (what we're looking for to find zombied processes), there is no need to test $1 specifically.
  132.  
  133. That is to say the above test:
  134.  
  135. $ ps ax -o{stat,ppid}= | awk '$1~"Z"{print $2}' | xargs -r kill -9
  136.  
  137. Can be rewritten as:
  138.  
  139. $ ps ax -o{stat,ppid}= | awk '/Z/{print $2}' | xargs -r kill -9
Add Comment
Please, Sign In to add comment