Hantera processer i förgrunden och bakgrunden med Bash-skalet i Linux. Genom att utnyttja Bashs funktioner för jobbkontroll och signaler, kan du få större flexibilitet i hur du kör dina kommandon. Här visar vi dig hur det fungerar.
Processernas värld
Varje gång ett program startas i ett Linux- eller Unix-liknande system, initieras en process. En ”process” är den interna representationen av ett aktivt program i datorns minne. Det finns en separat process för varje program som körs. Faktum är att nästan allt som pågår på din dator representeras av en process. Detta inkluderar komponenter i din grafiska skrivbordsmiljö (GDE), som GNOME eller KDE, och systemdemoner som aktiveras vid uppstart.
Varför inte *allt* som körs? Jo, inbyggda Bash-kommandon som cd, pwd, och alias behöver inte skapa en separat process när de används. Bash utför dessa kommandon direkt inom den instans av Bash-skalet som körs i ditt terminalfönster. Dessa kommandon är snabba eftersom de inte kräver att en ny process startas. (Du kan skriva `help` i en terminal för att se en lista över inbyggda Bash-program.)
Processer kan antingen köras i förgrunden, vilket innebär att de tar kontroll över terminalen tills de är klara, eller i bakgrunden. Bakgrundsprocesser tar inte upp terminalfönstret och du kan fortsätta arbeta i det, åtminstone så länge de inte genererar utdata på skärmen.
Ett praktiskt exempel
Låt oss börja med en enkel ping-test mot domänen howtogeek.com. Detta utförs först som en förgrundsprocess.
ping www.howtogeek.com
De förväntade resultaten visas i terminalfönstret. Under tiden ping körs, kan vi inte använda terminalen till något annat. För att stoppa kommandot trycker vi på Ctrl+C.
Ctrl+C
Effekten av Ctrl+C visas i skärmdumpen. Ping sammanfattar och avslutas.
Låt oss prova igen, men den här gången trycker vi Ctrl+Z istället för Ctrl+C. Kommandot avslutas inte, utan hamnar istället i bakgrunden. Vi får tillbaka kontrollen över terminalen.
ping www.howtogeek.com
Ctrl+Z
Effekten av Ctrl+Z visas i skärmdumpen.
Vi får nu beskedet att processen har stoppats. Stoppad betyder inte avslutad. Det är som en bil vid en stoppskylt, den är fortfarande där och väntar på att fortsätta. Processen är nu ett bakgrundsjobb.
Kommandot jobs visar en lista över jobben som har startats i den aktuella terminalsessionen. Eftersom jobb är processer, kan vi även använda kommandot `ps` för att se dem. Låt oss använda båda och jämföra resultatet. Vi använder alternativet `-T` (terminal) för att endast visa processer som körs i det aktuella terminalfönstret. Observera att det inte finns något behov av att använda ett bindestreck med alternativet `-T`.
jobs
ps T
Kommandot `jobs` ger oss följande information:
[1]: Siffran inom hakparentes är jobbnumret, som vi kan använda för att referera till jobbet när vi vill kontrollera det med jobbkontrollkommandon.
+: Plustecknet `+` visar att detta är det jobb som kommer att påverkas om vi använder ett jobbkontrollkommando utan att specificera ett jobbnummer. Det är standardjobbet och alltid det senast tillagda jobbet.
Stoppad: Processen körs inte.
`ping www.howtogeek.com`: Kommandot som startade processen.
Kommandot `ps` ger oss denna information:
PID: Processens process-ID, unikt för varje process.
TTY: Den pseudo-teletyp (terminalfönster) där processen startades.
STAT: Processens status.
TIME: Mängden CPU-tid som processen har använt.
COMMAND: Kommandot som startade processen.
Vanliga värden för STAT-kolumnen:
D: Oavbruten sömn. Processen väntar på inmatning eller utmatning och kan inte avbrytas.
I: Inaktiv.
R: Körs.
S: Avbrytbar sömn.
T: Stoppad av en jobbkontrollsignal.
Z: En zombieprocess. Processen har avslutats, men har inte ”städats upp” av sin överordnade process.
Värdet i STAT-kolumnen kan också ha en av dessa extra indikatorer:
<: Högprioriterad uppgift.
N: Lågprioriterad uppgift.
L: Processen har sidor låsta i minnet.
S: En sessionsledare. En sessionsledare startar processgrupper.
+: Processen är medlem i en förgrundsgrupp.
l: Multi-thread process.
Vi ser att Bash har status `Ss`. Det stora `S` indikerar att Bash-skalet sover, men att det kan avbrytas. Så fort vi behöver det kommer det att svara. Det lilla `s` indikerar att skalet är en sessionsledare.
Ping-kommandot har status `T`, vilket betyder att det har stoppats av en jobbkontrollsignal. I det här fallet var det Ctrl+Z som vi använde för att sätta det i bakgrunden.
Kommandot `ps T` har status `R`, vilket betyder att det körs. `+` indikerar att den här processen är medlem i förgrundsgruppen. Så kommandot `ps T` körs i förgrunden.
`bg`-kommandot
Kommandot `bg` används för att återuppta en bakgrundsprocess. Det kan användas med eller utan jobbnummer. Om det används utan jobbnummer, återupptas standardjobbet i bakgrunden. Processen körs fortfarande i bakgrunden, men den tar inte emot någon inmatning.
Om vi använder `bg`-kommandot, kommer vårt ping-kommando att återupptas:
bg
Ping-kommandot återupptas och vi ser återigen utdata i terminalfönstret. Namnet på kommandot som har startats om visas. Detta markeras i skärmdumpen.
Men vi har ett problem. Uppgiften körs i bakgrunden och accepterar inte inmatning. Hur stoppar vi det då? Ctrl+C har ingen effekt. Vi kan se det när vi trycker på det, men bakgrundsuppgiften tar inte emot tangenttryckningarna, så den fortsätter att pinga på.
Vi befinner oss nu i ett konstigt läge. Vi kan skriva i terminalfönstret, men det vi skriver rensas snabbt bort av utdatan från ping-kommandot. Allt vi skriver får effekt i förgrunden.
För att stoppa vår bakgrundsuppgift, måste vi flytta den till förgrunden och sedan stoppa den.
`fg`-kommandot
Kommandot `fg` flyttar en bakgrundsuppgift till förgrunden. Precis som `bg`-kommandot, kan det användas med eller utan jobbnummer. Om vi använder det med ett jobbnummer kommer det att fungera på ett specifikt jobb. Om det används utan jobbnummer kommer det att fungera på den senast bakgrundsjobb.
Om vi skriver `fg`, kommer vårt ping-kommando att hamna i förgrunden. De tecken vi skriver blandas med utdatan från ping-kommandot, men hanteras av skalet som om de hade skrivits in på kommandoraden som vanligt. Faktum är att ur Bash-skalets synvinkel är det precis vad som har hänt.
fg
Nu när vi har ping-kommandot i förgrunden igen, kan vi använda Ctrl+C för att avsluta det.
Ctrl+C
Vikten av att skicka rätt signaler
Det var inte särskilt elegant. Det fungerar helt klart bäst att köra en process i bakgrunden om processen inte genererar utdata och inte behöver inmatning.
Men vårt exempel har uppnått följande:
- Att sätta en process i bakgrunden.
- Att återställa processen till ett körläge i bakgrunden.
- Att flytta tillbaka processen till förgrunden.
- Att avsluta processen.
När du använder Ctrl+C och Ctrl+Z skickar du signaler till processen. Det är förkortade sätt att använda kommandot `kill`. Det finns 64 olika signaler som `kill` kan skicka. Använd `kill -l` på kommandoraden för att se dem. `kill` är inte den enda källan till dessa signaler. Vissa av dem utlöses automatiskt av andra processer i systemet.
Här är några av de vanligaste:
SIGHUP: Signal 1. Skickas automatiskt till en process när terminalen där den körs stängs.
SIGINT: Signal 2. Skickas till en process när du trycker på Ctrl+C. Processen avbryts och uppmanas att avslutas.
SIGQUIT: Signal 3. Skickas till en process om användaren skickar en ”quit”-signal, Ctrl+D.
SIGKILL: Signal 9. Processen avbryts omedelbart utan att försöka avsluta ordentligt.
SIGTERM: Signal 15. Detta är standardsignalen som skickas av `kill`, standardsignalen för programavslutning.
SIGTSTP: Signal 20. Skickas till en process när du använder Ctrl+Z, den stoppar processen och placerar den i bakgrunden.
Vi måste använda kommandot `kill` för att utfärda signaler som inte är kopplade till någon tangentkombination.
Ytterligare jobbkontroll
En process som flyttas till bakgrunden med Ctrl+Z placeras i ett stoppat läge. Vi måste använda `bg`-kommandot för att starta det igen. Det är enkelt att starta ett program som en pågående bakgrundsprocess, lägg till ett et-tecken `&` i slutet av kommandoraden.
Även om det är bäst om bakgrundsprocesser inte skriver till terminalfönstret, kommer vi använda exempel som gör det. Vi behöver något som vi kan referera till i skärmdumparna. Följande kommando startar en oändlig loop som en bakgrundsprocess:
`while true; do echo ”How-To Geek Loop Process”; sleep 3; done &`
Vi får veta jobbnumret och process-ID för processen. Vårt jobbnummer är 1 och process-id är 1979. Vi kan använda dessa identifierare för att kontrollera processen.
Utdatan från vår oändliga loop börjar dyka upp i terminalfönstret. Som tidigare kan vi använda kommandoraden, men alla kommandon vi ger blandas med utdatan från loopprocessen.
`ls`
För att stoppa processen kan vi använda `jobs` för att påminna oss själva om jobbnumret och sedan använda `kill`.
jobs rapporterar att vår process är jobb nummer 1. För att använda det numret med `kill` måste vi föregå det med ett procenttecken `%`.
jobs
kill %1
`kill` skickar signalen SIGTERM, signal nummer 15, till processen som då avslutas. När du trycker på Enter nästa gång visas en status för jobbet, och listar processen som ”avslutat”. Om processen inte svarar på `kill`-kommandot, kan du gå ett steg längre och använda `kill` med `SIGKILL`, signal nummer 9. Ange bara siffran 9 mellan `kill`-kommandot och jobbnumret.
kill 9 %1
Sammanfattning
Ctrl+C: Skickar SIGINT, signal 2, till processen – om den accepterar inmatning – och säger åt den att avslutas.
Ctrl+D: Skickar SIGQUIT, signal 3, till processen – om den accepterar inmatning – och säger åt den att avslutas.
Ctrl+Z: Skickar SIGSTP, signal 20, till processen och säger åt den att stoppa och bli en bakgrundsprocess.
`jobs`: Listar bakgrundsjobben och visar deras jobbnummer.
`bg job_number`: Startar om en bakgrundsprocess. Om du inte anger ett jobbnummer används den senaste processen som gjordes till en bakgrundsuppgift.
`fg job_number`: Tar en bakgrundsprocess till förgrunden och startar om den. Om du inte anger ett jobbnummer används den senaste processen som gjordes till en bakgrundsuppgift.
`kommandorad &`: Om du lägger till ett et-tecken `&` i slutet av en kommandorad körs kommandot som en bakgrundsuppgift, som körs.
`kill %job_number`: Skickar SIGTERM, signal 15, till processen för att avsluta den.
`kill 9 %job_number`: Skickar SIGKILL, signal 9, till processen och avslutar den omedelbart.