27.2. /proc


27.2. /proc

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

  1. bash$ cat /proc/devices
  2. Character devices:
  3.    1 mem
  4.    2 pty
  5.    3 ttyp
  6.    4 ttyS
  7.    5 cua
  8.    7 vcs
  9.   10 misc
  10.   14 sound
  11.   29 fb
  12.   36 netlink
  13.  128 ptm
  14.  136 pts
  15.  162 raw
  16.  254 pcmcia
  17.  Block devices:
  18.    1 ramdisk
  19.    2 fd
  20.    3 ide0
  21.    9 md
  22. bash$ cat /proc/interrupts
  23.            CPU0
  24.    0:      84505          XT-PIC  timer
  25.    1:       3375          XT-PIC  keyboard
  26.    2:          0          XT-PIC  cascade
  27.    5:          1          XT-PIC  soundblaster
  28.    8:          1          XT-PIC  rtc
  29.   12:       4231          XT-PIC  PS/2 Mouse
  30.   14:     109373          XT-PIC  ide0
  31.  NMI:          0
  32.  ERR:          0
  33. bash$ cat /proc/partitions
  34. major minor  #blocks  name     rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
  35.     3     0    3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030
  36.     3     1      52416 hda1 27 395 844 960 4 2 14 180 0 800 1140
  37.     3     2          1 hda2 0 0 0 0 0 0 0 0 0 0 0
  38.     3     4     165280 hda4 10 0 20 210 0 0 0 0 0 210 210
  39.     ...
  40. bash$ cat /proc/loadavg
  41. 0.13 0.42 0.27 2/44 1119
  42.          


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

  1. bash$ cat /proc/filesystems | grep iso9660
  2.         iso9660
  3.        


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


  1. CPU=$( awk '/model name/ {print $4}' < /proc/cpuinfo )
  2. if [ $CPU = Pentium ]
  3. then
  4.   выполнить_ряд_специфичных_команд
  5.   ...
  6. else
  7.   выполнить_ряд_других_специфичных_команд
  8.   ...
  9. fi


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

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

  1. #!/bin/bash
  2. # pid-identifier.sh: Возвращает полный путь к исполняемому файлу программы по идентификатору процесса (pid).
  3. ARGNO=1  # Число, ожидаемых из командной строки, аргументов.
  4. E_WRONGARGS=65
  5. E_BADPID=66
  6. E_NOSUCHPROCESS=67
  7. E_NOPERMISSION=68
  8. PROCFILE=exe
  9. if [ $# -ne $ARGNO ]
  10. then
  11.   echo "Порядок использования: `basename $0` PID-процесса" >&2  # Сообщение об ошибке на >stderr.
  12.   exit $E_WRONGARGS
  13. fi
  14. ps ax
  15. pidno=$( ps ax | grep $1 | awk '{ print $1 }' | grep $1 )
  16. # Проверка наличия процесса с заданным pid в списке, выданном командой  "ps", поле #1.
  17. # Затем следует убедиться, что этот процесс не был запущен этим сценарием ('ps').
  18. # Это делает последний "grep $1".
  19. if [ -z "$pidno" ]  # Если после фильтрации получается пустая строка,
  20. then                # то это означает, что в системе нет процесса с заданым pid.
  21.   echo "Нет такого процесса."
  22.   exit $E_NOSUCHPROCESS
  23. fi
  24. # Альтернативный вариант:
  25. #   if ! ps $1 > /dev/null 2>&1
  26. #   then                # в системе нет процесса с заданым pid.
  27. #     echo "Нет такого процесса."
  28. #     exit $E_NOSUCHPROCESS
  29. #    fi
  30. if [ ! -r "/proc/$1/$PROCFILE" ]  # Проверить право на чтение.
  31. then
  32.   echo "Процесс $1 найден, однако..."
  33.   echo "у вас нет права на чтение файла /proc/$1/$PROCFILE."
  34.   exit $E_NOPERMISSION  # Обычный пользователь не имеет прав
  35.                         # на доступ к некоторым файлам в каталоге /proc.
  36. fi
  37. # Последние две проверки могут быть заменены на:
  38. #    if ! kill -0 $1 > /dev/null 2>&1 # '0' — это не сигнал, но
  39.                                       # команда все равно проверит наличие
  40.                                       # процесса-получателя.
  41. #    then echo "Процесс с данным PID не найден, либо вы не являетесь его владельцем" >&2
  42. #    exit $E_BADPID
  43. #    fi
  44. exe_file=$( ls -l /proc/$1 | grep "exe" | awk '{ print $11 }' )
  45. # Или      exe_file=$( ls -l /proc/$1/exe | awk '{print $11}' )
  46. #
  47. # /proc/pid-number/exe — это символическая ссылка
  48. # на исполняемый файл работающей программы.
  49. if [ -e "$exe_file" ]  # Если файл /proc/pid-number/exe существует...
  50. then                 # то существует и соответствующий процесс.
  51.   echo "Исполняемый файл процесса #$1: $exe_file."
  52. else
  53.   echo "Нет такого процесса."
  54. fi
  55. # В большинстве случаев, этот, довольно сложный сценарий, может быть заменен командой
  56. # ps ax | grep $1 | awk '{ print $5 }'
  57. # В большинстве, но не всегда...
  58. # поскольку пятое поле листинга,выдаваемого командой 'ps', это argv[0] процесса,
  59. # а не путь к исполняемому файлу.
  60. #
  61. # Однако, оба следующих варианта должны работать безотказно.
  62. #       find /proc/$1/exe -printf '%l\n'
  63. #       lsof -aFn -p $1 -d txt | sed -ne 's/^n//p'
  64. # Автор последнего комментария: Stephane Chazelas.
  65. exit 0

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

  1. #!/bin/bash
  2. PROCNAME=pppd        # демон ppp
  3. PROCFILENAME=status  # Что смотреть.
  4. NOTCONNECTED=65
  5. INTERVAL=2           # Период проверки — раз в 2 секунды.
  6. pidno=$( ps ax | grep -v "ps ax" | grep -v grep | grep $PROCNAME | awk '{ print $1 }' )
  7. # Найти идентификатор процесса 'pppd', 'ppp daemon'.
  8. # По пути убрать из листинга записи о процессах, порожденных сценарием.
  9. #
  10. #  Однако, как отмечает Oleg Philon,
  11. #+ Эта последовательность команд может быть заменена командой "pidof".
  12. #  pidno=$( pidof $PROCNAME )
  13. #
  14. #  Мораль:
  15. #+ Когда последовательность команд становится слишком сложной,
  16. #+ это повод к тому, чтобы поискать более короткий вариант.
  17. if [ -z "$pidno" ]   # Если получилась пустая строка, значит процесс не запущен.
  18. then
  19.   echo "Соединение не установлено."
  20.   exit $NOTCONNECTED
  21. else
  22.   echo "Соединение установлено."; echo
  23. fi
  24. while [ true ]       # Бесконечный цикл.
  25. do
  26.   if [ ! -e "/proc/$pidno/$PROCFILENAME" ]
  27.   # Пока работает процесс, файл "status" существует.
  28.   then
  29.     echo "Соединение разорвано."
  30.     exit $NOTCONNECTED
  31.   fi
  32. netstat -s | grep "packets received"  # Получить некоторые сведения о соединении.
  33. netstat -s | grep "packets delivered"
  34.   sleep $INTERVAL
  35.   echo; echo
  36. done
  37. exit 0
  38. # Как обычно, этот сценарий может быть остановлен комбинацией клавиш Control-C.
  39. #    Упражнение:
  40. #    ----------
  41. #    Добавьте возможность завершения работы сценария, по нажатии на клавишу "q".
  42. #    Это сделает скрипт более жружественным к пользователю.
Warning

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


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