Текст книги "Основы программирования в Linux"
Автор книги: Нейл Мэтью
Соавторы: Ричард Стоунс
Жанры:
Программирование
,сообщить о нарушении
Текущая страница: 14 (всего у книги 67 страниц)
Функция perror
также превращает текущую ошибку в виде, представленном в переменной errno
, в строку и выводит ее в стандартный поток ошибок. Ей предшествует сообщение, заданное в строке s
(если указатель не равен NULL
), за которым следуют двоеточие и пробел.
Далее приведена синтаксическая запись функции:
#include
void perror(const char *s);
Например, вызов
perror(«program»);
может дать следующий результат в стандартном потоке ошибок:
program: Too many open files
Файловая система procfs
Ранее в этой главе мы уже писали о том, что ОС Linux обрабатывает многие вещи как файлы, и в файловой системе есть ряд элементов для аппаратных устройств. Эти файлы /dev применяются для доступа к оборудованию особыми методами с помощью низкоуровневых системных вызовов.
Программные драйверы, управляющие оборудованием, часто могут настраиваться определенными способами или сообщать информацию. Например, контроллер жесткого диска может настраиваться на применение определенного режима DMA. Сетевая карта может обладать функциональными возможностями для оповещения об установке высокоскоростного дуплексного соединения.
В прошлом для связи с драйверами устройств применялись утилиты общего назначения. Например, hdparm использовалась для настройки некоторых параметров диска, a ifconfig могла сообщить сетевую статистику. В недавнем прошлом появилась тенденция, направленная на обеспечение более подходящего способа доступа к информации драйвера и, как расширение, включающая взаимодействие с различными элементами ядра Linux.
ОС Linux предоставляет специальную файловую систему procfs, которая обычно доступна в виде каталога /proc. Она содержит много специальных файлов, обеспечивающих высокоуровневый доступ к информации драйвера и ядра. Приложения, выполняющиеся с корректными правами доступа, могут читать эти файлы для получения информации и записывать в них устанавливаемые параметры.
Набор файлов в каталоге /proc меняется от системы к системе, и с каждым новым выпуском Linux появляются новые файлы, дополнительные драйверы и средства поддержки файловой системы procfs. В этом разделе мы рассмотрим некоторые из самых широко распространенных файлов и кратко обсудим их применение.
В перечень каталога /proc на компьютере, использовавшемся для написания этой главы, включены следующие элементы:
1/ 10514/ 20254/ 6/ 9057/ 9623/ ide/ mtrr
10359/ 10524/ 29/ 698/ 9089/ 9638/ interrupts net/
10360/ 10530/ 983/ 699/ 9118/ acpi/ iomem partitions
10381/ 10539/ 3/ 710/ 9119/ asound/ ioports scsi/
10438/ 10541/ 30/ 711/ 9120/ buddyinfo irq/ self@
10441/ 10555/ 3069/ 742/ 9138/ bus/ kallsyms slabinfo
10442/ 10688/ 3098/ 7808/ 9151/ cmdline kcore splash
10478/ 10689/ 3099/ 7813/ 92/ config.gz keys stat
10479/ 10784/ 31/ 8357/ 9288/ cpuinfo key-users swaps
10482/ 113/ 3170/ 8371/ 93/ crypto kmsg sys/
10484/ 115/ 3171/ 840/ 9355/ devices loadavg sysrq-trigger
10486/ 116/ 3177/ 8505/ 9407/ diskstats locks sysvipc/
10495/ 1167/ 32288/ 8543/ 9457/ dma mdstat tty/
10497/ 1168/ 3241/ 8547/ 9479/ driver/ meminfo uptime
Во многих случаях файлы могут только читаться и дают информацию о состоянии. Например, /proc/cpuinfo предоставляет сведения о доступных процессорах:
$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 2
model name : Intel(R) Pentium(R) 4 CPU 2.66GHz
stepping : 8
cpu MHz : 2665.923
cache size : 512 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 2
wp : yes
flags : fpu vme de pse tsc msr рае mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss up
bogomips : 5413.47
clflush size : 64
Файлы /proc/meminfo и /рroc/version предоставляют данные об использовании оперативной памяти и версии ядра соответственно:
$ cat /proc/meminfo
MemTotal: 776156 kB
MemFree: 28528 kB
Buffers: 191764 kB
Cached: 369520 kB
SwapCached: 20 kB
Active: 406912 kB
Inactive: 274320 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 776156 kB
LowFree: 28528 kB
SwapTotal: 1164672 kB
SwapFree: 1164652 kB
Dirty: 68 kB
Writeback: 0 kB
AnonPages: 95348 kB
Mapped: 49044 kB
Slab: 57848 kB
SReclaimable: 48008 kB
SUnreclaim: 9840 kB
PageTables: 1500 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
CommitLimit: 1552748 kB
Committed_AS: 189680 kB
VmallocTotal: 245752 kB
VmallocUsed: 10572 kB
VmallocChunk: 234556 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
Hugepagesize: 4096 kB
$ cat /proc/version
Linux version 2.6.20.2-2-default (geeko@buildhost) (gcc version 4.1.3 20070218 (prerelease) (SUSE Linux)) #1 SMP Fri Mar 9 21:54:10 UTC 2007
Информация, выводимая этими файлами, генерируется при каждом чтении файла. Поэтому повторное чтение файла meminfo в более поздний момент времени даст результаты с точностью до секунд.
Получить дополнительную информацию от специальных функций ядра можно в подкаталогах каталога /proc. Например, статистику использования сетевых сокетов вы можете узнать из /proc/net/sockstat:
$ cat /proc/net/sockstat
sockets: used 285
TCP: inuse 4 orphan 0 tw 0 alloc 7 mem 1
UDP: inuse 3
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0
В некоторые элементы каталога /proc можно производить запись, а не только читать их. Например, общее количество файлов, которые могут быть открыты одновременно всеми выполняющимися программами, – это параметр ядра Linux. Текущее значение можно прочитать из /proc/sys/fs/file-max:
$ cat /proc/sys/fs/file-max
76593
В данном случае задана величина 76593
. Если вам нужно увеличить это значение, вы можете сделать это, записав его в тот же файл. Это действие может потребоваться при выполнении специального комплекса программ, например, системы управления базой данных, которая использует много таблиц, что потребует одновременного открытия большого числа файлов.
Примечание
Для записи в файлы /proc требуются права доступа суперпользователя. При записи в эти файлы нужно быть предельно внимательным; при записи неподходящих данных возможно возникновение серьезных проблем, включая крах системы и потерю данных.
Для увеличения предельного значения одновременно обрабатываемых в системе файлов до 80000 вы можете просто записать новое предельное значение в файл file-max.
# echo 80000 >/proc/sys/fs/file-max
Теперь, повторно прочитав файл, вы увидите новое значение:
$ cat /proc/sys/fs/file-max
80000
Подкаталоги каталога /proc с числовыми именами применяются для обеспечения доступа к информации о выполняющихся программах. В главе 11 вы узнаете больше о том, что программы выполняются как процессы.
Сейчас только отметьте, что у каждого процесса есть уникальный идентификатор: число в диапазоне от 1 до почти 32 000. Команда ps предоставляет список выполняющихся в данный момент процессов. Например, когда писалась эта глава:
neil@susel03:~/BLP4e/chapter03> ps -а
PID TTY TIME CMD
9118 pts/1 00:00:00 ftp
9230 pts/1 00:00:00 ps
10689 pts/1 00:00:01
bash neil@susel03:~/BLP4e/chapter03>
Вы видите несколько сеансов терминалов, запустивших командную оболочку bash и сеанс передачи файла, выполняющий программу ftp
. Просмотрев каталог /proc, вы получите более подробную информацию о сеансе ftp
.
В данном случае для ftp задан идентификатор процесса 9118
, поэтому вы должны заглянуть в каталог /proc/9118 для получения подробной информации о нем:
$ ls -l /proc/9118
total 0
0 dr-xr-xr-x 2 neil users 0 2007-05-20 07:43 attr
0 -r– 1 neil users 0 2007-05-20 07:43 auxv
0 -r–r–r– 1 neil users 0 2007-05-20 07:35 cmdline
0 -r–r–r– 1 neil users 0 2007-05-20 07:43 cpuset
0 lrvxrwxrwx 1 neil users 0 2007-05-20 07:43 cwd -> /home/neil/BLP4e/chapter03
0 -r– 1 neil users 0 2007-05-20 07:43 environ
0 lrwxrwxrwx 1 neil users 0 2007-05-20 07:43 exe -> /usr/bin/pftp
0 dr-x– 2 neil users 0 2007-05-20 07:19 fd
0 -rw-r–r– 1 neil users 0 2007-05-20 07:43 loginuid
0 -r–r–r– 1 neil users 0 2007-05-20 07:43 maps
0 -rw– 1 neil users 0 2007-05-20 07:43 mem
0 -r–r–r– 1 neil users 0 2007-05-20 07:43 mounts
0 -r– 1 neil users 0 2007-05-20 07:43 mountstats
0 -rw-r–r– 1 neil users 0 2007-05-20 07:43 oom_adj
0 -r–r–r– 1 neil users 0 2007-05-20 07:43 oom_score
0 lrwxrwxrwx 1 neil users 0 2007-05-20 07:43 root -> /
0 -rw– 1 neil users 0 2007-05-20 07:43 seccomp
0 -r–r–r– 1 neil users 0 2007-05-20 07:43 smaps
0 -r–r–r– 1 neil users 0 2007-05-20 07:33 stat
0 -r–r–r– 1 neil users 0 2007-05-20 07:43 statm
0 -r–r–r– 1 neil users 0 2007-05-20 07:33 status
0 dr-xr-xr-x 3 neil users 0 2007-05-20 07:43 task
0 -r–r–r– 1 neil users 0 2007-05-20 07:43 wchan
В данном перечне вы видите разные специальные файлы, способные сообщить вам, что происходит с процессом.
Можно сказать, что выполняется программа /usr/bin/pftp, и ее текущий рабочий каталог – home/neil/BLP4e/chapter03. Есть возможность прочитать другие файлы из этого каталога, чтобы увидеть командную строку, применяемую для запуска программы, а также ее окружение. Файлы cmdline и environ предоставляют эту информацию в виде последовательности нуль-терминированных строк, поэтому вам следует соблюдать осторожность при их просмотре. Более подробно окружение ОС Linux мы обсудим в главе 4.
$ od -с /proc/9118/cmdline
0000000 f t p 1 9 2 . 1 6 8 . 0 . 1 2
0000020
0000021
Из полученного вывода видно, что ftp
была запущена из командной строки ftp 192.163.0.12
.
Подкаталог fd предоставляет информацию об открытых дескрипторах файлов, используемых процессом. Эти данные могут быть полезны при определении количества файлов, одновременно открытых программой. На каждый открытый дескриптор приходится один элемент; имя его соответствует номеру дескриптора. В нашем случае, как мы и ожидали, у программы ftp
есть открытые дескрипторы 0, 1, 2 и 3. Они включают стандартные дескрипторы ввода, вывода и потока ошибок плюс подключение к удаленному серверу.
$ ls /proc/9118/fd
0 1 2 3
Более сложные приемы: fcntl и mmap
Теперь мы коснемся приемов, которые вы можете пропустить, поскольку они редко используются. Признавая это, мы помещаем их в книгу просто для вашего сведения, потому что применение описываемых средств может предоставить простые решения для замысловатых проблем.
fcntlСистемный вызов fcntl
предоставляет дополнительные методы обработки низкоуровневых дескрипторов файлов:
#include
int fcntl(int fildes, int cmd);
int fcntl(int fildes, int cmd, long arg);
С помощью системного вызова fcntl
вы можете выполнить несколько разнородных операций над открытыми дескрипторами файлов, включая их дублирование, получение и установку флагов дескрипторов файлов, получение и установку флагов состояния файла и управление блокировкой файла (advisory file locking).
Различные операции выбираются разными значениями параметра команды cmd
, как определено в файле fcntl.h. В зависимости от выбранной команды системному вызову может потребоваться третий параметр arg
.
□ fcntl(fildes, F_DUPFD, newfd)
– этот вызов возвращает новый дескриптор файла с числовым значением, равным или большим целочисленного параметра newfd
. Новый дескриптор – копия дескриптора fildes
. В зависимости от числа открытых файлов и значения newfd
этот вызов может быть практически таким же, как вызов dup(fildes)
.
□ fcntl(fildes, F_GETFD)
– этот вызов возвращает флаги дескриптора файла, как определено в файле fcntl.h. К ним относится FD_CLOEXEC
, определяющий, закрыт ли дескриптор файла после успешного вызова одного из системных вызовов семейства exec.
□ fcntl(fildes, F_SETFD, flags)
– этот вызов применяется для установки флагов дескриптора файла, как правило, только FD_CLOEXEC
.
□ fcntl(fildes, F_GETFL)
и fcntl(fildes, F_SETFL, flags)
– эти вызовы применяются, соответственно, для получения и установки флагов состояния файла и режимов доступа. Вы можете извлечь режимы доступа к файлу с помощью маски O_ACCMODE
, определенной в файле fcntl.h. Остальные флаги включают передаваемые значения в третьем аргументе вызову open с использованием O_CREAT
. Учтите, что вы не можете задать все флаги. В частности, нельзя задать права доступа к файлу с помощью вызова fcntl.
Вызов fcntl
также позволяет реализовать блокировку файла. См. более подробную информацию в разделе 2 интерактивного справочного руководства или главу 7, в которой мы обсуждаем блокировку файлов.
Система UNIX предоставляет полезное средство, позволяющее программам совместно использовать память, и, к счастью, оно включено в версию 2.0 и более поздние версии ядра Linux. Функция mmap
(для отображения памяти) задает сегмент памяти, который может читаться двумя или несколькими программами и в который они могут записывать данные. Изменения, сделанные одной программой, видны всем остальным.
Вы можете применить то же самое средство для работы с файлами, заставив все содержимое файла на диске выглядеть как массив в памяти. Если файл состоит из записей, которые могут быть описаны структурами на языке С, вы сможете обновлять файл с помощью методов доступа к массиву структур.
Это становится возможным благодаря применению сегментов виртуальной памяти с набором особых прав доступа. Чтение из сегмента и запись в него заставляет операционную систему читать соответствующую часть файла на диске и писать данные в нее.
Функция mmap создает указатель на область памяти, ассоциированную с содержимым файла, доступ к которому осуществляется через открытый дескриптор файла.
#include
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
Изменить начальную позицию порции данных файла, к которым выполняется обращение через совместно используемый сегмент, можно, передавая параметр off
. Открытый дескриптор файла задается в параметре fildes
. Объем данных, к которым возможен доступ (т. е. размер сегмента памяти), указывается в параметре len
.
Параметр addr
можно использовать для запроса конкретного адреса памяти. Если он равен нулю, результирующий указатель формируется автоматически. Последний вариант рекомендуется, потому что в противном случае трудно добиться переносимости; диапазоны доступных адресов в разных системах отличаются.
Параметр prot
используется для установки прав доступа к сегменту памяти. Он представляет собой результат поразрядной операции or, примененной к следующим константам:
□ PROT_READ
– сегмент может читаться;
□ PROT_WRITE
– в сегмент можно писать;
□ PROT_EXEC
– сегмент может выполняться;
□ PROT_NONE
– к сегменту нет доступа.
Параметр flags
контролирует, как изменения, сделанные программой в сегменте, отражаются в других местах; его возможные значения приведены в табл. 3.7.
Таблица 3.7
MAP_PRIVATE | Сегмент частный, изменения локальные |
MAP_SHARED | Изменения сегмента переносятся в файл |
MAP_FIXED | Сегмент должен располагаться по заданному адресу addr |
Функция msync
вызывает запись изменений в части или во всем сегменте памяти обратно а отображенный файл (или считывание из файла).
#include
int msync(void *addr, size_t len, int flags);
Корректируемая часть сегмента задается передачей начального адреса addr
и размера len
. Параметр flags
управляет способом выполнения корректировки с помощью вариантов, приведенных в табл. 3.8.
Таблица 3.8
MS_ASYNC | Выполнять запись асинхронно |
MS_SYNC | Выполнять запись синхронно |
MS_INVALIDATE | Обновить другие отражения этого файла так, чтобы они содержали изменения, внесенные этим вызовом |
Функция munmap
освобождает сегмент памяти.
#include
int munmap(void *addr, size_t len);
В программе mmap.с из упражнения 3.5 показан файл из структур, которые будут корректироваться с помощью функции mmap
и обращений в стиле массива. Ядро Linux версий, меньших 2.0, не полностью поддерживает применение функции mmap
. Программа работает корректно в системе Sun Solaris и других системах.
Упражнение 3.5. Применение функции mmap
1. Начните с определения структуры RECORD
и создайте NRECORDS
вариантов, в каждый из которых записывается собственный номер. Они будут добавлены в конец файла records.dat.
#include
#include
#include
#include
#include
typedef struct {
int integer;
char string[24];
} RECORD;
#define NRECORDS (100)
int main() {
RECORD record, *mapped;
int i, f;
FILE *fp;
fp = fopen(«records.dat», «w+»);
for (i=0; i
record.integer = i;
sprintf(record.string, «RECORD-%d», i);
fwrite(&record, sizeof(record), 1, fp);
}
fclose(fp);
2. Далее измените целое значение записи с 43 на 143 и запишите его в строку 43-й записи.
fp = fopen(«records.dat», «r+»);
fseek(fp, 43*sizeof(record), SEEK_SET);
fread(&record, sizeof(record), 1, fp);
record.integer =143;
sprintf(record.string, «RECORD-%d», record.integer);
fseek(fp, 43*sizeof(record), SEEK_SET);
fwrite(&record, sizeof(record), 1, fp);
fclose(fp);
3. Теперь отобразите записи в память и обратитесь к 43-й записи для того, чтобы изменить целое на 243 (и обновить строку записи), снова используя отображение в память.
f = open(«records.dat», O_RDWR);
mapped = (RECORD *)mmap(0, NRECORDS*sizeof(record),
PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);
mapped[43].integer = 243;
sprintf(mapped[43].string, «RECORD-%d», mapped[43].integer);
msync((void *)mapped, NRECORDS*sizeof(record), MS_ASYNC);
munmap((void *)mapped, NRECORDS*sizeof(record));
close(f);
exit(0);
}
В главе 13 вы встретитесь с еще одним средством совместного использования памяти – разделяемой памятью System V.
Резюме
В этой главе вы увидели, как ОС Linux обеспечивает прямой доступ к файлам и устройствам, как на этих низкоуровневых функциях строятся библиотечные функции, предоставляющие гибкие решения программных проблем. В результате вы смогли написать довольно мощную процедуру просмотра каталога с помощью нескольких строк программного кода.
Вы также узнали об обработке файлов и каталогов достаточно для того, чтобы превратить "сырое" приложение для работы с компакт-дисками, созданное в конце главы 2, в программу на языке С, применяющую более структурированное решение на базе файлов. Но на этом этапе вы не можете расширить функциональные возможности программы, поэтому мы отложим ее переработку до того времени, когда вы научитесь управлять экраном и клавиатурой, которые будут предметами обсуждения следующих двух глав.
Глава 4
Окружение Linux
Когда вы пишете программу для ОС Linux (или UNIX и UNIX-подобных систем), следует принимать во внимание то, что программа будет выполняться в многозадачной среде или многозадачном окружении. Это означает, что много программ будет выполняться одновременно и совместно использовать ресурсы компьютера, такие как память, дисковое пространство и циклы центрального процессора. Может даже существовать несколько экземпляров одной и той же программы, выполняющихся одновременно. Важно, чтобы эти программы не мешали друг другу, знали о своем окружении и могли действовать надлежащим образом, избегая конфликтов, таких как попытка писать в один и тот же файл одновременно с другой программой.
В этой главе рассматривается окружение, в котором действуют программы, как они его используют для получения информации об условиях функционирования и как пользователи программ могут изменять их поведение. В частности, в данной главе рассматриваются следующие темы:
□ передача аргументов в программы;
□ переменные окружения;
□ определение текущего времени;
□ временные файлы;
□ получение информации о пользователе и рабочем компьютере;
□ формирование и настройка регистрируемых сообщений;
□ выявление ограничений, накладываемых системой.
Аргументы программы
Когда в ОС Linux или UNIX выполняется программа на языке С, она начинается с функции main
. В таких программах функция main
объявляется следующим образом:
int main(int argc, char *argv[])
Здесь argc
– это счетчик аргументов программы, a argv
– массив символьных строк, представляющих сами аргументы.
Вы можете встретить программы на языке С для ОС Linux, просто объявляющие функцию main
как
main()
Этот вариант тоже работает, поскольку по умолчанию возвращаемому функцией значению будет назначен тип int
, а формальные параметры, которые в функции не применяются, не нуждаются в объявлении. Параметры argc
и argv
остаются на своем месте, но если вы не объявляете их, то и не можете их использовать.
Каждый раз, когда операционная система запускает новую программу, параметры argc
и argv
устанавливаются и передаются функции main
. Обычно эти параметры предоставляются другой программой, часто командной оболочкой, которая запросила у операционной системы запуск новой программы. Оболочка принимает заданную командную строку, разбивает её на отдельные слова и использует их для заполнения массива argv
. Помните о том, что до установки параметров argc
и argv
командная оболочка Linux обычно выполняет раскрытие метасимволов в аргументах, содержащих имена файлов, в то время как оболочка MS-DOS рассчитывает на то, что программы примут аргументы с метасимволами и выполнят собственную постановку.
Например, если мы дадим командной оболочке следующую команду:
$ myprog left right 'and center'
программа myprog запустит функцию main
с приведенными далее параметрами.
argc: 4
argv: {"myprog", «left», «right», «and center»}
Обратите внимание на то, что аргумент-счётчик содержит имя программы и в массив argv
оно включено как первый элемент argv[0]
. Поскольку в команде оболочки мы применили кавычки, четвертый аргумент представляет собой строку, содержащую пробелы.
Вам все это знакомо, если вы программировали на языке С стандарта ISO/ANSI, Аргументы функции main
соответствуют позиционным параметрам в сценариях командной оболочки: $0
, $1
и т.д. Язык ISO/ANSI С заявляет, что функция main
должна возвращать значение типа int
, спецификация X/Open содержит явное объявление, данное ранее.
Аргументы командной строки удобны для передачи данных программам. Например, вы можете применить их в приложениях баз данных для передачи имени базы данных, которую хотите использовать, что позволит вам применить одну и ту же программу для работы с несколькими базами данных. Многие утилиты также используют аргументы командной строки для изменения собственного поведения или установки опций. Вы обычно задаете эти так называемые флаги или переключатели с помощью аргументов командной строки, начинающихся со знака «дефис». Например, программа sort
принимает переключатель для изменения обычного порядка сортировки на обратный:
$ sort -r файл
Опции командной строки используются очень широко, и согласованное их применение будет реальной помощью тем, кто станет использовать вашу программу. В прошлом у каждой утилиты был свой подход к формированию опций командной строки, что приводило к некоторой путанице. Например, взгляните на то, каким способом приведенные далее команды принимают параметры:
$ tar cvfB /tmp/file.tar 1024
$ dd if=/dev/fd0 of=/trap/file.dd bs=18k
$ ps ax
$ gcc –help
$ ls -lstr
$ ls -l -s -t -r
Мы рекомендуем в ваших приложениях все переключатели командной строки начинать с дефиса и делать их односимвольными, состоящими из одной буквы или цифры. При необходимости опции, не содержащие последующих аргументов, могут группироваться вместе после общего дефиса. Таким образом, два только что приведенных примера с командой ls
соответствуют нашим рекомендациям. За каждой опцией может следовать любое необходимое ей значение как отдельный аргумент. Пример с программой dd
нарушает наше правило, поскольку использует многосимвольные опции, которые начинаются совсем не с дефисов (if=/dev/fd0
): в примере с программой tar
опции полностью оторваны от своих значений! Целесообразно добавлять более длинные и информативные имена переключателей как альтернативу односимвольных вариантов и использовать двойной дефис для их выделения. Таким образом, у нас могут быть два варианта опции получения помощи: -h
и –help
.
Еще один недостаток некоторых программ – создание опции +x
(например) для выполнения функции, противоположной -х
. В главе 2 мы применяли команду set -о xtrace
для включения отслеживания действий командной оболочки и команду set +о xtrace
для выключения этого режима.
Вы, вероятно, можете сказать, что запомнить порядок и назначение всех этих программных опций достаточно трудно без необходимости освоения вызывающих идиосинкразию форматов. Часто единственный выход – применение опции -h
(от англ. help) или страниц интерактивного справочного руководства (man
), если программист предоставил одну из этих возможностей. Чуть позже в этой главе мы покажем, что функция getopt
предоставляет изящное решение этих проблем. А сейчас, тем не менее, в упражнении 4.1 давайте посмотрим, как передаются аргументы программы.
Упражнение 4.1. Аргументы программы
Далее приведена программа args.c, проверяющая собственные аргументы.
#include
#include
int main(int argc, char *argv[]) {
int arg;
for (arg = 0; arg < argc; arg++) {
if (argv[arg][0] == '-')
printf(«option: %sn», argv[arg]+1);
else
printf(«argument %d: %sn», arg, argv[arg]);
}
exit(0);
}
Когда вы выполните эту программу, она просто выведет свои аргументы и определит опции. Суть в том, что программа принимает строковый аргумент и необязательный аргумент с именем файла, вводимый опцией -f
. Могут быть определены и другие опции.
$ ./args -i -lr 'hi there' -f fred.c
argument 0: ./args
option: i
option: lr
argument 3: hi there option: f
argument 5: fred.с
Как это работает
Программа просто использует аргумент-счетчик argc
для задания цикла, просматривающего все аргументы программы. Она находит опции поиском начального дефиса.
В данном примере, если мы предполагаем, что доступны опции -l
и -r
, то упускаем тот факт, что группа -lr
, возможно, должна интерпретироваться так же, как -l
и -r
.
В стандарте X/Open (который можно найти по адресу http://opengroup.org/) определено стандартное применение опций командной строки (Utility Syntax Guidelines, руководство по синтаксису утилит) и стандартный программный интерфейс для представления переключателей командной строки в программах на языке С: функция getopt
.