1

I have an old method of killing idle mosh-server processes, which doesn't work on my new VPS.

Here's the old method, which I run in root's crontab to clean up mosh processes that have been idle for 10+ days:

for tty in `w -sf | grep -P '\d\ddays mosh-server' | cut -c 10-15`; do kill -9 `ps -o pid= -t $tty`; done

The problem is that on the new VPS, these processes don't have TTYs, so I can't match by TTY and kill mosh that way. Here's what I've got so far (BTW, the new VPS is running kernel 3.2 on Debian wheezy, the old one was the prior Debian edition).

for loginday in `w | grep -P '\d\ddays.* mosh-server' | cut -c 34-40 | sed 's/^\([0-9]*\)\([a-zA-Z]*\).*$/\2 \1/'`; do echo $loginday; done

I'm trying to get the login day from 'w' and correlate it later with info from 'ps':

ps -C mosh-server -o bsdstart

Thus, I could correlate any idle mosh-server sessions started on the same day as login (which is probably 99.9% of them in the wild) and kill them THAT way, using 'ps' to get the pid.

However, 'w' outputs login day thusly:

03Oct13

Which I cut to simply "03Oct".

And 'ps' outputs thusly:

Oct 3

You can see in the above sed command, which is the part that isn't working, I'm trying to take in "03Oct" and output "Oct 03" (I'll deal with the zeroes when I get this working) and I cannot for the life of me get sed to work inside the for loop when it seems to work when I test it with 'echo':

echo 03Oct | sed 's/\([0-9]*\)\([a-zA-Z]*\).*/\2 \1/'

What's mangling the sed command once I paste it into the for loop?

Better yet, is there a better or less hacky way to do this? Given that detached idle mosh-server processes don't have TTYs on Linux 3.2 that I can easily associate? Edit: Also, on systems with libutempter installed, mosh-server will write information to utmp that I suspect would be useful, but I don't know how to get at it.

2 Answers 2

1

Your echo test is different from your loop test in two significant ways:

  • There's no white space around the date
  • the regex lacks anchors

Part of the reason your loop test isn't working is that you're not taking the white space into account. Another reason is that you're using the * quantifier which means "zero or more" and has the affect that you want some digits, but not really. To fix that you could use the + quantifier which means "one or more". We'll use that for the alpha characters. However, since you want to eliminate the leading zero, we can take a little different direction with the digits.

Since GNU sed supports extended regexes we can eliminate escaping all those special characters plus the ones I've added. Note, however, that the -r option is not portable. Also, I'm substituting the named character class for alphabetic characters to make the regex a little more readable and to make it compatible with languages with different character sets.

sed -r 's/^ *((0)|([1-9]))([0-9])([[:alpha:]]+).*$/\5 \3\4/'

The leading zero is being captured in group 2 and is being discarded. Group 1 is the leading digit of the two-digit number. Group 3 is empty when group 2 contains a zero (because of the alternation created using the pipe character).

As far as utmp goes, does last mosh-server output anything useful for you (with libutempter installed)?

Please also see Process Management to see if you find anything useful.

4
  • So, I'm now doing this after puzzling through it on the command line to pick apart how your solution works: for loginday in `w | grep -P '\d\ddays.* mosh-server' | cut -c 34-40 | sed -r 's/^ *((0)|([1-9]))([0-9])([a-zA-Z]+).*$/\5 \3\4/'`; do echo $loginday; done and it prints Oct and 03 on separate lines. I've never figured out how to stop that when it happens. Nov 22, 2013 at 16:05
  • last seems to search on wtmp by default on Debian; last -f /run/utmp mosh-server outputs a blank line, then the date upon which utmp starts. Nov 22, 2013 at 16:08
  • Bash tips: Always quote variables for output. You should use while read -r instead of for with pipelines. Use $() instead of backticks for readability and nestability. Your grep | cut | sed can be combined into one sed or awk. BashFAQs and other pages on that site are an essential resource. Nov 22, 2013 at 17:14
  • @GordonMorehouse: (I forgot to @ you in the previous comment) Oh, and when you use for quote its argument. for x in "$foo" Nov 22, 2013 at 17:55
1

To do something a bit more precise than parsing dates, you can look at the /proc filesystem. Something like this works for me on redhat:

⚡ for pid in $(pgrep mosh-server -u $USER); do if [[ $(stat -c %Y /proc/$pid) -lt $(( $(date +%s) - 36000 )) ]]; then echo "$pid is probably stale";fi;  done
27831 is probably stale                                                                                                                                      
38041 is probably stale                                                                                                                                      
38669 is probably stale                                                                                                                                      

⚡ ps fux | grep mosh                                                                                                                                         
1524      2444  0.4  0.0 160352  4752 ?        S    08:27   0:00 mosh-server new -c 256 -s -l LANG=en_US.UTF-8 -- bash -lc use prod                          
1524     27831  0.0  0.0 161648  6288 ?        S    Apr05   0:02 mosh-server new -c 256 -s -l LANG=en_US.UTF-8 -- bash -lc use prod                          
1524     38041  0.0  0.0 159696  4332 ?        S    Apr04   0:03 mosh-server new -c 256 -s -l LANG=en_US.UTF-8 -- bash -lc use prod                          
1524     38669  0.0  0.0 161276  5920 ?        S    Apr04   0:37 mosh-server new -c 256 -s -l LANG=en_US.UTF-8 -- bash -lc use prod 

Change the echo to a kill, and the 36000 to be whatever you want your timeout in seconds to be. If you want to do it for all users, drop the -u $USER and run it as root.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .