Книга: UNIX — универсальная среда программирования
6.7 Пример: zap
Разделы на этой странице:
6.7 Пример: zap
Программа zap
, которая избирательно уничтожает процессы, отличается от той, что была представлена в виде файла shell
в гл. 5. Главная проблема данной версии скорость. Она создает много процессов и поэтому работает медленно, что недопустимо для программы, уничтожающей процессы с ошибками. Если переписать zap
на Си, ее быстродействие повысится. Мы, однако, снова воспользуемся ps, чтобы найти информацию о процессе. Это намного легче, чем выуживать информацию из ядра, и, кроме того, мы имеем переносимый вариант. Программа zap
открывает программный канал, входной поток для которого берется из ps, и читает из него, как из файла. Функция popen(3)
аналогична fopen
, за исключением того, что первый аргумент является командой, а не именем файла. То же самое справедливо и для pclose
, но здесь она нам не нужна.
/* zap: interactive process killer */
#include <stdio.h>
#include <signal.h>
char *progname; /* program name for error message */
char *ps = "ps -ag"; /* system dependent */
main(argc, argv)
int argc;
char *argv[];
{
FILE *fin, *popen();
char buf[BUFSIZ];
int pid;
progname = argv[0];
if ((fin = popen(ps, "r")) == NULL) {
fprintf(stderr, "%s: can't run %sn", progname, ps);
exit(1);
}
fgets(buf, sizeof buf, fin); /* get header line */
fprintf(stderr, "%s", buf);
while (fgets(buf, sizeof buf, fin) != NULL)
if (argc == 1 || strindex(buf, argv[1]) >= 0) {
buf[strlen(buf)-1] = ''; /* suppress n */
fprintf(stderr, "%s? ", buf);
if (ttyin() == 'y') {
sscanf(buf, "%d", &pid);
kill(pid, SIGKILL);
}
}
exit(0);
}
Мы писали программу, чтобы использовать ps -ag
(этот флаг системно зависим), но если вы не являетесь привилегированным пользователем, то можете уничтожать лишь свои собственные процессы.
Первый вызов fgets
выбирает заголовок из ps; интересно выяснить, что случится, если попытаться уничтожить "процесс", соответствующий данному заголовку.
Функция sscanf
представляет собой член семейства scanf(3)
для форматного преобразования входной строки. Она преобразует строку, а не файл. Вызов kill
из системы посылает специальный сигнал процессу; сигнал SIGKILL
, определенный в <signal.h>
, не может быть перехвачен или проигнорирован. Вы можете вспомнить пятую главу, где его численное значение равно девяти, но лучше использовать символические константы из файлов макроопределений, чем включать в свои программы загадочные числа.
Если аргументы отсутствуют, zap
предоставляет каждую строку выходного потока ps как возможность для выбора. При наличии аргумента zap
предлагает только те выходные строки ps, которые ему соответствуют. Функция strindex(s1, s2)
проверяет, соответствует ли аргумент какой-либо части строки выходного потока ps, используя strncmp
(см. табл. 6.2). Функция strindex
возвращает позицию s2
в s1
или -1, если ее там нет.
strindex(s, t) /* return index of t in s, -1 if none */
char *s, *t;
{
int i, n;
n = strlen(t);
for (i = 0; s[i] != ''; i++)
if (strncmp(s+i, t, n) == 0)
return i;
return -1;
}
В табл. 6.4 представлены широко используемые функции из стандартной библиотеки ввода вывода.
fp=fopen(s, mode) |
Открыть файл s; значения mode "r" , "w" , "a" соответствуют чтению, записи и добавлению (при ошибке возвращается NULL) |
c=gets(fp) |
Читать символ: getchar() это getc(stdin) |
putc(c, fp) |
Записать символ: putchar(c) это putc(c, stdout) |
ungetc(c, fp) |
Вернуть символ во входной файл fp ; можно вернуть не более одного символа за раз |
scanf(fmt, a1, ...) |
Читать символы из stdin в a1 , ... в соответствии с fmt . Каждый ai должен быть указателем |
fscanf(fp,...) |
Читать из файла fp |
sscanf(s,...) |
Читать из строки s |
printf(fmt, a1, ...) |
Форматировать a1 , ... в соответствии с fmt ; печатать в stdout |
fprintf(fp, ...) |
Печатать ... в файл fp |
sprintf(s, ...) |
Печатать ... в строку s |
fqets(s, n, fp) |
Читать не более n символов в s из fp (возвращается NULL по концу файла) |
fputs(s, fp) |
Печатать строку s в файл fp |
fflush(fp) |
Занести буферизованные данные выходного потока в файл fp |
fclose(fp) |
Закрыть файл fp |
fp=popen(s, mode) |
Открыть программный канал для команды s (см. fopen ) |
pclose(fp) |
Закрыть программный канал fp |
system(s) |
Запустить команду s и ждать ее окончания |
Таблица 6.4: Полезные стандартные функции ввода-вывода
Упражнение 6.11
Модифицируйте zap
так, чтобы можно было применять любое число аргументов. В настоящем виде zap
высвечивает на экране строку, соответствующую выбранному варианту. Будет она делать это? Если нет, модифицируйте программу соответствующим образом. Подсказка: getpid(2)
.
Упражнение 6.12
Постройте fgrep(1)
на основе strindex
. Сравните время работы при сложных поисках, например 10 слов на документ. Почему fgrep
выполняется быстрее?
- Пример установочного скрипта
- Пример из практики
- ПРИМЕР ПРОСТОЙ ПРОГРАММЫ НА ЯЗЫКЕ СИ
- Примеры получения статистики
- Пример применения метода «пять почему»
- Пример 12-8. Частота встречаемости отдельных слов
- 1.2.5. Пример программы
- Пример 17-10. Блочный комментарий
- Примеры
- 2. Пример создания базового отношения в записи на псевдокоде
- Пример 9-8. Содержимое $* и $@, когда переменная $IFS -- пуста
- Часть I На примере денег