DevOps.Academy
CoursesCurriculumPricing

    Loading…

    ↑ ↓ move · ↵ open · Ctrl K anywhere

    ◔My learningSign in
    DevOps.Academy

    Free, hands-on DevOps lessons. Made with care in India.

    Learn

    All coursesLinux roadmapCurriculumMy learning

    Academy

    PricingCertificates

    Legal

    PrivacyTermsContact

    devops.rajeev.pro

    Linux & BashLesson 7 of 16
    Your progress · 0%
    On this page
    1. What a process is
    2. Finding processes
    3. Jobs: foreground, background and after logout
    4. Signals: asking and forcing
    5. Priorities: nice and renice
    ↖ Course roadmap
    Lesson 7 · Process management

    Processes: see them, control them, stop them

    What a process is, how to find the one eating your CPU, run jobs in the background, keep them alive after logout, stop them with the right signal and change their priority.

    30 min read · beginner · hands-on

    By the end of this lesson you'll be able to

    0 of 6 complete

    What a process is

    A program is a file on disk, such as /usr/sbin/nginx. A process is that program running: it has memory, open files, a user it runs as, and a number, the PID. Run the same program twice and you get two processes.

    Every process is started by another one, its parent (PPID). On Linux that happens in two steps: the parent forks (makes a copy of itself), and the copy execs (replaces itself with the new program). So everything forms one family tree, rooted at PID 1, which on modern servers is systemd.

    Every process has a parent. Your commands are children of your shell.© Diagram: DevOps Academy

    Every process has a parent. Your commands are children of your shell.© Diagram: DevOps Academy
    $ echo $$                       # your shell's own PID
    2210
    $ bash -c 'echo "me=$$ parent=$PPID"'
    me=2291 parent=2210
    $ pstree -p | head -n 12        # the whole family tree
    
    echo $$
    • echoprint text
    pstree -p | head -n 12
    • |pipe: send output to the next command
    • headshow the first lines
    • -nhow many lines

    Finding processes

    $ ps aux                         # every process: user, PID, %CPU, %MEM, state, command
    $ ps aux --sort=-%cpu | head -5  # the five busiest by CPU (-%mem for memory)
    $ ps -ef | grep [n]ginx          # parent PIDs too. [n] stops grep matching itself
    $ ps -o pid,ppid,user,ni,stat,%cpu,%mem,cmd -p 812   # exactly the columns you want
    $ pgrep -a nginx                 # PIDs and command lines matching a name
    812 nginx: master process /usr/sbin/nginx
    813 nginx: worker process
    $ pgrep -u www-data              # by user
    
    ps aux
    • pslist processes
    ps aux --sort=-%cpu | head -5
    • |pipe: send output to the next command
    • headshow the first lines
    ps -ef | grep [n]ginx
    • grepfind lines that match a pattern

    The STAT column says what each process is doing:

    STATMeans
    Rrunning, or ready to run
    Ssleeping, waiting for something (most processes, most of the time)
    Dwaiting for the disk or network, and can't be interrupted. Many D = slow storage
    Tstopped (you pressed Ctrl+Z)
    Zzombie: finished, but its parent hasn't collected it yet

    top: the live view

    top refreshes every few seconds. The keys that matter: P sort by CPU, M by memory, 1 show each core, k kill a PID, q quit. The header repeats the load average, and the %wa value shows CPU time spent waiting for disks. htop is a friendlier version if it's installed, and watch -n 2 'ps aux --sort=-%cpu | head' gives you a simple live view of anything.

    Two runaways at the top of the list, each using a whole core: exactly what the mission below asks you to find. top -p limited this view to four demo processes.© Screenshot: DevOps Academy

    Two runaways at the top of the list, each using a whole core: exactly what the mission below asks you to find. top -p limited this view to four demo processes.© Screenshot: DevOps Academy

    Jobs: foreground, background and after logout

    $ ./long-task.sh                 # runs in the foreground: the prompt waits
    ^Z                               # Ctrl+Z pauses it
    [1]+  Stopped                 ./long-task.sh
    $ bg                             # continue it in the background
    $ jobs                           # this shell's jobs
    [1]+  Running                 ./long-task.sh &
    $ fg %1                          # bring it back to the foreground
    $ ./another-task.sh &            # & starts it in the background straight away
    

    Jobs belong to your shell. When your SSH session ends, the shell sends them SIGHUP and they stop. For anything that must outlive your session:

    $ nohup ./backup.sh > backup.log 2>&1 &   # ignore the hang-up, log to a file
    $ tmux new -s deploy                      # a session that lives on the server
                                              # Ctrl+B then D detaches; log out safely
    $ tmux attach -t deploy                   # later, from any SSH login: reattach
    
    nohup ./backup.sh > backup.log 2>&1 &
    • >write output to a file, replacing it
    • 2>&1send errors to the same place as output
    In production

    Start every long operation (migrations, backups, big copies) inside tmux or screen. A dropped Wi-Fi connection halfway through a database migration is a bad afternoon. For things that should always run, don't use either: make them a systemd service.

    Signals: asking and forcing

    A signal is a message to a process. kill sends them, despite its name:

    Ask first (TERM), force last (KILL). A killed process can't save its work.© Diagram: DevOps Academy

    Ask first (TERM), force last (KILL). A killed process can't save its work.© Diagram: DevOps Academy
    $ kill 4821                 # SIGTERM (15): please stop, cleanly
    $ kill -HUP 812             # SIGHUP (1): nginx re-reads its config
    $ kill -9 4821              # SIGKILL: the kernel removes it at once. Last resort
    $ pkill -f "python worker.py"   # by command line instead of PID
    $ killall node              # every process with that exact name
    $ kill -l                   # the full list
    
    kill 4821
    • killsend a signal to a process

    SIGTERM lets the program finish its work. SIGKILL stops it mid-sentence, whatever it was doing.© Animation: DevOps Academy

    SIGTERM lets the program finish its work. SIGKILL stops it mid-sentence, whatever it was doing.© Animation: DevOps Academy

    Always try kill (TERM) first, wait a few seconds, check with ps -p 4821, and only then use -9. A database killed with -9 may need recovery when it starts again.

    A zombie (Z) is already dead, so you can't kill it. It's waiting for its parent to read its exit status. One or two are harmless. Thousands mean the parent program has a bug: restart the parent, and the zombies go with it.

    Priorities: nice and renice

    When CPUs are busy, the kernel shares them out by priority. The nice value runs from -20 (most important) to 19 (most polite). New processes start at 0.

    $ nice -n 15 tar czf backup.tar.gz /srv    # start a heavy job politely
    $ renice -n 10 -p 4821                     # make a running process give way
    4821 (process ID) old priority 0, new priority 10
    $ sudo renice -n -5 -p 812                 # only root may raise priority
    
    sudo renice -n -5 -p 812
    • sudorun the next command as root

    Use nice for backups, report jobs and big compressions on a server that's also serving users: the job takes a little longer, and the users don't notice it.

    ⌘
    Mini mission

    Stop a runaway process, gently

    Someone left a process spinning at 100% CPU and users say the server is slow. Find it, make it give way to everything else while you investigate, then stop it cleanly and prove it's gone.

    Input: A busy process (you'll start one with yes)Output: No yes process left; the busiest-process list returns to normal
    Reveal one safe solution
    $ yes > /dev/null &                         # the "runaway" for this mission
    [1] 4821
    $ ps aux --sort=-%cpu | head -3             # 1. find it
    USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    rajeev      4821 99.6  0.0   8392  1792 pts/0    R    10:51   0:21 yes
    $ renice -n 19 -p 4821                      # 2. calm it down while you look
    4821 (process ID) old priority 0, new priority 19
    $ ps -o pid,ppid,user,ni,cmd -p 4821        # 3. who started it, and from where?
        PID    PPID USER      NI CMD
       4821    2210 rajeev    19 yes
    $ kill 4821                                 # 4. ask it to stop (SIGTERM)
    $ pgrep yes || echo "gone"                  # 5. prove it
    gone
    
    yes > /dev/null &
    • >write output to a file, replacing it
    ps aux --sort=-%cpu | head -3
    • pslist processes
    • |pipe: send output to the next command
    • headshow the first lines
    kill 4821
    • killsend a signal to a process
    pgrep yes || echo "gone"
    • ||run the next command only if this one failed
    • echoprint text

    The PPID (2210) tells you which shell started it, which is how you find the person or script responsible. Here SIGTERM was enough. kill -9 would only have been needed if pgrep still found it after a few seconds.

    Try it yourself

    0 of 6 steps done

    Run each task in your own account or terminal, then tick it off.

    Knowledge check

    Quick check

    Question 1 of 5

    A process won't stop with kill 4821. What should you do first?

    Go deeper

    Official reading for this lesson

    • Docsps(1) manualUbuntu manpages ↗
    • Docstop(1) manualUbuntu manpages ↗
    • Docssignal(7): the list of signals and what they doUbuntu manpages ↗
    • Guidetmux getting startedtmux ↗
    • GuideLPIC-1 exam 101, objectives 103.5 and 103.6Linux Professional Institute ↗

    Or get every quiz answer right and it completes itself.

    ← PreviousServer review: a five-minute health checkNext lesson →Users and groups: who can do what