Emil Vikström

Emil Vikström

Datorer och webben

Emil Vikström RSS Feed
 
 
 
 

Döda program med kommandoraden och crontab

När Bloggkoll härom dagen hade problem med att avsluta hängda processer hörde de av sig till sin favorit-GNUru. De hade tröttnat på att döda processerna manuellt hela tiden och ville kunna automatisera det. Om du vill lära dig kommandoraden i GNU/Linux (och för all del andra Unix-liknande system) så får nu även du möjlighet att studera lösningen jag gav dem.

Om du läser vidare lär du dig att bli en mästare på terminalen. Om du är mer intresserad av att lära dig just crontab så är du säkert mer intresserad av min introduktion till schemaläggning med hjälp av crontab.

Problemet

Bloggkoll är en förenklad RSS-läsare. Du som användare av Bloggkoll lägger in din favoritblogg (eller vilken sajt som helst som publicerar en RSS-ström) och hålls sedan uppdaterad om nya inlägg. Detta sker genom att Bloggkoll helt automatiskt läser in en stor mängd RSS-strömmar och tolkar ut vad som är nya inlägg, för att sedan sammanfatta detta i ett vackert grafiskt gränssnitt.

Skräphög

Tekniken går ut på att man släpper lös ett gäng program som hämtar hem och processar en webbsida var (hur deras system fungerar i detalj vet jag inte, men du fattar poängen). Tyvärr är det webben vi pratar om, och det kan finnas en hel drös olika anledningar till att en del av dessa processer låser sig, från DNS-uppslag till webbservrar som avslutar mitt i en sändning. Detta resulterar i att ett stort antal processer ligger och skräpar på Bloggkolls server utan att göra någon direkt nytta.

Hur automatiserar man avstängningen så att min vän slipper logga in på servern varje dag och slå ihjäl gamla processer en och en? Vi vet namnet på programmet som hänger sig och vi kan utgå ifrån att om vi avslutar en process mitt i så förstör vi ingenting.

Lösningen

Det här är inte ett svårt problem. Jag tänker till och med börja med att ge dig lösningen, så går vi igenom hur det fungerar sedan. Jag tänker kalla programmet för exampleprogram i exemplet, mest för att jag har så dålig fantasi. Här är kommandoraden som behövs:

ps auxw | grep exampleprogram | grep -v grep | awk '{print $2}' | xargs kill -9

Låt oss bryta ner det i sina beståndsdelar. Först och främst betyder tecknet | att resultatet från kommandot till vänster ska skickas in i kommandot till höger om tecknet. Detta skapar ett rör (engelska: pipe) av kommandon.

ps auxw

Programmet ps visar öppna program. Med flaggorna auxw visar vi alla processer som är igång på systemet och vi får även se vilket kommando som användes för att starta dem. Exempel:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      3239  0.0  0.0   2148   524 ?        Ss   Sep11   0:01 /sbin/mdadm --monitor --pid-file /var/run/mdadm/monitor.pid --daemonise --scan --syslog
daemon    3248  0.0  0.0   2048   384 ?        Ss   Sep11   0:00 php /usr/sbin/important
root      3268  0.0  0.0   5148   988 ?        Ss   Sep11   0:00 /usr/sbin/cron
user      3270  0.0  0.0   8322  1337 ?        Ss   Sep11   0:10 php /usr/local/bloggkoll/exampleprogram
root      3293  0.0  0.2   8464  4188 ?        Ss   Sep11   0:00 /usr/bin/slim -d

På näst sista raden har vi programmet vi vill döda. I verkligheten var det förstås väldigt många av detta program.

grep exampleprogram

Grep använder vi för att plocka ut endast de rader som är intressanta. I det här fallet de rader som innehåller ordet exampleprogram. Resultat:

user      3270  0.0  0.0   8322  1337 ?        Ss   Sep11   0:10 php /usr/local/bloggkoll/exampleprogram
admin    44572  0.0  0.0   1453  99   ?        Ss   Sep11   0:00 grep exampleprogram

grep -v grep

Som du såg ovan plockar grep även ut sig själv (grep-processen startas nämligen samtidigt som ps-processen). Dett råder vi bot på med hjälp av v-flaggan till grep, som betyder “plocka ut rader som inte innehåller detta ord”. Resultat:

user      3270  0.0  0.0   8322  1337 ?        Ss   Sep11   0:10 php /usr/local/bloggkoll/exampleprogram

Nu börjar det likna något! Vi har nu effektivt plockat ut alla de processer vi är intresserade av! Men hur dödar vi dem? Till att börja med måste vi ha reda på processernas PID, ett nummer som är unikt för varje process. Detta finner vi i andra kolumnen. Det är egentligen detta nummer som vi varit ute efter hela tiden.

awk ‘{print $2}’

Awk är ett mycket mångsidigt och invecklat kommando. Det är i princip ett helt skriptspråk på egen hand, med närmast oändliga möjligheter för den som vill automatisera sitt arbetsflöde med hjälp av datorn. Jag kan själv nästan ingenting om awk, men kommer få anledning att återkomma till det och lära mig mer.

Ovanstående enkla kommando plockar i alla fall ut den andra kolumnen och ger oss alltså en PID per rad:

3270

xargs

Programmet xargs är ett användbart litet program. Varje rad den får som indata (i det här fallet varje PID) lägger den på som ett eget argument på slutet av ett kommando (i mitt fall på slutet av kill -9). Om det blir för många på en gång så kör den kommandot flera gånger och skickar med några av raderna åt gången. Resultatet blir att vi kör nedanstående kommando:

kill -9 3270

kill -9

Programmet kill dödar processer, alltså stänger av program. Det kan även användas för att skicka andra signaler till programmen, som till exempel be dem att ladda om sina konfigurationsfiler eller helt enkelt starta om sig. I sitt normala utförande så är kill ett väldigt snällt och artigt program; det ber helt enkelt programmet att stänga av sig sin vanliga väg (terminate, eller signalen TERM).

Det normala förfarandet fungerar förstås inte för oss eftersom programmen har hängt sig, och därför bryr de sig inte heller om vad man säger till dem. Därför använder vi flaggan 9 som betyder döda (signalen KILL). På så sätt är processen garanterat död efteråt.

Det fattas något!

För att döda processerna automatiskt måste vi givetvis komma på ett sätt att schemalägga dödandet. Jag tänker inte gå in på detta särskilt djupt just nu, men kommer få anledning att återkomma till ämnet.

Skriv crontab -e för att öppna din bästa texteditor. Lägg detta på en egen rad:

37 1 * * * ps auxw | grep exampleprogram | grep -v grep | awk '{print $2}' | xargs kill -9

Detta gör att vi dödar exampleprogram klockan 01:37 varje natt. Då kommer vi också att döda processer som inte hängt sig, men dessa kommer att köras automatiskt igen lite senare så det gör inget om de avbryts just nu. Vill du lära dig lite mer om crontab kan du läsa min guide till schemaläggning med cron.

Alternativ lösning

Programmet killall är byggt för att stänga av processor med ett visst namn eller som har en viss fil öppen. Eftersom det finns andra PHP-skript igång som inte ska stängas av så måste vi döda på öppen fil.

killall -9 /usr/local/bloggkoll/exampleprogram

Killall är bara garanterat att fungera på Linux, och det har vissa egenskaper som gör att min lösning ovan kan vara mer flexibel. Till exempel kan ju min lösning stänga av processer som dragit en viss mängd CPU-tid.

Ett svar på “Döda program med kommandoraden och crontab”

  1. 1
    3®|k:

    Du en oneliner-wizard!

    h=’4572696B20524F58′;a=$(expr length $h);b=1;c=2;while [ $b -lt $a ];do d=$(echo $h | cut -c$b,$c);f=$(echo “ibase=16;obase=8;$d”|bc);g=$(echo “$f”);echo -ne “$g”;((b=b+2));((c=c+2));done;echo

Diskutera