27.2. /proc

Фактически, каталог /proc -- это виртуальная файловая система. Файлы, в каталоге /proc, содержат информацию о процессах, о состоянии и конфигурации ядра и системы.

bash$ cat /proc/devices
Character devices:
   1 mem
   2 pty
   3 ttyp
   4 ttyS
   5 cua
   7 vcs
  10 misc
  14 sound
  29 fb
  36 netlink
 128 ptm
 136 pts
 162 raw
 254 pcmcia

 Block devices:
   1 ramdisk
   2 fd
   3 ide0
   9 md



bash$ cat /proc/interrupts
           CPU0
   0:      84505          XT-PIC  timer
   1:       3375          XT-PIC  keyboard
   2:          0          XT-PIC  cascade
   5:          1          XT-PIC  soundblaster
   8:          1          XT-PIC  rtc
  12:       4231          XT-PIC  PS/2 Mouse
  14:     109373          XT-PIC  ide0
 NMI:          0
 ERR:          0



bash$ cat /proc/partitions
major minor  #blocks  name     rio rmerge rsect ruse wio wmerge wsect wuse running use aveq

    3     0    3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030
    3     1      52416 hda1 27 395 844 960 4 2 14 180 0 800 1140
    3     2          1 hda2 0 0 0 0 0 0 0 0 0 0 0
    3     4     165280 hda4 10 0 20 210 0 0 0 0 0 210 210
    ...



bash$ cat /proc/loadavg
0.13 0.42 0.27 2/44 1119
        

      

Сценарии командной оболочки могут извлекать необходимую информацию из соответствующих файлов в каталоге /proc. [1]

bash$ cat /proc/filesystems | grep iso9660
        iso9660

             

      

kernel_version=$( awk '{ print $3 }' /proc/version )

      

CPU=$( awk '/model name/ {print $4}' < /proc/cpuinfo )

if [ $CPU = Pentium ]
then
  выполнить_ряд_специфичных_команд
  ...
else
  выполнить_ряд_других_специфичных_команд
  ...
fi

      

В каталоге /proc вы наверняка заметите большое количество подкаталогов, с не совсем обычными именами, состоящими только из цифр. Каждый из них соответствует исполняющемуся процессу, а имя каталога -- это ID (идентификатор) процесса. Внутри каждого такого подкаталога находится ряд файлов, в которых содержится полезная информация о соответствующих процессах. Файлы stat и status хранят статистику работы процесса, cmdline -- команда, которой был запущен процесс, exe -- символическая ссылка на исполняемый файл программы. Здесь же вы найдете ряд других файлов, но, с точки зрения написания сценариев, они не так интересны, как эти четыре.

Пример 27-1. Поиск файла программы по идентификатору процесса

#!/bin/bash
# pid-identifier.sh: Возвращает полный путь к исполняемому файлу программы по идентификатору процесса (pid).

ARGNO=1  # Число, ожидаемых из командной строки, аргументов.
E_WRONGARGS=65
E_BADPID=66
E_NOSUCHPROCESS=67
E_NOPERMISSION=68
PROCFILE=exe

if [ $# -ne $ARGNO ]
then
  echo "Порядок использования: `basename $0` PID-процесса" >&2  # Сообщение об ошибке на >stderr.
  exit $E_WRONGARGS
fi

ps ax

pidno=$( ps ax | grep $1 | awk '{ print $1 }' | grep $1 )
# Проверка наличия процесса с заданным pid в списке, выданном командой  "ps", поле #1.
# Затем следует убедиться, что этот процесс не был запущен этим сценарием ('ps').
# Это делает последний "grep $1".
if [ -z "$pidno" ]  # Если после фильтрации получается пустая строка,
then                # то это означает, что в системе нет процесса с заданым pid.
  echo "Нет такого процесса."
  exit $E_NOSUCHPROCESS
fi

# Альтернативный вариант:
#   if ! ps $1 > /dev/null 2>&1
#   then                # в системе нет процесса с заданым pid.
#     echo "Нет такого процесса."
#     exit $E_NOSUCHPROCESS
#    fi


if [ ! -r "/proc/$1/$PROCFILE" ]  # Проверить право на чтение.
then
  echo "Процесс $1 найден, однако..."
  echo "у вас нет права на чтение файла /proc/$1/$PROCFILE."
  exit $E_NOPERMISSION  # Обычный пользователь не имеет прав
                        # на доступ к некоторым файлам в каталоге /proc.
fi

# Последние две проверки могут быть заменены на:
#    if ! kill -0 $1 > /dev/null 2>&1 # '0' -- это не сигнал, но
                                      # команда все равно проверит наличие
                                      # процесса-получателя.
#    then echo "Процесс с данным PID не найден, либо вы не являетесь его владельцем" >&2
#    exit $E_BADPID
#    fi



exe_file=$( ls -l /proc/$1 | grep "exe" | awk '{ print $11 }' )
# Или      exe_file=$( ls -l /proc/$1/exe | awk '{print $11}' )
#
# /proc/pid-number/exe -- это символическая ссылка
# на исполняемый файл работающей программы.

if [ -e "$exe_file" ]  # Если файл /proc/pid-number/exe существует...
then                 # то существует и соответствующий процесс.
  echo "Исполняемый файл процесса #$1: $exe_file."
else
  echo "Нет такого процесса."
fi


# В большинстве случаев, этот, довольно сложный сценарий, может быть заменен командой
# ps ax | grep $1 | awk '{ print $5 }'
# В большинстве, но не всегда...
# поскольку пятое поле листинга,выдаваемого командой 'ps', это argv[0] процесса,
# а не путь к исполняемому файлу.
#
# Однако, оба следующих варианта должны работать безотказно.
#       find /proc/$1/exe -printf '%l\n'
#       lsof -aFn -p $1 -d txt | sed -ne 's/^n//p'

# Автор последнего комментария: Stephane Chazelas.

exit 0

      

Пример 27-2. Проверка состояния соединения

#!/bin/bash

PROCNAME=pppd        # демон ppp
PROCFILENAME=status  # Что смотреть.
NOTCONNECTED=65
INTERVAL=2           # Период проверки -- раз в 2 секунды.

pidno=$( ps ax | grep -v "ps ax" | grep -v grep | grep $PROCNAME | awk '{ print $1 }' )
# Найти идентификатор процесса 'pppd', 'ppp daemon'.
# По пути убрать из листинга записи о процессах, порожденных сценарием.
#
#  Однако, как отмечает Oleg Philon,
#+ Эта последовательность команд может быть заменена командой "pidof".
#  pidno=$( pidof $PROCNAME )
#
#  Мораль:
#+ Когда последовательность команд становится слишком сложной,
#+ это повод к тому, чтобы поискать более короткий вариант.


if [ -z "$pidno" ]   # Если получилась пустая строка, значит процесс не запущен.
then
  echo "Соединение не установлено."
  exit $NOTCONNECTED
else
  echo "Соединение установлено."; echo
fi

while [ true ]       # Бесконечный цикл.
do

  if [ ! -e "/proc/$pidno/$PROCFILENAME" ]
  # Пока работает процесс, файл "status" существует.
  then
    echo "Соединение разорвано."
    exit $NOTCONNECTED
  fi

netstat -s | grep "packets received"  # Получить некоторые сведения о соединении.
netstat -s | grep "packets delivered"


  sleep $INTERVAL
  echo; echo

done

exit 0

# Как обычно, этот сценарий может быть остановлен комбинацией клавиш Control-C.

#    Упражнение:
#    ----------
#    Добавьте возможность завершения работы сценария, по нажатии на клавишу "q".
#    Это сделает скрипт более жружественным к пользователю.

      
Warning

Будьте предельно осторожны при работе с файловой системой /proc, так как попытка записи в некоторые файлы может повредить файловую систему или привести к краху системы.

Примечания

[1]

Отдельные системные команды, такие как procinfo, free, vmstat, lsdev и uptime делают это именно таким образом.