2011-09-14

constructing process tree from the ps -ef result

#! /usr/bin/awk -f

# Usage:
# ps -ef | ./proctree.awk
# ps -f > proclist.txt; ./proctree.awk proclist.txt

BEGIN { pid_col = 2; ppid_col = 3 }

# find the field number for PID and PPID column
/PID +PPID/ {
for (i=1; i < NF; i++) {
if ($i == "PID") {
pid_col = i ; ppid_col = i + 1
print; break
}
}
next
}

{
processes[$pid_col] = $0
children[$ppid_col] = children[$ppid_col] "," $pid_col
if ($ppid_col == 0 || $ppid_col == 1) child_of_swapper_init = child_of_swapper_init "," $pid_col
}

END {
if (0 in processes) {
print processes[0]
split(substr(children[0], 2), child_of_swapper, ",")
for (pid in child_of_swapper) {
if (pid != 1) print processes[pid]
}
}

if (1 in processes) {
print_tree(1, 0)
} else {
## find the top processes.
for (pid in children) {
if (pid in processes) continue
origins = origins "," pid
}

split(substr(origins, 2), top_procs, ",")
for (pid in top_procs) {
print_tree(top_procs[pid], 0)
}
}
}

function print_tree(pid, depth, myfmt, mypid, mychld)
{
if (index(child_of_swapper_init, pid)) depth = 0

if (depth == 0) {
if (pid in processes) {
print processes[pid]
} else {
depth = -1
}
} else {
myfmt = sprintf("%%%is%%s", 3 * depth)
printf(myfmt "\n", " ", processes[pid])
}

split(substr(children[pid], 2), mychld, ",")
for (mypid in mychld) {
print_tree(mychld[mypid], depth + 1)
}
}

#__end__

2011-09-05

How to generate cyclic numbers in ksh

Sometimes, I need to generate limited number of temporary files in loop like below.

while :
do
ps -elf > /tmp/ps.log.$cyclic_number_here
done


Generating cyclic number is an easy job. For example, next function does that.

#! /usr/bin/ksh
GEN_CYCLIC_CALL_COUNT=1
gen_cyclic_number()
{
typeset -i max=$1 mod

((max < 1)) && print 0 && return

((mod = GEN_CYCLIC_CALL_COUNT % max))
if ((mod == 0)); then
((GEN_CYCLIC_CALL_COUNT = max + 1))
print -- $max
else
((GEN_CYCLIC_CALL_COUNT += 1))
print -- $mod
fi
}
But this function will not output the correct numbers when used in command subsititution because it's executed in a subshell.

Correct and easier way is to use proper arithmetic expressions as arithmetic expansion is done in the shell, not in a subshell.

typeset -i i=-1
while :
do
ps -elf > /tmp/ps.log.$((i = (i += 1) % 3)) # generates ps.log.0, ps.log.1, ps.log.2
done


What you need is just 0 and 1, even simpler solution is here.
typeset -i i=1
while :
do
ps -elf > /tmp/ps.log.$((i ^= 1))
done