Измерение пропускной способности

image_print

NTK_RFC 0002

Bandwidth measurement

Измерение пропускной способности

PDF

В этом документе описаны изменения протокола Npv7. Текст будет включен в окончательную документацию, а пока его можно изменять, контактируя с разработчиками.

Проблема измерения качества каналов

В текущей версии Npv7 радар (Radar) измеряет качество канала, используя лишь время кругового обхода rtt1 и потери пакетов. Это явно не оптимально, поскольку пропускная способность не учитывается и канал с малой пропускной способностью (например, 20 Кбит/с), но с небольшой задержкой окажется лучше широкополосного канала с умеренной задержкой.

Улучшение

Узел должен включать в пакеты трассировки (Tracer Packet) не только rtt пройденных каналов, но и текущую их пропускную способность (полосу). Это позволит формировать трафик с учетом реальной пропускной способности каналов.

Измерение пропускной способности

Измерение включает 2 фазы. В первой измеряется общая полоса новых каналов узлами перехвата и назначения, а вторая фаза обеспечивает постоянный мониторинг пропускной способности. Отслеживание используемой полосы выполняется с помощью библиотеки libpcap.

Общая доступная полоса

        A <--> B <--> C

Узел B «ловит» трафик между узлами A и C. В конце ловушки B измеряет общую доступную полосу каналов B—>C и B—>A. Имеются разные методы измерения пропускной способности каналов. Первый и простейший заключается в передаче неопределенного числа случайных пакетов в течение нескольких секунд по адресу получателя на канале. Скорость передачи контролируется с помощью libpcap и регистрируется максимальное число переданных в секунду байтов как доступнеая для выгрузки (upload) полоса данного канала. Этот метод очень эффективен и измеренная полоса является реальной, а не аппроксимированной. Побочным эффектом является полная загрузка канала на несколько секунд.

Другой вариант более изыскан и использует методы Packet Pair и Packet Train, описанные в http://perform.wpi.edu/downloads/wbest/README и http://www-static.cc.gatech.edu/fac/Constantinos.Dovrolis/bw.html.

Поскольку каналы могут быть асимметричными, измерения повторяются также для A—>B и C—>B. В результате будет получена пропускная способность каналов A->B, B->A, C->B, B->C.

Контроль полосы в реальном масштабе времени

С помощью библиотеки libpcap узел B может отслеживать использование полосы каналов.

Max_link_bw

Общая доступная пропускная способность канала.

nflows

Текущее число потоков в канале. Потоком считается множество (stream) пакетов, связанных с конкретным соединением.

Текущую доступную полосу канала можно аппроксимировать выражением

link_avail_bw   = Max_link_bw/(nflows+1)

Такая аппроксимация выбрана потому, что метод управления трафиком TCP похож на алгоритм max-min и при большом числе потоков link_avail_bw является хорошим приближением.

Если радар сообщает о значительных вариациях текущей доступной полосы, передается новый запрос QSPN.

Задержка rtt

Каждый узел сети будет задерживать пересылку полученного пакета Tracer (TP) на время, обратно пропорциональное link_avail_bw. Таким образом, пакеты TP будут приниматься для эффективности. Побочным эффектом этого правила является игнорирование крайних случаев, когда маршруты с очень низким значением rtt будут иметь очень малую полосу bw или маршруты с оптимальной полосой bw будут иметь обчень большое значение rtt. Однако в реальном мире такие ситуации достаточно редки, поскольку rtt и the зачастую связаны между собой.

Дополнительная информация об эффективности пакетов TP приведена в документе QSPN v2.

Пропускная способность маршрута

Пропускная способность маршрута из S в D обозначается bw(S -> D) и равна пропускной способности наихудшего канала в пути. Например, для маршрута

S --64Mb/s--> R --64Mb/s--> T --32Mb/s--> O --100Mb/s--> I --100Mb/s--> D

пропускная способность составит bw(S -> D) = 32 Мбит/с.

Пакет TP должен запомнить единственное значение пропускной способности (_one_ bw) и это будет bw() текущего маршрута. Например, если S передает TP, то по получении этого пакета узлом T, сохраненная в нем пропускная способность будет bw(S->R->T)=64, но при достижении узла O, она сменится на bw(S→R→T→O)=32.

Отметим, что каждое значение bw приблизительно соответствует доступной полосе соответствующего канала (link_avail_bw). Например, запись S —64Mb/s—> R показывает, что текущая пропускная способность канала S—>R составляет приблизительно 64 Мбит/с.

Асимметричные маршруты

QSPN v1 предоставляет каждому узлу наилучший маршрут загрузки трафика (download) с каждого другого узла. Рассмотрим в качестве примера узлы S и D.

       1:   ,--<-<-<---.
           /            \
         S                D
           \            / 
       2:   `-->->->---'

Маршруты типа 1 являются лучшими маршрутами выгрузки (upload) из D в S, а маршруты типа 2 — лучшими для противоположного направления. QSPN дает S только маршруты типа 1, а D знает только маршруты типа 2. Если маршруты не симметричны, S при выгрузке в D будет использовать маршрут типа 1, который может иметь низкую производительность.

Решение очень просто — S при выгрузке большого блока данных будет запрашивать у D его маршруты D->S (тип 2), т. е. лучшие маршруты выгрузки из S в D.

Демон Netsukuku, используя libpcap, будет отслеживать пакеты, исходящие от localhost. Если пакеты отправлялись более 16 секунд, демон будет запрашивать у целевого узла лучшие маршруты выгрузки (upload) и добавлять их в свою таблицу маршрутизации. Таким образом, маршруты выгрузки будут запрашиваться лишь при необходимости.

Отметим, что в QSPN v2 имеется встроенная поддержка асимметричной маршрутизации.

Задержка и полоса

Может возникнуть ситуация, когда канал с хорошей пропускной способностью имеет высокую задержку. Для некоторых приложений малая задержка важна — к таким приложениям относится, например, ssh, где не так важна высокая скорость как малая задержка, чтобы получать быстрый отклик при вводе команд.

Узлам Netsukuku следует поддерживать три типа таблиц маршрутизации:

  • маршруты с наилучшей пропускной способностью;

  • маршруты с наименьшей задержкой;

  • маршруты с эффективной комбинацией пропускной способности и задержки.

Если протокол приложения использует значения TOS в своих пакетах IP, можно добавить правила маршрутизации и выбрать для протокола подходящую таблицу (например, вторую для ssh).

Возможен вариант хранения в ядре лишь усредненной (третьей) таблицы, поскольку она применяется наиболее часто. Конкретные маршруты с наилучшей пропускной способностью и задержкой можно добавлять в ядро лишь в момент их использования. Например, при запуске bittorrent для загрузки с узлов A,B,C монитор ntkd будет добавлять в ядро маршруты с наилучшей пропускной способностью для A,B,C.

IGS

Шлюз inet-gw, позволяющий совместно использовать свое соединение с Internet, замеряет свою доступную полосу Internet-соединения. Максимальная пропускная способность в обоих направлениях известна, поскольку пользователь должен задать ее в конфигурационном файле netsukuku.conf. Таким образом, отслеживание устройства, используемого принятым по умолчанию маршрутом в Internet, позволяет легко узнать доступную полосу.

Балансировка нагрузки

Балансировка нагрузки будет применяться всегда, поскольку маршруты добавляются в ядро с использованием опции multipath. Пакеты, передаваемые узлу, будут использовать разные маршруты.

Балансировка нагрузки внутри Netsukuku не зависит от проблем балансировки на IGS. Узлы ntk согласованы между собой и не используют NAT для взаимодействия внутри сети.


Перевод на русский язык

Николай Малых

nmalykh@protocols.ru

1Round-trip time.

Рубрика: Фрактальные сети | Комментарии к записи Измерение пропускной способности отключены

Библиотека Judy для работы с динамическими массивами

image_print

PDF

Компоненты библиотеки

Judy1 отображает индекс (Index — word) на бит.

JudyL отображает индекс (Index — word) на Value (word/указатель).

JudySL отображает индекс (строка с null-завершением) на Value.

JudyHS отображает индекс (массив байтов) размером Length на Value.

Judy представляет собой библиотеку C для создания и использования динамических массивов. Библиотека была предложена и реализована Doug Baskins из Hewlett-Packard.

Семейство функций и макросов поддерживает полностью динамические массивы, которые могут индексироваться 32- или 64-битовыми словами (в зависимости от размера word для процессора), строками с null-символом в конце или массивом байтов заданного размера. Динамический массив (разреженный) можно также считать функцией отображения или ассоциативной памятью.

Тип Word_t определен как typedef unsigned long int в файле Judy.h и должен иметь размер sizeof(void *), т. е. указателя.

В функциях Judy1 Index имет тип Word_t, а Value — просто бит (bit) или флаг наличия (отсутствия) Index в массиве. Этот можно рассматривать как огромное битовое поле (huge bitmap).

В функциях JudyL Index и Value имеют тип Word_t. В результате JudyL является чистым отображением слова на слово (указатель). JudySL и JudyHL базируются на этом свойстве JudyL.

В функциях JudySL Index является строкой с null-символом в конце, а ValueWord_t.

В функциях JudyHS Index является массивом байтов размера Length, а Value имеет тип Word_t. Дополнение (май 2004 г.) в Judy является гибридом, в котором используются лучшие качества методов хещирования и Judy. Автор надеется, что JudyHS послужит хорошей заменой методов хэширования, когда размер хэш-таблицы меняется при росте численности. Корректно настроенный метод хеширования со статическим размером таблицы и численностью непобедим по скорости. Обнако JudyHS будет работать лучше с численностью, отличающейся от оптимального размера хэш-таблицы. JudyHS не теряет производительности в тех случаях, где это известно для алгоритмов хэширования. JudyHS не использует связный список для обработки конфликтов хэш-значений, применяя взамен дерево массивов JudyL и виртуальную хэш-таблицу размером 4 миллиарда.

Массивы Judy являются быстрыми и небольшими по памяти, не требуют найтройки для широкого диапазона типов набора индексов (последовательные, периодические, кластерные, случайные). Judy обычно превосходит по скорости и экономии памяти другие модели хранения данных, такие как skip-списки, связные списки, двоичные, троичные и b-деревья и даже хэширование, а также повышает эффективность работы при очень больших размерах данных.

Массив Judy создается просто путем определения пустого (null) указателя, а затем по этому указателю сохраняется (вставляется) первый элемент массива. Используемая массивом Judy память примерно пропорциональна численности (количеству элементов).

Judy имеет два интерфейса API — макросы C и вызовы функций. Поскольку макросы иногда быстрее и имеют более простой интерфейс обработки ошибок по сравнению с эквивалентными функциями, они являются предпочтительным вариантом.

Поскольку исходный (пустой) массив Judy представляется null-указателем, можно создать массив массивов Judy. Т. е. значениями массива Judy (Value), кроме Judy1, могут быть указатели на другие массивы Judy. Это существенно упрощает создание массивов произвольной размерности или значения Index (массивы JudySL и JudyHS используют для этого JudyL).

Файлы

/usr/share/doc/Judy/ — страницы руководства в формате HTML;
/usr/share/doc/Judy/demo/ — примеры файлов исходного кода.

Ошибки

На упрощение обработки ошибок в Judy было затрачено много сил и времени, что позволило сохранить гибкость и функциональность. Тема обработки ошибок достаточно скучна, но упускать ее нельзя. Из описанных здесь методов рекомендуется применять второй. Он создает наиболее быстрый код, используя минимальный объем памяти и требует написания дополнительного кода лишь для функций вставки и удаления. Метод совместим с двумя другими и предназначен для создания кода, который может обрабатывать отказы malloc() иначе, чем принято по умолчанию в Judy. Если принятый по умолчанию метод Judy работает хорошо, имеет смысл применять его.

Имеется две категории ошибок, возвращаемых Judy (и другими динамическими ADT):

  1. Ошибки пользовательских программ, такие как повреждение памяти или непригодные указатели.

  2. Нехватка памяти (отказ malloc()) при вставке (Insert, Set) или удалении (Delete, Unset) для изменения массива Judy. Для вставки или удаления не всегда применяется функция malloc(), поэтому операции могут быть успешными даже при отказе malloc().

Имеется три метода обработки ошибок при использовании макросов

  1. Принятый по умолчанию метод выводит сообщение об ошибке в stderr. Например,

File 'YourCfile.c', line 1234: JudyLIns(), JU_ERRNO_* == 2, ID == 321

Это говорит об ошибке в строке 321 функции JudyLIns(). Проблема возникла в строке 1234 файла YourCfile.c, где произошел отказ JLI(). JU_ERRNO_* == 2 указывает JU_ERRNO_NOMEM (определена в файле Judy.h). Идентификатор ID указывает номер строки исходного файла, где произошла ошибка. Программа была прервана с возвратом exit(1);. По умолчанию обе категории ошибок Judy обрабатываются этим методом.

  1. Запрет обработки ошибок в макросах

    Когда в программе «нет ошибок», сообщения могут выдаваться лишь для отказов malloc() и все возвращаемые ошибки можно считать такими отказами. Используя показанный ниже оператор #define, можно отключить все проверки и вывод ошибок. К коду, который может приводить к отказам malloc(), потребуется добавить специальный код. Judy сохраняет в массиве данные, присутствовавшие до вызова, в случаях отказа malloc()1.

#define JUDYERROR_NOTEST 1

в программном коде или

cc -DJUDYERROR_NOTEST sourcefile -lJudy

в командной строке.

//Пример использования метода 2 в программе.
    
JLI(PValue, PLArray, Index);
if (PValue == PJERR) goto out_of_memory_handling;
...

JLD(RC_int, PLArray, Index);
if (RC_int == JERR) goto out_of_memory_handling;
...

J1S(RC_int, P1Array, Index);
if (RC_int == JERR) goto out_of_memory_handling;
...

J1U(RC_int, P1Array, Index);
if (RC_int == JERR) goto out_of_memory_handling;
...

Отметим, что без определения JUDYERROR_NOTEST операция goto out_of_memory_handling не будет выполняться и компилятор исключит ее при оптимизации. Будет использован принятый по умолчанию метод использования макроса для вывода сообщения об ошибке, как описано выше. При определении JUDYERROR_NOTEST операция goto out_of_memory_handling будет выполняться в случае возникновения ошибки (отказ malloc()).

  1. Заданный пользователем макрос JUDYERROR()

    Макрос JUDYERROR(), определенный в файле Judy.h обеспечивает гибкую обработку ошибок, позволяющую программе использовать макросы массивов Judy вместо вызова функций. Можно использовать свой макрос JUDYERROR(), соответствующий реальным задачам. Ниже приведен пример возможного варианта взамен принятого по умолчанию. Он служит для различения двух типов ошибок и явно1 проверки остальных ошибок JU_ERRNO_NOMEM, которые могут возникать в программе.

// Пример Judy macro API для продолжения работы при нехватке памяти,
// вывода сообщения и возврата exit(1) при возникновении ошибки.

#ifndef JUDYERROR_NOTEST
#include <stdio.h>  // нужен для fprintf()

// Макрос, используемый Judy macro APIs для возврата кода -1:

#define JUDYERROR(CallerFile, CallerLine, JudyFunc, JudyErrno, JudyErrID) \
{                                                                         \
    if ((JudyErrno) != JU_ERRNO_NOMEM) /* не отказ malloc() */         	  \
    {                                                                     \
        (void) fprintf(stderr, "File '%s', line %d: %s(), "               \
            "JU_ERRNO_* == %d, ID == %d\n",                               \
            CallerFile, CallerLine,                                       \
            JudyFunc, JudyErrno, JudyErrID);                              \
        exit(1);                                                          \
    }                                                                     \
}
#endif // не определено JUDYERROR_NOTEST

Этот макрос обработки ошибок должен включаться в программу до оператора #include <Judy.h>.

Judy1

Макросы Judy1

Макросы Judy1 представляют собой библиотеку C для создания и использования динамического массива битов. Индексом массива может служить любое значение слова (word).

Массив Judy1 эквивалентен массиву или отображению (map) битов, адресуемому Index (ключ). Массив может быть разреженным (sparse), а Index может быть любым значением (Value) размера word. Наличие индекса представляет установленный (set) бит, а такой бит представляет наличие индекса. Отсутствие индекса представляет сброшенный (unset) бит, а сброшенный бит представляет отсутствие индекса.

Массив Judy1 выделяется с указателем NULL

Pvoid_t PJ1Array = (Pvoid_t) NULL;

Память для поддержки массива выделяется при установке бита и освобождается при его сбросе. Если указатель Judy1 (PJ1Array) имеет значение NULL, это говорит, что все биты сброшены (для массива Judy1 не требуется памяти).

Как и обычные массивы Judy1, не имеет дубликатов индексов.

При использовании описанных здесь макросов вместо вызова функций Judy1 принятая по умолчанию обработка ошибок передает сообщение на стандартный вывод ошибок и завершает программу с кодом exit(1). Другие методы обработки ошибок рассмотрены в разделе Ошибки.

Поскольку макросы иногда быстрее и включают более эффективную обработку ошибок по сравнению с функциями, их применение является предпочтительным в Judy1.

Синтаксис

cc [flags] sourcefiles -lJudy
#include <Judy.h>

int     Rc_int;                          // Код возврата - integer
Word_t  Rc_word;                         // Код возврата - unsigned word
Word_t  Index, Index1, Index2, Nth;

Pvoid_t PJ1Array = (Pvoid_t) NULL;       // Инициализация массива Judy1

J1S( Rc_int,  PJ1Array, Index);          // Judy1Set()
J1U( Rc_int,  PJ1Array, Index);          // Judy1Unset()
J1T( Rc_int,  PJ1Array, Index);          // Judy1Test()
J1C( Rc_word, PJ1Array, Index1, Index2); // Judy1Count()
J1BC(Rc_int,  PJ1Array, Nth, Index);     // Judy1ByCount()
J1FA(Rc_word, PJ1Array);                 // Judy1FreeArray()
J1MU(Rc_word, PJ1Array);                 // Judy1MemUsed()
J1F( Rc_int,  PJ1Array, Index);          // Judy1First()
J1N( Rc_int,  PJ1Array, Index);          // Judy1Next()
J1L( Rc_int,  PJ1Array, Index);          // Judy1Last()
J1P( Rc_int,  PJ1Array, Index);          // Judy1Prev()
J1FE(Rc_int,  PJ1Array, Index);          // Judy1FirstEmpty()
J1NE(Rc_int,  PJ1Array, Index);          // Judy1NextEmpty()
J1LE(Rc_int,  PJ1Array, Index);          // Judy1LastEmpty()
J1PE(Rc_int,  PJ1Array, Index);          // Judy1PrevEmpty()

Определения

J1S(Rc_int, PJ1Array, Index); // Judy1Set()

Устанавливает бит Index в массиве Judy1 PJ1Array. Возвращает Rc_int = 1 при сброшенном бите Index (нет ошибки) и 0 при установленном ранее бите (ошибка).

J1U(Rc_int, PJ1Array, Index); // Judy1Unset()

Сбрасывает бит Index в массиве Judy1 PJ1Array. Возвращает Rc_int = 1 при установленном ранее бите Index (нет ошибки) и 0 при сброшенном бите (ошибка).

J1T(Rc_int, PJ1Array, Index); // Judy1Test()

Проверяет установку бита Index в массиве Judy1 PJ1Array. Возвращает Rc_int = 1 при установленном бите Index (Index присутствует) и 0 при сброшенном бите (Index отсутствует).

J1C(Rc_word, PJ1Array, Index1, Index2); // Judy1Count()

Считает число индексов, присутствующих в массиве Judy1 PJ1Array между значениями Index1 и Index2 (включительно). Возвращает в Rc_word число интексов. Возврат Value = 0 может быть корректным для счетчика или указывать особый случай полностью заполненного массива (только на 32-битовых машинах). Более подробно это рассмотрено в описании функции Judy1Count(). Для подсчета числа присутствующих в массиве Judy1 индексов (численность) служит

J1C(Rc_word, PJ1Array, 0, -1);

Отметим, что -1 указывает максимальный индекс (все 1).

J1BC(Rc_int, PJ1Array, Nth, Index); // Judy1ByCount()

Находит Nth-й индекс, который присутствует в массиве Judy1 PJ1Array (Nth = 1 возвращает первый имеющийся индекс). Для указания последнего индекса в полностью заполненном массиве (присутствуют все индексы, что бывает редко) используется Nth = 0. Возвращает Rc_int = 1 и Index = Nth, если индекс найден, и Rc_int = 0 в противном случае (Value в Index не содержит полезной информации).

J1FA(Rc_word, PJ1Array); // Judy1FreeArray()

Освобождает весь массив Judy1 PJ1Array (быстрее цикла J1N(), J1U()). Возвращает в Rc_word число освобожденных битов и устанавливает PJ1Array = NULL.

J1MU(Rc_word, PJ1Array); // Judy1MemUsed()

Возвращает в Rc_word число байтов памяти, занятых массивом Judy1 PJ1Array. Это очень быстрый макрос и его можно применять после J1S() или J1U() практически без снижения производительности.

Макросы поиска Judy1

Средства поиска в Judy1 позволяют найти установленные или сброшенные биты в массиве. Поиск может быть включающим или исключающим и выполняется в обоих направлениях. Все средства поиска используют похожие последовательности вызова. При успешном поиске в Rc_int возвращается 1 вместе с найденным индексом Index. При неудачном поиске Rc_int = 0, а Index не содержит полезной информации. Код возврата Rc_int должен проверяться до использования возвращенного Index, поскольку при поиске возможны отказы.

J1F(Rc_int, PJ1Array, Index); // Judy1First()

Включительный поиск первого присутствия индекса не меньше указанного Index. Для поиска первого элемента служит Index = 0. J1F() обычно служит для начала упорядоченного сканирования индексов в массиве Judy1.

J1N(Rc_int, PJ1Array, Index); // Judy1Next()

Исключительный поиск первого присутствия индекса больше указанного Index. J1N() обычно служит для продолжения упорядоченного сканирования индексов в массиве Judy1 или поиска «соседа» указанного индекса.

J1L(Rc_int, PJ1Array, Index); // Judy1Last()

Включительный поиск последнего присутствия индекса не больше указанного Index. Для поиска последнего индекса в массиве используется Index = -1 (все 1). J1L() обычно служит для начала упорядоченного сканирования в обратном направлении индексов в массиве Judy1.

J1P(Rc_int, PJ1Array, Index); // Judy1Prev()

Исключительный поиск предыдущего индекса меньше указанного Index. J1P() обычно служит для продолжения упорядоченного сканирования в обратном направлении индексов в массиве Judy1 или поиска «соседа» указанного индекса.

J1FE(Rc_int, PJ1Array, Index); // Judy1FirstEmpty()

Включительный поиск первого отсутствия индекса не меньше указанного Index. Для поиска первого отсутствующего элемента служит Index = 0.

J1NE(Rc_int, PJ1Array, Index); // Judy1NextEmpty()

Исключительный поиск первого отсутствия индекса больше указанного Index.

J1LE(Rc_int, PJ1Array, Index); // Judy1LastEmpty()

Включительный поиск последнего присутствия индекса не больше указанного Index. Для поиска последнего отсутствующего индекса в массиве используется Index = -1 (все 1)

J1PE(Rc_int, PJ1Array, Index); // Judy1PrevEmpty()

Исключительный поиск предыдущего индекса меньше указанного Index.

Пример

В приведенном ниже примере ошибки при вызове J1S() или J1U() вызывают пользовательскую процедуру process_malloc_failure. Этого не требуется при использовании принятого по умолчанию макроса JUDYERROR(), поскольку он завершает программу при любом отказе, включая ошибки malloc().

#include <stdio.h>
#include <Judy.h>

int main()  {                    // Пример программы с Judy1 macro API
   Word_t Index;                 // индекс (или ключ)
   Word_t Rcount;                // счетчик индексов (установленных битов)
   Word_t Rc_word;               // возвращаемое значение (word)
   int    Rc_int;                // возвращаемое логическое значение (0 или 1)

   Pvoid_t PJ1Array = (Pvoid_t) NULL; // инициализация массива Judy1

   Index = 123456;
   J1S(Rc_int, J1Array, Index);  // Установка бита 123456
   if (Rc_int == JERR) goto process_malloc_failure;
   if (Rc_int == 1) printf("OK - bit successfully set at %lu\n", Index);
   if (Rc_int == 0) printf("BUG - bit already set at %lu\n", Index);

   Index = 654321;
   J1T(Rc_int, J1Array, Index);  // проверка установки бита 654321
   if (Rc_int == 1) printf("BUG - set bit at %lu\n", Index);
   if (Rc_int == 0) printf("OK - bit not set at %lu\n", Index);

   J1C(Rcount, J1Array, 0, -1);  // счетчик установленных битов массива
   printf("%lu bits set in Judy1 array\n", Rcount);

   Index = 0;
   J1F(Rc_int, J1Array, Index);  // найти первый бит, установленный в массиве
   if (Rc_int == 1) printf("OK - first bit set is at %lu\n", Index);
   if (Rc_int == 0) printf("BUG - no bits set in array\n");

   J1MU(Rc_word, J1Array);       // объем используемой памяти
   printf("%lu Indexes used %lu bytes of memory\n", Rcount, Rc_word);

   Index = 123456;
   J1U(Rc_int, J1Array, Index);  // сбросить бит 123456
   if (Rc_int == JERR) goto process_malloc_failure;
   if (Rc_int == 1) printf("OK - bit successfully unset at %lu\n", Index);
   if (Rc_int == 0) printf("BUG - bit was not set at %lu\n", Index);

   return(0);
}

Функции Judy1

Функции Judy1 обеспечивают библиотеку C для работы с динамическими массивами битов, в которых индексом служит любое значение типа word.

Для всех функций имеются эквивалентные макросы. Поскольку макросы иногда работают быстрее и обеспечивают более простой контроль ошибок, использование макросов предпочтительней вызова функций Judy1. Определения функций представлены ниже для полноты.

Одной из сложностей, связанных с вызовами функций Judy1, является решение вопроса о передаче указателя или его адреса. Поскольку функции, меняющие массив Judy1, должны менять и указатель на него, нужно передавать адрес указателя, а не сам указатель. Это ведет к трудно обнаруживаемым ошибкам в программах. На практике макросы позволяют компилятору обнаруживать программные ошибки при передаче указателей вместо адресов.

При вызове функций Judy1 используется дополнительный параметр по сравнению с соответствующими макросами. Этим параметром является указатель на структуру ошибки или NULL (если детали ошибок не возвращаются).

Ниже функции описаны в терминах их использования макросами (для случая #define JUDYERROR_NOTEST 1). Это является рекомендуемым использованием макросов после завершения отладки программ. Если макрос JUDYERROR_NOTEST не задан, объявляется структура ошибки для хранения информации, возвращаемой из функций Judy1 при возникновении ошибок.

Следует обращать внимание на размещение символа & в разных функциях.

Синтаксис

int    Judy1Set(PPvoid_t PPJ1Array, Word_t Index, PJError_t PJError);
int    Judy1Unset(PPvoid_t PPJ1Array, Word_t Index, PJError_t PJError);
int    Judy1Test(Pcvoid_t PJ1Array, Word_t Index, PJError_t PJError);
Word_t Judy1Count(Pcvoid_t PJ1Array, Word_t Index1, Word_t Index2, PJError_t PJError);
int    Judy1ByCount(Pcvoid_t PJ1Array, Word_t Nth, Word_t * PIndex, PJError_t PJError);
Word_t Judy1FreeArray(PPvoid_t PPJ1Array, PJError_t PJError);
Word_t Judy1MemUsed(Pcvoid_t PJ1Array);
int    Judy1First(Pcvoid_t PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1Next(Pcvoid_t PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1Last(Pcvoid_t PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1Prev(Pcvoid_t PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1FirstEmpty(Pcvoid_t PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1NextEmpty(Pcvoid_t PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1LastEmpty(Pcvoid_t PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1PrevEmpty(Pcvoid_t PJ1Array, Word_t * PIndex, PJError_t PJError);

Определения

Judy1Set(&PJ1Array, Index, &JError)

#define J1S(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Set(&PJ1Array, Index, PJE0)

Judy1Unset(&PJ1Array, Index, &JError)

#define J1U(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Unset(&PJ1Array, Index, PJE0)

Judy1Test(PJ1Array, Index, &JError)

#define J1T(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Test(PJ1Array, Index, PJE0)

Judy1Count(PJ1Array, Index1, Index2, &JError)

#define J1C(Rc_word, PJ1Array, Index1, Index2) \
   Rc_word = Judy1Count(PJ1Array, Index1, Index2, PJE0)

Возвращенное значение 0 может указывать ошибкой, быть пригодным значением счетчика или указывать особый случай полностью заполненного массива (только для 32-битовых машин). При необходимости для устранения неоднозначности можно использовать приведенный ниже код.

JError_t JError;
Rc_word = Judy1Count(PJ1Array, Index1, Index2, &JError);
if (Rc_word == 0)	{
    if (JU_ERRNO(&JError) == JU_ERRNO_NONE)
        printf("Judy1 array population == 0\n");
    if (JU_ERRNO(&JError) == JU_ERRNO_FULL)
        printf("Judy1 array population == 2^32\n");
    if (JU_ERRNO(&JError) == JU_ERRNO_NULLPPARRAY)
        goto NullArray;
    if (JU_ERRNO(&JError) >  JU_ERRNO_NFMAX)
        goto Null_or_CorruptArray;
}

Judy1ByCount(PJ1Array, Nth, &Index, &JError)

#define J1BC(Rc_int, PJ1Array, Nth, Index) \
   Rc_int = Judy1ByCount(PJ1Array, Nth, &Index, PJE0)

Judy1FreeArray(&PJ1Array, &JError)

#define J1FA(Rc_word, PJ1Array) \
   Rc_word = Judy1FreeArray(&PJ1Array, PJE0)

Judy1MemUsed(PJ1Array)

#define J1MU(Rc_word, PJ1Array) \
   Rc_word = Judy1MemUsed(PJ1Array)

Judy1First(PJ1Array, &Index, &JError)

#define J1F(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1First(PJ1Array, &Index, PJE0)

Judy1Next(PJ1Array, &Index, &JError)

#define J1N(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Next(PJ1Array, &Index, PJE0)

Judy1Last(PJ1Array, &Index, &JError)

#define J1L(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Last(PJ1Array, &Index, PJE0)

Judy1Prev(PJ1Array, &Index, &JError)

#define J1P(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Prev(PJ1Array, &Index, PJE0)

Judy1FirstEmpty(PJ1Array, &Index, &JError)

#define J1FE(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1FirstEmpty(PJ1Array, &Index, PJE0)

Judy1NextEmpty(PJ1Array, &Index, &JError)

#define J1NE(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1NextEmpty(PJ1Array, &Index, PJE0)

Judy1LastEmpty(PJ1Array, &Index, &JError)

#define J1LE(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1LastEmpty(PJ1Array, &Index, PJE0)

Judy1PrevEmpty(PJ1Array, &Index, &JError)

#define J1PE(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1PrevEmpty(PJ1Array, &Index, PJE0)

Определения всех функций Judy, типов Pvoid_t, Pcvoid_t, PPvoid_t, Word_t, JError_t и PJError_t, констант NULL, JU_ERRNO_*, JERR и PJE0 приведены в файле Judy.h (/usr/include/Judy.h). Следует отметить, что вызывающие должны определять массивы Judy1 типа Pvoid_t, который можно передать функциям, принимающим Pcvoid_t (constant Pvoid_t), а также по адресу в функции, принимающие PPvoid_t.

JudyL

Макросы JudyL

Макросы JudyL представляют собой библиотеку C для создания и использования динамического массива слов (word). Индексом массива может служить любое значение слова (word).

Массив JudyL эквивалентен массиву значений Value типа word, адресуемому Index (ключ). Массив может быть разреженным (sparse), а Index может быть любым значением (Value) размера word. Память для поддержки массива выделяется при вставке пары «индекс-значение» и освобождается при ее удалении. Массив JudyL можно также считать отображением слова на другое слово (указатель).

Если указатель Judy1 (PJ1Array) имеет значение NULL, это говорит, что все биты сброшены (для массива Judy1 не требуется памяти).

Как и обычные массивы, JudyL не имеет дубликатов индексов.

Значение может применяться как скаляр, указатель на структуру или блок данных (включая другой массив Judy).

Массив JudyL выделяется с указателем NULL

Pvoid_t PJLArray = (Pvoid_t) NULL;

При использовании описанных здесь макросов вместо вызова функций JudyL принятая по умолчанию обработка ошибок передает сообщение на стандартный вывод ошибок и завершает программу с кодом exit(1). Другие методы обработки ошибок рассмотрены в разделе Ошибки.

Поскольку макросы иногда быстрее и включают более эффективную обработку ошибок по сравнению с функциями, их применение является предпочтительным в JudyL.

Синтаксис

cc [flags] sourcefiles -lJudy

#include <Judy.h>

int     Rc_int;                          // Код возврата - integer
Word_t  Rc_word;                         // Код возврата - unsigned word
Word_t  Index, Index1, Index2, Nth;

PWord_t  PValue;                         // Указатель на возвращаемое значение
Pvoid_t PJLArray = (Pvoid_t) NULL;       // Инициализация массива JudyL

JLI( PValue,  PJLArray, Index);          // JudyLIns()
JLD( Rc_int,  PJLArray, Index);          // JudyLDel()
JLG( PValue,  PJLArray, Index);          // JudyLGet()
JLC( Rc_word, PJLArray, Index1, Index2); // JudyLCount()
JLBC(PValue,  PJLArray, Nth, Index);     // JudyLByCount()
JLFA(Rc_word, PJLArray);                 // JudyLFreeArray()
JLMU(Rc_word, PJLArray);                 // JudyLMemUsed()
JLF( PValue,  PJLArray, Index);          // JudyLFirst()
JLN( PValue,  PJLArray, Index);          // JudyLNext()
JLL( PValue,  PJLArray, Index);          // JudyLLast()
JLP( PValue,  PJLArray, Index);          // JudyLPrev()
JLFE(Rc_int,  PJLArray, Index);          // JudyLFirstEmpty()
JLNE(Rc_int,  PJLArray, Index);          // JudyLNextEmpty()
JLLE(Rc_int,  PJLArray, Index);          // JudyLLastEmpty()
JLPE(Rc_int,  PJLArray, Index);          // JudyLPrevEmpty()

JLI(PValue, PJLArray, Index) // JudyLIns()

Вставляет Index и Value в массив JudyL PJLArray. При успешной вставке устанавливается значение Value = 0. Если Index уже присутствует, Value не меняется. Возвращает указатель PValue на значение Value, который программа может использовать для чтения или изменения Value, пока не будет выполнен следующий макрос JLI() (вставка), JLD() (удаление) или JLFA() (очистка массива) для массива PJLArray. Например,

*PValue = 1234;
Value = *PValue;

Возвращает в PValue значение PJERR, если возникает отказ malloc(). Отметим, что макросы JLI() и JLD() реорганизуют массив JudyL, поэтому PValue из предыдущего вызова JudyL становится непригодным и должно быть обновлено.

JLD(Rc_int, PJLArray, Index) // JudyLDel()

Удаляет пару IndexValue из массива JudyL. Макрос возвращает Rc_int = 1 при успешном удалении и Rc_int = 0, если Index отсутствует. При отказе malloc() устанавливается Rc_int = JERR.

JLG(PValue, PJLArray, Index) // JudyLGet()

Возвращает указатель PValue, связанный с Index в массиве PJLArray. Макрос возвращает значение Pvalue, указывающее на Value. При отсутствии Index возвращается PValue = NULL, а пр отказе malloc() — PValue = PJERR.

JLC(Rc_word, PJLArray, Index1, Index2) // JudyLCount()

Возвращает число индексов, имеющихся в массиве JudyL PJLArray между значениями Index1 и Index2 (включительно). Rc_word содержит значение счетчика. Значение 0 может указывать отсутствие индексов. Для подсчета всех индексов в массиве JudyL используется вызов

JLC(Rc_word, PJLArray, 0, -1);

JLBC(PValue, PJLArray, Nth, Index) // JudyLByCount()

Находит Nth-й, присутствующий в массиве JudyL PJLArray (при Nth = 1 возвращается первый имеющийся индекс).

Возвращает PValue с указанием на Value и Index, установленные для имеющегося Nth-ого индекса или PValue = NULL, если индекс отсутствует (значение Index в этом случае не имеет смысла).

JLFA(Rc_word, PJLArray) // JudyLFreeArray()

По указателю на массив JudyL полностью освобождает его гораздо быстрее чем в цикле JLN(), JLD(). Возвращает в Rc_word число освобожденных байтов и устанавливает PJLArray = NULL.

JLMU(Rc_word, PJLArray) // JudyLMemUsed()

Возвращает в Rc_word число байтов, выделенных malloc() для PJLArray. Это очень быстрый макрос и его можно использовать перед или после JLI() или JLD() практически без влияния на производительность.

Средства поиска JudyL

Макросы JLF(), JLN(), JLL(), JLP() позволяют выполнять поиск в массиве. Поиск может быть включительным или исключительным и выполняться в обоих направлениях. При успешном поиске Index содержит найденный индекс, а PValue — указатель на значение (Value) для найденного Index. Если поиск не дал результата, возвращается PValue = NULL, а Index не содержит полезной информации. Указатель PValue должен проверяться до использования Index, поскольку при поиске возможны отказы.

Макросы JLFE(), JLNE(), JLLE(), JLPE() позволяют искать отсутствующие (пустые) индексы в массиве. Поиск может быть включительным или исключительным и выполняется в обоих направлениях. При успешном поиске возвращается Index отсутствующего индекса и Rc_int = 1. При неудаче возвращается Rc_int = 0, а Index не содержит полезной информации. Значение Rc_int должно проверяться до использования Index, поскольку при поиске возможен отказ.

JLF(PValue, PJLArray, Index) // JudyLFirst()

Включительный поиск первого присутствующего индекса не меньше переданного Index. При Index = 0 отыскивается первый имеющийся индекс. JLF() обычно применяется для начала упорядоченного сканирования имеющихся в JudyL индексов.

JLN(PValue, PJLArray, Index) // JudyLNext()

Исключительный поиск первого присутствующего индекса больше переданного Index. JLN() обычно служит для продолжения упорядоченного сканирования индекса JudyL или поиска «соседа» данного индекса.

JLL(PValue, PJLArray, Index) // JudyLLast()

Включительный поиск последнего присутствующего индекса не больше переданного Index. При Index = -1 (все 1) отыскивается последний индекс массива. JLL() обычно применяется для упорядоченного сканирования присутствующих в массиве JudyL индексов в обратном направлении.

JLP(PValue, PJLArray, Index) // JudyLPrev()

Исключительный поиск предыдущего индекса меньше переданного Index. JLP() обычно служит для продолжения упорядоченного сканирования присутствующих в массиве JudyL индексов в обратном направлении.

JLFE(Rc_int, PJLArray, Index) // JudyLFirstEmpty()

Включительный поиск первого отсутствующего индекса не меньше переданного Index. Index = 0 задает поиск первого отсутствующего в массиве индекса.

JLNE(Rc_int, PJLArray, Index) // JudyLNextEmpty()

Исключительный поиск следующего отсутствующего индекса больше переданного Index.

JLLE(Rc_int, PJLArray, Index) // JudyLLastEmpty()

Включительный поиск последнеого отсутствующего индекса не больше переданного Index. При Index = -1 (все 1) отыскивается последний индекс, отсутствующий в массиве.

JLPE(Rc_int, PJLArray, Index) // JudyLPrevEmpty()

Исключительный поиск предыдущего индекса меньше переданного Index.

Многомерные массивы JudyL

Запись указателя на другой массив JudyL в Value массива JudyL обеспечивает простой способ поддержки динамических многомерных массивов. Такие массивы (деревья), созданные с помощью JudyL, являются очень быстрыми и нетребовательными к памяти (фактически, так реализованы JudySL и JudyHS). Таким способом можно реализовать произвольную размерность. Для завершения числа измерений (дерева), указатель в Value помечается как не указывающий на другой массив Judy с помощью флага JLAP_INVALID в младших битах указателя2. После удаления флага JLAP_INVALID значение используется как указатель на пользовательские данные. Флаг JLAP_INVALID определен в файле Judy.h.

Ниже приведен фрагмент кода, который можно использовать для проверки указания на другой массив JudyL.

PValue = (PWord_t)PMultiDimArray;

for (Dim = 0; ;Dim++)	{
   if (PValue == (PWord_t)NULL) goto IndexNotFound;

   /* Переход к следующему измерению в массиве. */
   JLG(PValue, (Pvoid_t)*PValue, Index[Dim]);

   /* Проверка указателя на пользовательский буфер. */
   if (*PValue & JLAP_INVALID)) break;
}
UPointer = (UPointer_t) (*PValue & ~JLAP_INVALID);  // mask and cast.
printf("User object pointer is 0x%lx\n", (Word_t) UPointer);
       ...

Этот код работает, поскольку malloc() гарантирует возврат указателя с младшими битами, имеющими значение 0x0. Флаг JLAP_INVALID должен удаляться перед использованием указателя.

Пример

Считывание последовательности пар «индекс-значение» со стандартного ввода, сохранение в массиве и вывод в отсортированном виде.

#include <stdio.h>
#include <Judy.h>

Word_t   Index;                     // индекс массива
Word_t   Value;                     // значение элемента массива
Word_t * PValue;                    // указатель на значение элемента массива
int      Rc_int;                    // код возврата

Pvoid_t  PJLArray = (Pvoid_t) NULL; // Инициализация массива JudyL

while (scanf("%lu %lu", &Index, &Value))	{
    JLI(PValue, PJLArray, Index);
    If (PValue == PJERR) goto process_malloc_failure;
    *PValue = Value;                // запись нового значения
}
// Затем перебираются все сохраненные индексы в порядке сортировки сначала по возрастанию, 
// потом по убыванию и во втором проходе каждый индекс удаляется.

Index = 0;
JLF(PValue, PJLArray, Index);
while (PValue != NULL)	{
    printf("%lu %lu\n", Index, *PValue));
    JLN(PValue, PJLArray, Index);
}

Index = -1;
JLL(PValue, PJLArray, Index);
while (PValue != NULL)	{
    printf("%lu %lu\n", Index, *PValue));

    JLD(Rc_int, PJLArray, Index);
    if (Rc_int == JERR) goto process_malloc_failure;

    JLP(PValue, PJLArray, Index);
}

Функции JudyL

Функции JudyL обеспечивают библиотеку C для создания и работы с динамическими массивами слов (word), использующими в качестве индекса любые значения слов (word).

Для каждой функции имеется эквивалентный макрос. Поскольку макросы иногда быстрее и проще в обработке ошибок, они являются предпочтительными. Определения функций приведены здесь лишь для полноты.

Одной из сложностей, связанных с вызовами функций JudyL, является решение вопроса о передаче указателя или его адреса. Поскольку функции, меняющие массив JudyL, должны менять и указатель на него, нужно передавать адрес указателя, а не сам указатель. Это ведет к трудно обнаруживаемым ошибкам в программах. На практике макросы позволяют компилятору обнаруживать программные ошибки при передаче указателей вместо адресов.

При вызове функций JudyL используется дополнительный параметр по сравнению с соответствующими макросами. Этим параметром является указатель на структуру ошибки или NULL (если детали ошибок не возвращаются).

Ниже функции описаны в терминах их использования макросами (для случая #define JUDYERROR_NOTEST 1). Это является рекомендуемым использованием макросов после завершения отладки программ. Если макрос JUDYERROR_NOTEST не задан, объявляется структура ошибки для хранения информации, возвращаемой из функций JudyL при возникновении ошибок.

Следует обращать внимание на размещение символа & в разных функциях.

Синтаксис

PPvoid_t JudyLIns(PPvoid_t PPJLArray, Word_t    Index, PJError_t PJError);
int      JudyLDel(PPvoid_t PPJLArray, Word_t    Index, PJError_t PJError);
PPvoid_t JudyLGet(Pcvoid_t  PJLArray, Word_t    Index, PJError_t PJError);
Word_t   JudyLCount(Pcvoid_t PJLArray, Word_t Index1, Word_t Index2, PJError_t PJError);
PPvoid_t JudyLByCount(Pcvoid_t PJLArray, Word_t Nth, Word_t * PIndex, PJError_t PJError);
Word_t   JudyLFreeArray(PPvoid_t PPJLArray, PJError_t PJError);
Word_t   JudyLMemUsed(Pcvoid_t  PJLArray);
PPvoid_t JudyLFirst(Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
PPvoid_t JudyLNext(Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
PPvoid_t JudyLLast(Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
PPvoid_t JudyLPrev(Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
int      JudyLFirstEmpty(Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
int      JudyLNextEmpty(Pcvoid_t PJLArray, Word_t * PIndex, PJError_t PJError);
int      JudyLLastEmpty(Pcvoid_t PJLArray, Word_t * PIndex, PJError_t PJError);
int      JudyLPrevEmpty(Pcvoid_t PJLArray, Word_t * PIndex, PJError_t PJError);

Определения

JudyLIns(&PJLArray, Index, &JError)

#define JLI(PValue, PJLArray, Index)  \
   PValue = JudyLIns(&PJLArray, Index, PJE0)

JudyLDel(&PJLArray, Index, &JError)

#define JLD(Rc_int, PJLArray, Index)  \
   Rc_int = JudyLDel(&PJLArray, Index, PJE0)

JudyLGet(PJLArray, Index, &JError)

#define JLG(PValue, PJLArray, Index)  \
   PValue = JudyLGet(PJLArray, Index, PJE0)

JudyLCount(PJLArray, Index1, Index2, &JError)

#define JLC(Rc_word, PJLArray, Index1, Index2)  \
   Rc_word = JudyLCount(PJLArray, Index1, Index2, PJE0)

JudyLByCount(PJLArray, Nth, &Index, &JError)

#define JLBC(PValue, PJLArray, Nth, Index) \
   PValue = JudyLByCount(PJLArray, Nth, &Index, PJE0)

JudyLFreeArray(&PJLArray, &JError)

#define JLFA(Rc_word, PJLArray) \
   Rc_word = JudyLFreeArray(&PJLArray, PJE0)

JudyLMemUsed(PJLArray)

#define JLMU(Rc_word, PJLArray) \
   Rc_word = JudyLMemUsed(PJLArray)

JudyLFirst(PJLArray, &Index, &JError)

#define JLF(PValue, PJLArray, Index) \
   PValue = JudyLFirst(PJLArray, &Index, PJEO)

JudyLNext(PJLArray, &Index, &JError)

#define JLN(PValue, PJLArray, Index) \
   PValue = JudyLNext(PJLArray, &Index, PJEO)

JudyLLast(PJLArray, &Index, &JError)

#define JLL(PValue, PJLArray, Index) \
   PValue = JudyLLast(PJLArray, &Index, PJEO)

JudyLPrev(PJLArray, &Index, &JError)

#define JLP(PValue, PJLArray, Index) \
   PValue = JudyLPrev(PJLArray, &Index, PJEO)

JudyLFirstEmpty(PJLArray, &Index, &JError)

#define JLFE(Rc_int, PJLArray, Index) \
   Rc_int = JudyLFirstEmpty(PJLArray, &Index, PJEO)

JudyLNextEmpty(PJLArray, &Index, &JError)

#define JLNE(Rc_int, PJLArray, Index) \
   Rc_int = JudyLNextEmpty(PJLArray, &Index, PJEO)

JudyLLastEmpty(PJLArray, &Index, &JError)

#define JLLE(Rc_int, PJLArray, Index) \
   Rc_int = JudyLLastEmpty(PJLArray, &Index, PJEO)

JudyLPrevEmpty(PJLArray, &Index, &JError)

#define JLPE(Rc_int, PJLArray, Index) \
   Rc_int = JudyLPrevEmpty(PJLArray, &Index, PJEO)

Определения всех функций Judy, типов Pvoid_t, Pcvoid_t, PPvoid_t, Word_t, JError_t и PJError_t, констант NULL, JU_ERRNO_*, JERR и PJE0 приведены в файле Judy.h (/usr/include/Judy.h). Следует отметить, что вызывающие должны определять массивы Judy1 типа Pvoid_t, который можно передать функциям, принимающим Pcvoid_t (constant Pvoid_t), а также по адресу в функции, принимающие PPvoid_t.

Большиство функций JudyL возвращает PPvoid_t, поскольку значения в массиве могут быть ссылками на другие объекты, или Word_t *, когда нужен указатель на Value, а не указатель на указатель.

JudySL

Макросы JudySL

Макросы JudySL обеспечивают библиотеку C для создания и работы с динамическими массивами, использующими строки с null-символом в конце в качестве Index (ассоциативный массив).

Массив JudySL эквивалентен отсортированному набору строк, с каждой из которых связано значение Value типа word. Value адресуются индексами Index (ключ), которые представляют собой строки произвольного размера, завершающиеся null-символом. Память для массива выделяется при вставке пар «индекс-значение» и и освобождается при удалении пар. Это форма ассоциативного массива, где элементы сортируются лексически (с учетом регистра) по индексам. Это можно рассматривать как

void * JudySLArray["Toto, I don't think we're in Kansas any more"];

Массив JudySL создается с указателем NULL

Pvoid_t PJSLArray = (Pvoid_t) NULL;

Как в обычных массивах индексы не дублируются.

При использовании описанных здесь макросов вместо вызова функций JudySL принятая по умолчанию обработка ошибок выводит сообщения на стандартный вывод ошибок и завершает программу с exit(1).

Синтаксис

cc [flags] sourcefiles -lJudy

#include <Judy.h>

#define MAXLINELEN 1000000           // задает максимальный размер строк

Word_t * PValue;                     // элемент массива JudySL
uint8_t  Index[MAXLINELEN];          // строка
int      Rc_int;                     // возвращаемое значение
Word_t   Rc_word;                    // полное слово возвращаемого значения

Pvoid_t PJSLArray = (Pvoid_t) NULL;  // Инициализация массива JudySL

JSLI(PValue,  PJSLArray, Index);     // JudySLIns()
JSLD(Rc_int,  PJSLArray, Index);     // JudySLDel()
JSLG(PValue,  PJSLArray, Index);     // JudySLGet()
JSLFA(Rc_word, PJSLArray);           // JudySLFreeArray()
JSLF(PValue,  PJSLArray, Index);     // JudySLFirst()
JSLN(PValue,  PJSLArray, Index);     // JudySLNext()
JSLL(PValue,  PJSLArray, Index);     // JudySLLast()
JSLP(PValue,  PJSLArray, Index);     // JudySLPrev()

JSLI(PValue, PJSLArray, Index) // JudySLIns()

Вставляет строку Index и Value в массив JudySL PJSLArray. При успешной вставке Index устанавливается Value = 0. Если Index уже присутствует, Value не меняется. Макрос возвращает указатель PValue на значениеValue индекса Index. Программы должны использовать этот указатель для изменения Value, например,

*PValue = 1234;

Макросы JSLI() и JSLD реорганизуют массив JudySL, поэтому возвращенные предыдущими вызовами JudySL указатели теряют силу и должны быть определены заново.

JSLD(Rc_int, PJSLArray, Index) // JudySLDel()

Удаляет заданную пару IndexValue (элемент) из массива JudySL. Возвращает Rc_int = 1 при успешном удалении и Rc_int = 0, если Index отсутствует в массиве.

JSLG(PValue, PJSLArray, Index) // JudySLGet()

Возвращает указатель на Value индекса Index или PValue = NULL, если Index отсутствует в массиве.

JSLFA(Rc_word, PJSLArray) // JudySLFreeArray()

По указателю на массив JudySL (PJSLArray) освобождает массив полностью (гораздо быстрей, нежели цикл JSLN(), JSLD()). Возвращает в Rc_word число освобожденных байтов и PJSLArray = NULL.

Средства поиска JudySL

Средства поиска JudySL обеспечивают поиск индексов в массиве (включительный или исключительный) в прямом и обратном направлении.

При успешном поиске Index содержит найденный индекс, а PValue — указатель на значение (Value) для найденного Index. Если поиск не дал результата, возвращается PValue = NULL, а Index не содержит полезной информации. Указатель PValue должен проверяться до использования Index, поскольку при поиске возможны отказы. Для учета всех возможных результатов буфер Index должен иметь размер не меньше максимально длинной строки массива.

JSLF(PValue, PJSLArray, Index) // JudySLFirst()

Включительный поиск первого имеющегося индекса не меньше переданной строки Index. Поиск с пустой (null) строкой индекса будет возвращать первый индекс в массиве. JSLF() обычно применяется для начала упорядоченного сканирования действительных индексов массива JudySL.

uint8_t Index[MAXLINELEN];
strcpy (Index, "");
JSLF(PValue, PJSLArray, Index);

JSLN(PValue, PJSLArray, Index) // JudySLNext()

Исключительный поиск следующего индекса больше переданной строки Index. JSLN() обычно служит для продолжения упорядоченного сканирования действительных индексов в массиве JudySL или поиска «соседа» заданного индекса.

JSLL(PValue, PJSLArray, Index) // JudySLLast()

Включительный поиск последнего имеющегося индекса не больше переданной строки Index. Начало поиска со строки с максимальным значением (например, самой длинной строки с 0xff байтов) возвратит последний индекс в массиве. JSLL() обычно служит для начала упорядоченного сканирования действительных индексов массива JudySL в обратном направлении.

JSLP(PValue, PJSLArray, Index) // JudySLPrev()

Исключительный поиск предыдущего индекса меньше переданной строки Index. JSLP() обычно служит для продолжения упорядоченного сканирования действительных индексов массива JudySL в обратном направлении или поиска «соседа» указанного индекса.

Пример программы сортировки строк

#include <stdio.h>
#include <Judy.h>

#define MAXLINE 1000000                 // максимальный размер строки (длина)

uint8_t   Index[MAXLINE];               // строка для вставки

int     // Синтаксис:  JudySort < file_to_sort
main()
{
    Pvoid_t   PJArray = (PWord_t)NULL;  // Массив Judy.
    PWord_t   PValue;                   // Элемент массива Judy.
    Word_t    Bytes;                    // Размер массива JudySL.

    while (fgets(Index, MAXLINE, stdin) != (char *)NULL)
    {
        JSLI(PValue, PJArray, Index);   // Сохранить строку в массиве.
        if (PValue == PJERR)            // Недостаточно памяти?
        {                               // Обработка нехватки памяти.
            printf("Malloc failed -- get more ram\n");
            exit(1);
        }
        ++(*PValue);                    // Число экземпляров строк.
    }
    Index[0] = '\0';                    // Начать с наименьшей строки.
    JSLF(PValue, PJArray, Index);       // Находит первую строку.
    while (PValue != NULL)
    {
        while ((*PValue)--)             // Выводит дубликаты.
            printf("%s", Index);
        JSLN(PValue, PJArray, Index);   // находит следующую строку.
    }
    JSLFA(Bytes, PJArray);              // Освобождает массив.

    fprintf(stderr, "The JudySL array used %lu bytes of memory\n", Bytes);
    return (0);
}

Функции JudySL

Функции JudySL обеспечивают библиотеку C для создания и работы с динамическими массивами строк, завершающихся null-символом (ассоциативный массив).

Для каждой функции имеется эквивалентный макрос. Поскольку макросы иногда быстрее и проще в обработке ошибок, они являются предпочтительными. Определения функций приведены здесь лишь для полноты.

Одной из сложностей, связанных с вызовами функций JudySL, является решение вопроса о передаче указателя или его адреса. Поскольку функции, меняющие массив JudySL, должны менять и указатель на него, нужно передавать адрес указателя, а не сам указатель. Это ведет к трудно обнаруживаемым ошибкам в программах. На практике макросы позволяют компилятору обнаруживать программные ошибки при передаче указателей вместо адресов.

При вызове функций JudySL используется дополнительный параметр по сравнению с соответствующими макросами. Этим параметром является указатель на структуру ошибки или NULL (если детали ошибок не возвращаются).

Ниже функции описаны в терминах их использования макросами (для случая #define JUDYERROR_NOTEST 1). Это является рекомендуемым использованием макросов после завершения отладки программ. Если макрос JUDYERROR_NOTEST не задан, объявляется структура ошибки для хранения информации, возвращаемой из функций JudySL при возникновении ошибок.

Следует обращать внимание на размещение символа & в разных функциях.

Синтаксис

PPvoid_t JudySLIns(PPvoid_t PPJSLArray, const uint8_t * Index, PJError_t PJError);
int      JudySLDel(PPvoid_t PPJSLArray, const uint8_t * Index, PJError_t PJError);
PPvoid_t JudySLGet(Pcvoid_t PJSLArray, const uint8_t * Index, PJError_t PJError);
Word_t   JudySLFreeArray(PPvoid_t PPJSLArray, PJError_t PJError);
PPvoid_t JudySLFirst(Pcvoid_t PJSLArray, uint8_t * Index, PJError_t PJError);
PPvoid_t JudySLNext(Pcvoid_t PJSLArray, uint8_t * Index, PJError_t PJError);
PPvoid_t JudySLLast(Pcvoid_t PJSLArray, uint8_t * Index, PJError_t PJError);
PPvoid_t JudySLPrev(Pcvoid_t PJSLArray, uint8_t * Index, PJError_t PJError);

Определения

JudySLIns(&PJSLArray, Index, &JError)

#define JSLI(PValue, PJSLArray, Index) \
   PValue = JudyLIns(&PJSLArray, Index, PJE0)

JudySLDel(&PJSLArray, Index, &JError)

#define JSLD(Rc_int, PJSLArray, Index) \
   Rc_int = JudySLDel(&PJSLArray, Index, PJE0)

JudySLGet(PJSLArray, Index, &JError)

#define JSLG(PValue, PJSLArray, Index) \
   PValue = JudySLIns(PJSLArray, Index, PJE0)

JudySLFreeArray(&PJSLArray, &JError)

#define JSLFA(Rc_word, PJSLArray) \
   Rc_word = JudySLFreeArray(&PJSLArray, PJE0)

JudySLFirst(PJSLArray, Index, &JError)

#define JSLF(PValue, PJSLArray, Index) \
   PValue = JudySLFirst(PJSLArray, Index, PJE0)

JudySLNext(PJSLArray, Index, &JError)

#define JSLN(PValue, PJSLArray, Index) \
   PValue = JudySLNext(PJSLArray, Index, PJE0)

JudySLLast(PJSLArray, Index, &JError)

#define JSLL(PValue, PJSLArray, Index) \
   PValue = JudySLLast(PJSLArray, Index, PJE0)

JudySLPrev(PJSLArray, Index, &JError)

#define JSLP(PValue, PJSLArray, Index) \
   PValue = JudySLPrev(PJSLArray, Index, PJE0)

Определения всех функций Judy, типов Pvoid_t, Pcvoid_t, PPvoid_t, Word_t, JError_t и PJError_t, констант NULL, JU_ERRNO_*, JERR и PJE0 приведены в файле Judy.h (/usr/include/Judy.h). Следует отметить, что вызывающие должны определять массивы Judy1 типа Pvoid_t, который можно передать функциям, принимающим Pcvoid_t (constant Pvoid_t), а также по адресу в функции, принимающие PPvoid_t.

Большиство функций JudySL возвращает PPvoid_t, поскольку значения в массиве могут быть ссылками на другие объекты, или Word_t *, когда нужен указатель на Value, а не указатель на указатель.

JudyHS

Макросы JudyHS

Библиотека C для создания и работы с динамическими массивами, использующими массив байтов размера Length в качестве Index и word как Value.

Массив JudyHS эквивалентен массиву значений или указателей размера word. Index служит указателем на массив байтов заданного размера Length. Вместо использования строк с null-завершением (как в JudySL) здесь могут применяться строки с любыми битами, включая null. Это дополнение (май 2004 г.) к массивам Judy является комбинацией методов хэширования и Judy. В JudyHS не возникает возможности снижения производительности за счет знания алгоритма хэширования.

Поскольку JudyHS базируется на хэшировании, индексы не сохраняются в каком-либо определенном порядке. Поэтому функции JudyHSFirst(), JudyHSNext(), JudyHSPrev() и JudyHSLast() для поиска соседей не имеют практического значения. Значение Length для каждого массива байтов может меняться от 0 до предела malloc() (около 2 Гбайт).

Отличием JudyHS является скорость и расширяемость при сохранении эффективности использования памяти. Скорость сопоставима с лучшими методами хэширования, а эффективность использования памяти близка к связным спискам для таких же Index и Value. Массивы JudyHS рассчитаны на работу с числом индексов от 0 до миллиардов.

Массив JudyHS создается с указателем NULL.

Pvoid_t PJHSArray = (Pvoid_t) NULL;

Поскольку макросы проще и эффективней в части обработки ошибок, они являются предпочтительными по сравнению с функциями JudyHS.

Синтаксис

cc [flags] sourcefiles -lJudy

#include <Judy.h>

Word_t  * PValue;                           // элемент массива JudyHS
int       Rc_int;                           // код возврата
Word_t    Rc_word;                          // полное значение возвращаемого слова
Pvoid_t   PJHSArray = (Pvoid_t) NULL;       // инициализация массива JudyHS
uint8_t * Index;                            // указатель на массив байтов
Word_t    Length;                           // число байтов в Index

JHSI( PValue,  PJHSArray, Index, Length);   // JudyHSIns()
JHSD( Rc_int,  PJHSArray, Index, Length);   // JudyHSDel()
JHSG( PValue,  PJHSArray, Index, Length);   // JudyHSGet()
JHSFA(Rc_word, PJHSArray);                  // JudyHSFreeArray()

Определения

JHSI(PValue, PJHSArray, Index, Length) // JudyHSIns()

По указателю на массив JudyHS (PJHSArray) вставляет строку Index размера Length и Value в массив JudyHS PJHSArray. При успешной вставке Index устанавливается Value = 0. Если Index уже есть в массиве, Value не меняется. Возвращаемое значение PValue указывает на Value. Программам следует использовать этот указатель для изменения Value, например,

Value = *PValue;
*PValue = 1234;

Отметим, что JHSI() и JHSD могут реорганизовать массив JudyHS, поэтому возвращенные из предыдущих вызовов JudyHS указатели должны быть обновлены (с помощью JHSG()).

JHSD(Rc_int, PJHSArray, Index, Length) // JudyHSDel()

По указателю на массив JudyHS (PJHSArray) удаляет указанный Index вместе с Value из массива JudyHS. Возвращает Rc_int = 1 при успешном удалении и Rc_int = 0, если Index отсутствует.

JHSG(PValue, PJHSArray, Index, Length) // JudyHSGet()

По указателю на массив JudyHS (PJHSArray) находит значение Value, связанное с Index. Возвращает указатель PValue на значение Value для Index или PValue = NULL при отсутствии Index.

JHSFA(Rc_word, PJHSArray) // JudyHSFreeArray()

По указателю на массив JudyHS (PJHSArray) освобождает массив целиком. Возвращает в Rc_word число освобожденных байтов и PJHSArray = NULL.

Пример

Приведенный ниже фрагмент кода будет выводить дубликаты строк с их номерами при вводе с stdin.

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <Judy.h>

// Команда компиляции cc -O PrintDupLines.c -lJudy -o PrintDupLines

#define MAXLINE 1000000                 /* Максимальный размер строки */
uint8_t   Index[MAXLINE];               // Проверяемая строка

int     // Команда PrintDupLines < file
main()	{
    Pvoid_t   PJArray = (PWord_t)NULL;  // Массив Judy.
    PWord_t   PValue;                   // Указатель на элемент массива Judy.
    Word_t    Bytes;                    // Размер массива JudyHS.
    Word_t    LineNumb = 0;             // Номер текущей строки.
    Word_t    Dups = 0;                 // Число строк-дубликатов.

    while (fgets(Index, MAXLINE, stdin) != (char *)NULL)	{
        LineNumb++;                     // Номер строки.

        // Сохранение строки в массиве
        JHSI(PValue, PJArray, Index, strlen(Index)); 
        if (PValue == PJERR)	{      // См. Ошибки.
            fprintf(stderr, "Out of memory -- exit\n");
            exit(1);
        }
        if (*PValue == 0)	{             // Проверка дублирования
            Dups++;
            printf("Duplicate lines %lu:%lu:%s", *PValue, LineNumb, Index);
        } else {
            *PValue = LineNumb;         // Сохранение номера строки
        }
    }
    printf("%lu Duplicates, free JudyHS array of %lu Lines\n", 
                    Dups, LineNumb - Dups);
    JHSFA(Bytes, PJArray);              // Освобождение массива JudyHS
    printf("JudyHSFreeArray() free'ed %lu bytes of memory\n", Bytes);
    return (0);
}

Функции JudyHS

Функции JudySL обеспечивают библиотеку C для создания и работы с динамическими массивами из массивов байтов размера Length с использованием индексов типа word.

Для каждой функции имеется эквивалентный макрос. Поскольку макросы иногда быстрее и проще в обработке ошибок, они являются предпочтительными. Определения функций приведены здесь лишь для полноты.

Одной из сложностей, связанных с вызовами функций JudyHS, является решение вопроса о передаче указателя или его адреса. Поскольку функции, меняющие массив JudyHS, должны менять и указатель на него, нужно передавать адрес указателя, а не сам указатель. Это ведет к трудно обнаруживаемым ошибкам в программах. На практике макросы позволяют компилятору обнаруживать программные ошибки при передаче указателей вместо адресов.

При вызове функций JudyHS используется дополнительный параметр по сравнению с соответствующими макросами. Этим параметром является указатель на структуру ошибки или NULL (если детали ошибок не возвращаются).

Ниже функции описаны в терминах их использования макросами (для случая #define JUDYERROR_NOTEST 1). Это является рекомендуемым использованием макросов после завершения отладки программ. Если макрос JUDYERROR_NOTEST не задан, объявляется структура ошибки для хранения информации, возвращаемой из функций JudyHS при возникновении ошибок.

Следует обращать внимание на размещение символа & в разных функциях.

Синтаксис

PPvoid_t JudyHSIns(PPvoid_t PPJHS, void *Index, Word_t Length, PJError_t PJError);
int      JudyHSDel(PPvoid_t PPJHS, void *Index, Word_t Length, PJError_t PJError);
PPvoid_t JudyHSGet(Pcvoid_t  PJHS, void *Index, Word_t Length, PJError_t PJError);
Word_t   JudyHSFreeArray(PPvoid_t PPJHS, PJError_t PJError);

Определения

JudyHSIns(&PJHS, Index, Length, &JError)

#define JHSI(PValue, PJHS, Index) \
   PValue = JudyLIns(&PJHS, Index, PJE0)

JudyHSDel(&PJHS, Index, Length, &JError)

#define JHSD(Rc_int, PJHS, Index, Length) \
   Rc_int = JudyHSDel(&PJHS, Index, Length, PJE0)

JudyHSGet(PJHS, Index, Length)

#define JHSG(PValue, PJHS, Index, Length) \
   PValue = JudyHSIns(PJHS, Index, Length)

JudyHSFreeArray(&PJHS, &JError)

#define JHSFA(Rc_word, PJHS) \
   Rc_word = JudyHSFreeArray(&PJHS, PJE0)

Определения всех функций Judy, типов Pvoid_t, Pcvoid_t, PPvoid_t, Word_t, JError_t и PJError_t, констант NULL, JU_ERRNO_*, JERR и PJE0 приведены в файле Judy.h (/usr/include/Judy.h). Следует отметить, что вызывающие должны определять массивы Judy1 типа Pvoid_t, который можно передать функциям, принимающим Pcvoid_t (constant Pvoid_t), а также по адресу в функции, принимающие PPvoid_t.

Большиство функций JudyHS возвращает PPvoid_t, поскольку значения в массиве могут быть ссылками на другие объекты, или Word_t *, когда нужен указатель на Value, а не указатель на указатель.


Перевод на русский язык

Николай Малых

nmalykh@protocols.ru

1В процессе тестирования Judy было найдено очень мало malloc()/ОС, где не возникало ошибок при отказах malloc(). Иногда приходилось ждать очень долго, поскольку в большинстве систем запускалась «бесконечная» подкачка.

2В текущей версии Judy.h значение этого флага 0x4 было заменено на 0x1, чтобы можно было использовать функцию malloc(), не выравнивающую выделенную память по 8-битовой границе (например, старая версия valgrind).

 

Рубрика: Алгоритмы | Комментарии к записи Библиотека Judy для работы с динамическими массивами отключены

Краткое описание работы массивов JUDY

image_print

PDF

Doug Baskins, doug@sourcejudy.com

16 октября 2001 г., изменено в июле 2002

Разработчика алгоритма Judy часто спрашивают, почему этот алгоритм такой быстрый. Здесь предпринята попытка кратко ответить на этот вопрос. Более полное описание пакета приведено в документе Judy Shop Manual.

Исходный код Judy был открыт в июне 2002 г. и доступен по ссылке http://sourceforge.net/projects/judy1.

Дерево Judy в общем случае быстрее и требует меньше памяти, нежели такие варианты как бинарные деревья (AVL) trees, b-деревья и skip-списки. При использовании конфигурации Judy Scalable Hashing пакет обычно быстрее других методов хэширования.

Термины пространство (expanse), численность (population) и плотность (density) нечасто применяются в литературе о поиске по дереву, поэтому ниже даны краткие определения.

Пространство

Диапазон возможных ключей (например, 256 — 511).

Численность

Число ключей в пространстве (например, для 260, 300, 499, 500 это будет 4).

Плотность

Описывает степень разреженности пространства ключей (density = population/expanse). Плотность 1,0 означает, что все возможные ключи установлены или действительный в данном пространстве.

Термины узел (node) и ветвь (branch) в этом документе взаимозаменяемы.

Термины ключ (key) и индекс (index) взаимозаменяемы в документе. Дерево Judy рассматривается как неограниченный массив Judy на уровне интерфейса API. Пространства массивов JudyL и Judy1 ограничены размером слова (32 или 64 бита), применяемого в качестве индекса. Массив JudySL ограничен лишь размером строки ключа, которая может быть сохранена в машине.

Заполнение строки кэша CPU — это дополнительное время, требуемое для чтения ссылки из ОЗУ (RAM) если слово не найдено в кэше. В современных компьютерах это время составляет 50 — 2000 машинных команд2. Поэтому такого заполнения следует избегать, если ту же работу можно выполнить менее чем за 50 команд.

Некоторые причины превосходства Judy по сравнению с двоичными деревьями, b-tree и skip-списками указаны ниже.

  • Judy редко отдает предпочтение простоте по отношению к скорости и пространству (алгоритм Judy прост лиш на уровне API).

  • Judy по возможности избегает заполнения строк кэша (основной критерий устройства Judy).

  • Для b-tree требуется поиск в кажом узле (ветви), что ведет к заполнению большого числа строк кэша.

  • Двоичные деревья имеют значительно больше уровней (примерно в 8 раз), что увеличивает число заполнений строк кэша.

  • Skip-списки приблизительно эквивалентны дереву степени 4, что увеличивает число заполнений строк кэша.

  • Основанное на пространстве цифровое дерево (Judy является его вариантом) не требует балансировки при расширении.

  • Часть ключа (8 битов) служит для деления пространства на субдеревья, а в этих субдеревьях требуется лишь оставшаяся часть ключа , что сокращает размер.

Основным недостатком простых деревьев является неэффективное использование памяти, особенно при больших значениях степени втевления узлов N. Дерево Judy решает эту проблему. Фактически, это дерево превосходит по эффективности использования памяти почти все другие структуры (включая простые связные списки). Исключением может являться плотно заполненный линейный массив (array[]).

С точки зрения скорости Judy представляет собой дерево степени 256 (trie) в соответствии с определением D. Knuth (том 3). Число 256 для степени дерева является «магическим» по ряду причин. Основная причина заключается в том, что байт (минимальный адресуемый элемент памяти) имеет размер 8 битов. Высокая степень также ведет к снижению числа заполнений строк кэша на доступ.

Интересно отметить, что в ранней версии Judy использовалось расширение ветвей (иногда это называют level-compressed trie). Возможности расширения возникают главным образом на верхних уровнях дерева. Поскольку дерево представляет собой иерархию, верхние ветви с большой вероятностью присутствуют в кэше, поэтому их расширение не снижает существенно число заполнений строк кэша. Позднее расширение ветвей было исключено из Judy. Однако пакет Judy был настроен на использование наименьшего возможного числа инструкций, когда доступ вероятно будет к кэшу.

Наличие кэше CPU в современных машинах изменило многие алгоритмы. Для использования преимуществ кэша важно применять его как можно чаще. В дереве Judy наличие кэша снижает число заполнений строк кэша в 1-3 раза (или более) на поиск.

В пространстве 232 (или 2564) требуется не более 4 заполнений строк кэша для наихудшего случая доступа к плотно заполненному дереву степени 256. В пространстве 264 (или 2568) требуется 8 заполнений в наихудшем случае. На практике Judy обычно делает это гораздо эффективней. Одной из причин этого является то, что «плотность» ключей редко бывает минимально возможнойй в большинстве подпространств. Для увеличения глубины дерева Judy требуется высокая плотность в сочетании с большой численностью. Объяснять это долго. Можно провести аналогию с кучей песка. Потребуется много песка для создания высокой кучи, особенно если под каждой песчинкой должно размещаться 256 других. В 64-битовом варианте Judy для создания 8 уровней может потребоваться больше памяти, нежели имеется на планете.

Judy эффективно приспосабливается к разным уровням плотности и численности. Поскольку структурой данных Judy служит дерево деревьев, каждое субдерево является статическим пространством, которое оптимизировано в соответствии с плотностью содержащихся ключей. Для поддержки такой гибкости в 32(64)-битовом Judy имеется приблизительно 25(85) первичных и примерно столько же вторичных структур данных. Здесь описаны некоторые из них для демонстрации связи (синергии) плотности и сжатия.

С точки зрения расхода памяти (размера) дерево Judy совместно использует (без дублирования) цифровой ключ в дереве. Эта форма сжатия ключа является естественным результатом применения цифрового дерева. Было бы очень неудобно делать на это деревьях, сбалансированных по численности (и, по-видимому, это не было сделано). Каждый указатель в дереве Judy ссылается на похожее меньшее субпространство, в то же время декодируя другие 8 битов ключа (в чистом цифровом дереве ключи не хранятся внутри и определяются по положению).

Рассмотрим верхнюю часть небольшого дерева Judy (JudyL) и нижнюю часть плотно заполненного дерева Judy1. Дерево Judy с численностью 0 является просто указателем NULL. Дерево JudyL с одним ключом является корневым указателем на объект из двух слов, содержащий ключ и связанное с ним значение. Дерево JudyL с численностью два ключа является объектом из 4 слов (2 значения и 2 сортированных ключа. Дерево с численностью 3 ключа является объектом из 8 слов с (число слов + 3) значений и тремя сортированными ключами.

Это можно продолжать до численности в 32 ключа, когда формируется фактическая древовидная структура со «сжатым» узлом степени 256, которая декодирует первый байт каждого ключа. Значение 32 было выбрано потому, что именно здесь структура дерева требует эквивалентного числа заполнений строк кэша. Все объекты ниже этого узла содержат ключи, которые сокращаются по меньшей мере на первый байт.

Имеется три типа узлов, два из которых связаны с 1 заполнением строки кэша при прохождении и один — с 2. На каждом пути вниз3 по дереву при любой численности проходится не более 1 объекта с заполнением двух строк кэша. Это означает, что иногда может быть дополнительное заполнение одной строки кэша по сравнению с ожидаемым при прохождении чистого узла степени 256.

С другой стороны, густонаселенное дерево Judy1, в котором ключ декодирован на 1 байт и плотность подпространства ключей степени 256 выше 0,094 (25 ключей/пространство 256), битовая последовательность из 32 байтов (256 битов) формируется из имеющегося сортированного массива из 24 1-байтовых ключей (обработка значений опущена). В результате для ключа используется около 1,3 (32/25) байта памяти (по сравнению с 1,0). Отметим, что рост плотности (численности) на этом этапе не требует увеличения памяти для ключей. Например, при достижении плотности 0,5 (численность = 128 / пространство = 256) потребляется около 2 битов ((32/128)*8) на ключ с добавлением некоторых издержек (2,0 слова) для структуры дерева.

Отметим, что вставка или удаление ключа почти так же просты, как установки или сброс бита. Кроме того, расход памяти почти одинаков для 32- и 64-битовых деревьев Judy. При одинаковом размере ключей 32- и 64-битовые деревья Judy очень похожи по расходу памяти на ключ, глубине и производительности. Однако расход памяти в 64-битовом Judy выше, поскольку размер указателей и значений (JudyL) удваивается.

В короткой заметке невозможно описать такие детали структур данных как Root, JPM, указатели, линейные, битовые и несжатые узлы, области значений, непосредственные индексы, терминальные узлы (листья), менее сжатая форма, управления памятью, быстрый поиск листьев и подсчет деревьев. Однако базовые понятия здесь рассмотрены, а остальное можно узнать из документации.

Doug Baskins
doug@sourcejudy.com

Вольный перевод на русский язык

Николай Малых

nmalykh@protocols.ru

1Этот вариант кода не поддерживает некоторые современные процессоры. Более современный вариант доступен по ссылке. Прим. перев.

2Современные машины часто используют конвейерную запись в ОЗУ и это не вносит дополнительной задержки в Judy.

3Американские деревья растут корнем вверх. Прим. перев.

Рубрика: Алгоритмы | Комментарии к записи Краткое описание работы массивов JUDY отключены

SiFive-OE-poPingUI-P4

image_print

PDF

Для экспериментов с применением языка P4 (p4.org) в сетевых устройствах была предпринята попытка сборки прототипа компилятора P4C на платформе HiFive Unleashed U540 компании SiFive. В качестве среды разработки использовалась система OpenEmbedded (www.yoctoproject.org) и базовый репозиторий SiFive (github.com/sifive/meta-sifive/tree/master). Для работы также требуется пакет repo, установка которого описана по ссылке.

Для сборки образов потребуется достаточно большое пространство на диске (после сборки образа на диске было занято 94 Гбайт), а сам диск должен быть быстрым (SSD или SAS).

  1. Создаем пустой каталог и переходим в него

    mkdir sifive-master
    cd sifive-master

    Далее в тексте этот каталог будет именоваться корневым и все ссылки на каталоги и файлы будут отсчитываться от него.

  2. Создаем и заполняем репозиторий

    $ repo init -u git://github.com/sifive/meta-sifive -b master -m tools/manifests/sifive.xml
    $ repo sync
  3. Создаем уровень meta-poPingUI

    $ bitbake-layers create-layer meta-poPingUI
    NOTE: Starting bitbake server... 
    Add your new layer with 'bitbake-layers add-layer meta-poPingUI'
    $ bitbake-layers add-layer meta-poPingUI
    NOTE: Starting bitbake server... 
    Unable to find bblayers.conf
  4. Копируем файл установки окружения из каталога meta-sifive

    $ cp meta-sifive/setup.sh meta-poPingUI/setup.sh
  5. Редактируем созданную копию, добавляя строку

    $ bitbake-layers add-layer ../meta-poPingUI
  6. Из строки DISTRO_FEATURES_append = » largefile opengl ptest multiarch pam systemd vulkan » удаляем opengl и vulkan и получаем в результате

    DISTRO_FEATURES_append = " largefile ptest multiarch pam systemd "
  7. В начале файла меняем имя создаваемого образа, как показано ниже

    BITBAKEIMAGE="coreip-cli"
  8. В конце файла помещаем символ комментария в показанные ниже строки

    # Add r600 drivers for AMD GPU 
    #PACKAGECONFIG_append_pn-mesa = " r600" 
    
    # Add support for modern AMD GPU (e.g. RX550 / POLARIS) 
    #PACKAGECONFIG_append_pn-mesa = " radeonsi" 
    #PACKAGECONFIG_append_pn-mesa = " gallium-llvm"
  9. Копируем каталог meta-sifive/conf в meta-poPingUI/conf

  10. Редактируем файл meta-poPingUI/conf/layer.conf, заменяя sifive на poPingUI, а также устанавливаем для уровня высокий приоритет, чтобы при совпадении имен задания выбирались из нашего уровня

    BBFILE_PRIORITY_meta-poPingUI = "9"
  11. Копируем каталог meta-sifive/recipes-sifive/images в meta-poPingUI/recipes-poPingUI/images

    Поскольку планируется работа лишь с платой HiFive без модулей расширения удаляем файлы с поддержкой графического интерфейса (demo-coreip-xfce4.bb и demo-coreip-xfce4-debug.bb), а файлы demo-coreip-cli.bb и demo-coreip-cli-debug.bb переименовываем в coreip-cli.bb и coreip-cli-debug.bb. Это позволит избежать путаницы и при необходимости воспользоваться образами уровня meta-sifive.

  12. Переходим в корневой каталог репозитория и вводим команду

    $ . ./meta-poPingUI/setup.sh
    Init OE 
    You had no conf/local.conf file. This configuration file has therefore been 
    created for you with some default values. You may wish to edit it to, for 
    example, select a different MACHINE (target hardware). See conf/local.conf 
    for more information as common configuration options are commented. 
    
    You had no conf/bblayers.conf file. This configuration file has therefore been 
    created for you with some default values. To add additional metadata layers 
    into your configuration please add entries to conf/bblayers.conf. 
    
    The Yocto Project has extensive documentation about OE including a reference 
    manual which can be found at: 
       http://yoctoproject.org/documentation 
    
    For more information about OpenEmbedded see their website: 
       http://www.openembedded.org/ 
    
    
    ### Shell environment set up for builds. ### 
    
    You can now run 'bitbake <target>' 
    
    Common targets are: 
       core-image-minimal 
       core-image-sato 
       meta-toolchain 
       meta-ide-support 
    
    You can also run generated qemu images with a command like 'runqemu qemux86'. 
    
    Other commonly useful commands are: 
    - 'devtool' and 'recipetool' handle common recipe tasks 
    - 'bitbake-layers' handles common layer tasks 
    - 'oe-pkgdata-util' handles common target package tasks 
    Adding layers 
    NOTE: Starting bitbake server... 
    NOTE: Starting bitbake server... 
    NOTE: Starting bitbake server... 
    NOTE: Starting bitbake server... 
    NOTE: Starting bitbake server... 
    NOTE: Starting bitbake server... 
    NOTE: Starting bitbake server... 
    NOTE: Starting bitbake server... 
    NOTE: Starting bitbake server... 
    Creating auto.conf 
    --------------------------------------------------- 
    MACHINE=freedom-u540 bitbake coreip-cli 
    --------------------------------------------------- 
    
    Buildable machine info 
    --------------------------------------------------- 
    * freedom-u540: The SiFive HiFive Unleashed board 
    * qemuriscv64: The 64-bit RISC-V machine 
    --------------------------------------------------- 
    
  13. Запускаем сборку образа командой

    $ MACHINE=freedom-u540 bitbake coreip-cli
    Parsing recipes: 100% |#############################################################################################################################################################################| Time: 0:00:18 
    Parsing of 2346 .bb files complete (0 cached, 2346 parsed). 3445 targets, 174 skipped, 0 masked, 0 errors. 
    NOTE: Resolving any missing task queue dependencies 
    
    Build Configuration: 
    BB_VERSION           = "1.46.0" 
    BUILD_SYS            = "x86_64-linux" 
    NATIVELSBSTRING      = "mageia-7" 
    TARGET_SYS           = "riscv64-oe-linux" 
    MACHINE              = "freedom-u540" 
    DISTRO               = "nodistro" 
    DISTRO_VERSION       = "nodistro.0" 
    TUNE_FEATURES        = "riscv64" 
    meta                 = "HEAD:57ccf1e3bb320bd28a2d106c98f4706434c3075a" 
    meta-oe               
    meta-python           
    meta-multimedia       
    meta-networking       
    meta-gnome            
    meta-xfce            = "HEAD:920161113533074d27dc93c521815380fdf20275" 
    meta-riscv           = "HEAD:8bd3402c76f897189842f65e521f1388777660ca" 
    meta-sifive          = "HEAD:4c97a625e70558fbca9dc210616b13115e22dbee" 
    meta-poPingUI        = "<unknown>:<unknown>"
    
    
  14. Процесс загрузки исходных кодов1 и сборки компонент достаточно долог и можно заняться другими делами. В моей системе Mageia 7.1 процесс завершается ошибкой

    virtual:native:/OE/sifive-master/openembedded-core/meta/recipes-devtools/perl/libxml-parser-perl_2.46.bb:do_configure

    Для решения этой проблемы создаем в каталоге уровня файл meta-poPingUI/recipes-devtools/libxml-parser-perl/libxml-parser-perl_2.46.bbappend, показанный ниже

    do_configure_prepend_class-native () { 
       cd ${S} 
       ${HOSTTOOLS_DIR}/perl Makefile.PL 
       cd - 
    }
  15. Проблема с networkmanager решается командой LC_ALL=C ../recipe-sysroot-native/usr/bin/intltool-merge -x -u -c ./po/.intltool-merge-cache ../NetworkManager-1.22.10/po data/org.freedesktop.NetworkManager.policy.in data/org.freedesktop.NetworkManager.policy из каталога build/tmp-glibc/work/riscv64-oe-linux/networkmanager/1.22.10-r0/build и создания символьной ссылки /usr/bin/nativeperl на локальный перл хоста2

  16. На этом первичные правки завершаются и образ собирается нормально. Можно начинать внесение своих правок.

  17. Сначала добавим Judy, поскольку от этого пакета зависит p4c и связанные пакеты.

    $ devtool add https://github.com/multiSnow/judy.git
    $ bitbake judy

    Процесс завершается ошибкой /lib/ld-linux-riscv64-lp64d.so.1: No such file or directory. Это связано с попыткой запуска двоичного файла генерации таблиц, собранного для RISCV, из среды сборки x86. Найти способ обхода этой проблемы мне не удалось, поэтому были просто взяты файлы, созданные на платформе HiFive Unleashed, и помещены в каталоги исходного кода judy. При этом запуск программы генерации (JudyLTablesGen и Judy1TablesGen) из Makefile был удален путем простого редактирования.

    Копируем файл JudyLTables.c в каталог build/tmp-glibc/work/riscv64-oe-linux/judy/1.0.5+git999-r0/judy-1.0.5+git999/src/JudyL и удаляем конец строки 7953 ./JudyLTablesGen. Затем повторяем команду bitbake judy и выполняем аналогичные процедуры в каталоге Judy1 с файлом Judy1Tables.c. Следующий запуск команды bitbake judy обеспечивает сборку пакета без ошибок.

  18. Добавляем созданное задание на уровень meta-poPingUI командой

    $ devtool finish -f judy meta-poPingUI/recipes-devtools

    из корневого каталога системы сборки. В результате готовое задание помещается на нужный уровень в каталог recipes-devtools. После этого следует повторить сборку задания, поскольку при переносе внесенные изменения теряются (см. 14). Операции выполняются с файлами в каталоге build/tmp-glibc/work/riscv64-oe-linux/judy/1.0.5+gitAUTOINC+a5971f3ee4-r0/build/src.

  19. Следующим добавляем пакет PI

    $ devtool add https://github.com/p4lang/PI.git

    В файле задания pi_git.bb меняем строку DEPENDS, как показано ниже

    DEPENDS = "readline judy nanomsg protobuf protobuf-c"
    

    И добавляем опции настройки

    EXTRA_OECONF = " --with-fe-cpp --with-proto=Protobuf --with-internal-rpc --with-cli "

    Между пакетами PI и bmv2 имеются циклические зависимости, поэтому PI придется собрать дважды без поддержки bmv2 (без опции —with-bmv2). Включаем задание на уровень meta-poPingUI командами из корневого каталога

    $ mkdir meta-poPingUI/recipes-p4
    $ devtool finish pi meta-poPingUI/recipes-p4
    $ bitbake pi
    
  20. Затем добавляем пакет bmv2 (behavioral model version 2), содержащий прототип коммутатора P4.

    $ devtool add https://github.com/p4lang/behavioral-model.git

    Система сборки создает для него задание с именем bm. Редактируем в файле задания bm_git.bb приведенные ниже строки

    DEPENDS = "gmp judy nanomsg libpcap pi boost"
    EXTRA_OECONF = " --with-nanomsg --with-pi --enable-modules --disable-dependency-tracking --without-thrift "
    

    Затем переносим задание на уровень meta-poPingUI командой из корневого каталога

    $ devtool finish bm meta-poPingUI/recipes-p4
  21. Начинаем сборку компилятора P4C

    $ devtool add https://github.com/p4lang/p4c.git

    Файл задания корректируем как показано ниже

    DEPENDS = "flex-native bison-native boost protobuf protobuf-native protobuf-c protobuf-c-native doxygen bm bdwgc gmp judy" 
    EXTRA_OECMAKE = "-DENABLE_GC=OFF -DENABLE_EBPF=OFF -DENABLE_PROTOBUF_STATIC=OFF "

    Сборка завершается ошибкой, связанной с запуском исполняемого файла RISCV (tools/irgenerator) в среде сборки x86. Для решения проблемы помещаем символ комментария в начало строки с вызовом команды irgenerator (строка 3194) в файле build.ninja каталога build/workspace/sources/p4c/oe-workdir/p4c-1.0+git999. Затем нужно скопировать в каталог build/workspace/sources/p4c/oe-workdir/p4c-1.0+git999/ir заранее подготовленные на целевой платформе файлы, перечисленные ниже

    gen-tree-macro.h 
    gen-tree-macro.h.fixup 
    gen-tree-macro.h.tmp 
    ir-generated.cpp 
    ir-generated.cpp.fixup 
    ir-generated.cpp.tmp 
    ir-generated.h 
    ir-generated.h.fixup 
    ir-generated.h.tmp 
    libir.a

    Копируем задание на уровень meta-poPingUI командой из корневого каталога

    $ devtool finish bm meta-poPingUI/recipes-p4

    После чего повторяем сборку и после получения ошибки внесим описанные выше правки в каталоге build/tmp-glibc/work/riscv64-oe-linux/p4c/1.0+gitAUTOINC+f79af56ea9-r0/build и еще раз собираем пакет командой

    $ bitbake p4c
  22. Сборка завершается без ошибок и можно внести задание в образ, редактируя файл meta-poPingUI/recipes-poPingUI/images/coreip-cli.bb. Для этого добавляем строку в конце переменной IMAGE_INSTALL, как показано ниже

       p4c \ 
       ${CORE_IMAGE_EXTRA_INSTALL} \ 
       " 
    
    IMAGE_INSTALL_append_freedom-u540 = "\ 
       unleashed-udev-rules \ 
       "
  23. Далее создаем образ командой

    $ MACHINE=freedom-u540 bitbake coreip-cli

    и по завершении его создания переносим на SD-карту командой

    $ zcat build/tmp-glibc/deploy/images/freedom-u540/coreip-cli-freedom-u540.wic.gz | sudo dd of=/dev/sdX bs=512K iflag=fullblock oflag=direct conv=fsync status=progress

    где sdX — имя устройства (SD-карта).

  24. По завершении записи можно отмонтировать SD-карту и перенести ее на плату HiFive Unleased. Для входа в систему служит имя пользователя root с паролем sifive.

В следующих статьях будет описана оптимизация образа и добавление функций трассировки, тестирования и мониторинга сетевых функций.

Работа выполнена в рамках проекта «Орион».


Николай Малых

nmalykh@protocols.ru


1Время от времени при загрузке кода могут возникать ошибки, связанные с недоступностью сетевых ресурсов Internet. В таких случаях следует просто повторить команду.

2Попытка выполнить команду из файла дополнения дает ошибку «You must have XML::Parser installed to run ../recipe-sysroot-native/usr/bin/intltool-merge». Добавление зависимостей проблему не решает.

3Номер строки может отличаться, поэтому лучше воспользоваться контекстным поиском в файле.

4Можно найти строку по контексту Generating IR class files. Искомая строка будет предыдущей.

Рубрика: Linux, RISC-V, Языки сетевого программирования | Комментарии к записи SiFive-OE-poPingUI-P4 отключены

SNSD

image_print

NTK_RFC 0009

Scattered Name Service Disgregation

Распределенная служба имен

PDF

В этом документе описана распределенная служба имен (Scattered Name Service Disgregation) — расширение протокола ANDNA. Текст будет включен в окончательную документацию, а сейчас в него можно вносить правки, связавшись с разработчиками.

SNSD


Распределенная служба имен SNSD является эквивалентом ANDNA для записи SRV Record в Internet DNS1, определенной в [1] и кратко описанной в [2].

SNSD отличается от SRV Record и имеет свои уникальные свойства.

С помощью SNSD можно связать адреса IP и имена хостов с другим hostname.

Каждая назначенная запись имеет номер службы (service number), что позволяет группировать адреса IP и hostname с одинаковым номером в массив. При запросе распознавания (resolution request) клиент будет указывать номер, поэтому он получит запись для указанного номера, связанного с hostname.

Например, узел X имеет зарегистрированное имя хоста angelica и по умолчанию для этого имени выделен IP-адрес 1.2.3.4. X связывает имя хоста depausceve со службой http (номер 80) для имени хоста angelica, а также адрес 11.22.33.44 со службой ftp (номер 21) хоста angelica.

Когда Y обычным путем распознает адрес angelica, он получает 1.2.3.4, но при распознавании адреса из web-браузера он будет запрашивать запись, связанную со службой http, и запрос будет возвращать depausceve. Браузер будет распознавать адрес по имени depausceve и получит доступ к серверу. Когда клиент ftp хоста Y будет пытаться распознать адрес angelica, он получит 11.22.33.44. Если Y попытается распознать адрес для не связанной службы, он получит основной адрес хоста 1.2.3.4.

Узел, связанный с записью SNSD, называется узлом SNSD (SNSD node). В приведенном примере такими узлами являются depausceve и 11.22.33.44.

Узел, который регистрирует записи и сохраняет регистрацию основного имени хоста, всегда называют регистрирующим узлом (register node), но может также использоваться термин Zero SNSD node — фактически это соответствует наиболее общей записи SNSD для службы с номером 0.

Отметим, что SNSD полностью отменяет NTK_RFC 0004 [3].

Служба, приоритет, вес

Номер службы

Номер службы указывает область действия записи SNSD. Адрес IP, связанный со службой номер x, будет возвращаться только в ответ на запросы распознавания, содержащие этот номер. Номер службы — это номер порта, с которым связана соответствующая служба. Номера портов можно узнать из файла /etc/services. Служба с номером 0 соответствует обычной записи ANDNA и в ответ на базовый запрос распознавания будет возвращаться соответствующий адрес IP.

Приритет

Запись SNSD имеет также значение приоритета, которое определяет приоритет данной записи среди других записей внутри массива службы. Клиент будет взаимодействовать с первым узлом SNSD, имеющим наивысший приоритет, и только при недоступности этого узла станет обращаться к узлам с меньшим приоритетом.

Вес

Значение веса, связанное с записью SNSD, служит для выбора среди нескольких записей с одинаковым приоритетом. Клиент запрашивает у ANDNA распознавание и получает, например, 8 разных записей. Первая запись, используемая клиентом, выбирается псевдослучайным способом. Каждая запись может быть выбрана с вероятностью, пропорциональной ее весу. Отметим, что в случае одинакового приоритета у всех записей выбор становится полностью случайным.

Для запрета использования записи можно задать нулевой вес. Значения веса должны быть меньше 128.

Регистрация SNSD

Метод регистрации записи SNSD похож на описанный в [3]. С одной службой можно связать до 16 записей. Максимальное число зарегистрированных записей составляет 256.

Регистрация записей SNSD выполняется одним узлом register_node. Узел hash_node, получающий регистрацию, не будет связываться с counter_node, поскольку имя хоста уже зарегистрировано и его не нужно проверять. Остается проверить лишь действительность подписи.

Регистрирующий узел может также выбрать необязательную функцию SNSD, чтобы убедиться в том, что имя хоста SNSD всегда связано с доверенной машиной. В этом случае узлу register_node нужен открытый ключ ANDNA узла SNSD для передачи узлу периодических запросов. Если узел не отвечает, register_node будет передавать ANDNA для удаления соответствующей записи SNSD.

Регистрация записей SNSD для имен хостов, которые лишь помещены в очередь andna_queue, отвергается. Практические действия по регистрации записи SNSD показаны ниже.

 * Изменение файла /etc/netsukuku/snsd_nodes.
{{{
register_node# cd /etc/netsukuku/ 
register_node# cat snsd_nodes
#
# Файл узлов SNSD
#
# В формате
# hostname:snsd_hostname:service:priority:weight[:pub_key_file]
# или
# hostname:snsd_ip:service:priority:weight[:pub_key_file]
#
# Параметр pub_key_file является необязательным. При его наличии NetsukukuD будет
# периодически проверять snsd_hostname и контролировать принадлежность имени к
# одной машине. При смене машины соответствующая запись snsd будет удаляться.
#

depausceve:pippo:http:1
depausceve:1.2.3.4:21:0

angelica:frenzu:ssh:1:/etc/netsukuku/snsd/frenzu.pubk

register_node#
register_node# scp frenzu:/usr/share/andna_lcl_keyring snsd/frenzu.pubk
}}}
 * Передача сигнала SIGHUP демону NetsukukuD на регистрирующем узле.
{{{
register_node# killall -HUP ntkd
# или 
register_node# rc.ntk reload
}}}

Нулевое значение SNSD IP

Основной адрес IP, связанный с обычным hostname, имеет по умолчанию приведенные ниже значения.

{{{
IP       = register_node IP     # Это значение нельзя изменить
service  = 0
priority = 16
weight   = 1
}}}

Можно связать другие записи SNSD со службой 0, но не разрешается менять основной адрес IP, в качестве которого может служить только IP-адрес узла register_node. Хотя нет возможности установить другую привязку для основного адреса IP, его можно «отключить», установив вес 0.

Строка, применяемая для смены значений веса и приоритета основного IP, имеет вид

{{{
hostname:hostname:0:priority:weight

# Например,
register_node# echo depausceve:depausceve:0:23:12 >> /etc/netsukuku/snsd_nodes
}}}

Цепочка SNSD

Поскольку для нулевой записи можно задать разные псевдонимы и резервные адреса IP, можно создавать цепочки SNSD. Например,

{{{
depausceve registers: depausceve:80 --> pippo
pippo registers:      pippo:0  --> frenzu
frenzu registers:     frenzu:0 --> angelica
}}}

Однако цепочки SNSD игнорируются и пригодным считается лишь первое преобразование. Поскольку для службы 0 всегда имеется основной адрес IP, распознавание выполняется всегда. В приведенном случае (depausceve:80 —> pippo:0) распознавание будет возвращать основной IP-адрес pippo:0.

Отклик на запрос преобразования для службы 0 всегда возвращает адреса IP, а не имена хостов.


[1] http://www.ietf.org/rfc/rfc2782.txt

[2] http://en.wikipedia.org/wiki/SRV_record

[3] Mail Exchange request, http://netsukuku.freaknet.org/main_doc/ntk_rfc/Ntk_MX_request

Перевод на русский язык

Николай Малых

nmalykh@protocols.ru

1Domain Name System — служба доменных имен.

Рубрика: Фрактальные сети | Комментарии к записи SNSD отключены

Протокол ANDNS

image_print

PDF

0. Введение

В этом документе описан протокол, применяемый для коммуникаций с ANDNA. Протокол используется для запросов в сфере internet. Например, можно запросить google.it в internet или depausceve в сети netsukuku.

В случае запросов internet элемент dns_wrapper будет взаимодействовать с серверами dns, заданными в файле /etc/resolv.conf, когда модуль ntkd загружен.

1. Обозначения

Далее на рисунках байты представляются в виде

         1  2  3  4  5  6  7  8
        +--+--+--+--+--+--+--+--+
        |                       |
        +--+--+--+--+--+--+--+--+

Числа указывают номера битов. Двухбайтовое слово представляется в форме

         1  2  3  4  5  6  7  8  1  2  3  4  5  6  7  8
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                       |                       |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

2. Заголовки

Заголовки имеют размер 4 байта и показанный на рисунке формат

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                      ID                    | R|
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |QR| P| Z| QT  |  ANCOUNT  |I |   NK|   RCODE   |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

ID

Двухбайтовый идентификатор запроса. Значение ID выбирается случайным образом и в ответах должно применяться то же значение ID.

R

Бит рекурсии, при установке которого запросы SNSD, имеющие имя хоста в качестве распознавания, будут распознаваться (если это возможно).

QR

0 для вопросов, 1 для ответов.

P

Если запрос является h2ip и связан с ntk, P задает протокол: 0 для TCP, 1 для UDP и 0 в остальных случаях.

Z

Сжатие zlib. При z=1 содержимое пакета (кроме заголовков) сжимается с помощью zlib (см. 8. Сжатие).

QT

Тип запроса (см. 3. Типы запросов). В откликах это поле должно сохраняться неизменным.

ANCOUNT

Счетчик ответов. Поле устанавливается только при QR=1 (пакет содержит ответы) и указывает число ответов в этом пакете.

I

Бит версии IP, использованной для содержимого пакета. Все адреса в пакете являются IPv4 (4 байта), если I=0 и IPv6 (16 байтов), если I=1. Этот бит полезен лишь в вопросах. Сервер будет возвращать ответ NO SUCH DOMAIN (нет такого домена), если на его узле применяется иная версия протокола IP. При совпадении версий в ответе будет использоваться та же версия протокола.

NK

Биты Netsukuku, позволяющий задать область запроса (query realm). При NK=1 областью запроса является netsukuku, при NK=2 — internet. Значение NK=0 указывает, что пакет не кодируется данным протоколом и содержит обычный протокол DNS (см. 4. Область запроса). В ответах это поле должно сохраняться.

RCODE

Результат запроса. Для пакетов с вопросами устанавливается RCODE = 0. В случае ошибок устанавливается ANCOUNT = 0.

3. Типы запросов

Имеется несколько типов запросов.

QTYPE = 0

Это классическое преобразование hostname -> ip (gethostbyname). Этот тип запросов применяется также для распознавания SNSD [1]. Можно указать сервис и общая форма представления такого запроса имеет вид

                hostname:service -> ip

Если сервис не указан, будет применяться 0-service.

Например, если нужно найти адрес хостинга сервиса http хоста depausceve, запрос может иметь вид

                depausceve:80

Формирование запросов описано в 6. Вопросы.

QTYPE = 1

Обратное преобразование ip -> host.

QTYPE =2

Глобальный запрос для всех служб указанного хоста. Областью запроса является Ntk.

4. Область запроса

Запрос можно сформулировать для поиска того или иного объекта в сети netsukuku или internet. При использовании протокола ANDNS область запроса указывается битами NK (см. 2. Заголовки).

Если используется протокол DNS, нужно формулировать запрос с неким суффиксом. Если запрос сделан для google.it.int (или google.it.INT), он будет относиться к internet. Запрос google.it.ntk (или google.it.NTK) будет относиться к сети netsukuku. Если суффикс не задан, по умолчанию областью запроса служит Netsukuku

Элемент dns_wrapper сначала определяет суффикс для корректного выбора области запроса. Найденный суффикс удаляется и запрос выполняется в соответствующей области.

5. RCODE

Это поле содержит код результата выполнения запроса. В пакетах с вопросом поле всегда имеет значение 0. Возможные коды в ответах перечислены ниже.

RCODE = 0 No Error

Пакет содержит ответы (ANSWERS), число которых указывается полем ANCOUNT (см. 2. Заголовки).

RCODE = 1 Interpretation Error

Сервер не понял запроса (запрос сформирован некорректно).

RCODE = 2 Server Fail

Сервер столкнулся с ошибкой при обработке корректного запроса.

RCODE = 3 No Such Domain

Искомого объекта не существует.

RCODE = 4 Not Implemented

Данный тип запросов не реализован на этом сервере.

RCODE = 5 Refused

Сервер отказывается взаимодействовать с вами.

Отметим, что выражение (RCODE XOR ANCOUNT) всегда истинно. Если RCODE содержит ту или иную ошибку (RCODE!=0), в пакете не будет ответа. Если же RCODE = 0 (нет ошибок), пакет содержит тот или иной ответ.

6. Вопросы

Формат вопроса зависит от QTYPE.

Case QTYPE = 0 (h2ip) и Realm=NTK

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                    SERVICE                    |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |       
        |                                               |       
        |                                               |
        |                   HOSTNAME                    |
        |                     HASH                      |
        |                     (HH)                      |
        |                                               |
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

SERVICE — 2-байтовое поле, представляющее значение сервиса SNSD [1].

HH — 16-байтовое хэш-значение имени хоста (hostname).

QTYPE = 0 (h2ip) и Realm=INET

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   SERVICE                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   RDLENGTH                    |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |
        \                                               \
        \                    RDATA                      \
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

SERVICE — 2-байтовое поле, представляющее значение сервиса SNSD [1]. В данный момент для преобразований INET сервис ограничен значением 25 (предполагается TCP) или 0.

RDLENGTH — размер RDATA.

RDATA — строка имени хоста с учетом strlen(RDATA)=RDLENGTH.

QTYPE = 1 (ip2h)

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |
        /                     RDATA                     /
        /                                               /
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

RDATA — адрес IP в двоичном формате. Размер поля (4 или 16 байтов) зависит от поля I в заголовке.

QTYPE = 2 (глобальный запрос)

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |       
        |                                               |       
        |                                               |
        |                   HOSTNAME                    |
        |                     HASH                      |
        |                     (HH)                      |
        |                                               |
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

HH — 16-байтовое хэш-значение имени хоста (hostname).

7. Ответы

QTYPE=0 (h2ip)

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |  | T|     WG          |       PRIO            |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |
        /                     RDATA                     /
        /                                               /
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Бит T устанавливается (1), если ответ содержит IP. T = 0 говорит о том, что ответ содержит хэш hostname.

WG указывает «вес» ответа [1].

PRIO — приоритет [1].

RDATA содержит двоичный адрес IP, размер которого определяется битом I в заголовке, или хэш hostname.

QTYPE=1 (ip2h)

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                    RDLENGTH                   |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |
        /                     RDATA                     /
        /                                               /
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

RDLENGTH — размер RDATA (RDATA — имя хоста).

RDATA — распознанное имя хоста.

QTYPE=2 (глобальный запрос)

При QTYPE=2 перед ответом помещается дополнительное поле заголовка

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                    ANCOUNT                    |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Эти 2 байта указывают число ответов, порожденных запросом. Отметим, что поле ANCOUNT в основном заголовке будет иметь значение 1, если RCODE=0, и 0 в противном случае. Эти два байта указывают реальное число ответов для случая QTYPE=2.

После дополнительного заголовка размещаются ответы в показанном на рисунке формате.

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        | M| T| P|  WG          |       PRIO            |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                    SERVICE                    |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |
        /                     DATA                      /
        /                                               /
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Бит T указывает тип DATA (T для Hostname и 1 для IP).

Бит M устанавливается при установленном бите T и показывает, что это MAIN_IP для hostname.

P — протокол (0 для TCP, 1 для UDP).

При T=1 версия IP указывается в основном заголовке. Если T=0, данные имеют формат

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |       
        |                                               |       
        |                                               |
        |                   HOSTNAME                    |
        |                     HASH                      |
        |                     (HH)                      |
        |                                               |
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

HH — 16-байтовое хэш-значение SNSD hostname.

При T=1 данные имеют показанный на рисунке формат

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |
        /                    RDATA                      /
        /                                               /
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

RDATA — двоичное представление IP, размер которого зависит от бита I в основном заголовке (4 для IPv4, 16 для IPv6).

8. Сжатие

Формат сжатого пакета показан на рисунке.

        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                      ID                    | R|
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |QR| P| Z| QT  |  ANCOUNT  |I |   NK|   RCODE   |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                     USIZE                     |
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                                               |
        /                     DATA                      /
        /                                               /
        |                                               |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Заголовки остаются не сжатыми. Содержимое пакета, вопрос и ответы сжимаются с помощью zlib. Буфером, для сжатия является DATA. Поле USIZE показывает исходный размер содержимого пакета (вопрос и ответы). Для сжатого пакета устанавливается Z=1.

[1] NTC_RFC 0009 http://netsukuku.freaknet.org/main_doc/ntk_rfc/Ntk_SNSD

Перевод на русский язык

Николай Малых

nmalykh@protocols.ru

Рубрика: Фрактальные сети | Комментарии к записи Протокол ANDNS отключены

P4 — программируемые, независимые от протокола процессоры пакетов

image_print

P4: Programming Protocol-Independent Packet Processors

P4 — программируемые, независимые от протокола процессоры пакетов

Pat Bosshart1, Dan Daly2, Glen Gibb1, Martin Izzard1, Nick McKeown3, Jennifer Rexford4, Cole Schlesinger4, Dan Talayco1, Amin Vahdat5, George Varghese6, David Walker4

PDF

Тезисы

P4 — язык высокого уровня для программирования независимых от протоколов сетевых процессоров. P4 работает совместно с протоколами управления SDN, такими как OpenFlow. В настоящее время OpenFlow явно задает протокольные заголовки, с которыми ведется работа. Набор этих полей расширился за несколько лет с 12 до 41, что усложнило спецификацию, но не обеспечивает достаточной гибкости добавления новых заголовков. В этой статье предлагается язык P4 как вариант будущего развития OpenFlow. Преследуются три цели: (1) возможность изменения конфигурации в «полевых» условиях, (2) независимость от протоколов (коммутатору не следует опираться на какой-либо из имеющихся протоколов) и независимость от платформы, позволяющая программистам описывать функциональность обработки пакетов без учета специфики оборудования, на котором будет происходить обработка. Например, будет описано, как можно использовать P4 для настройки коммутатора с целью добавления новой иерархической метки.

1. Введение

Программно-определяемые сети (SDN7) дают операторам возможность программного управления их сетями. В SDN уровень управления физически отделен от уровня пересылки и один уровень управления может контролировать множество устройств пересылки. Хотя устройства пересылки могут программироваться множеством способов, наличие общего, открытого и независимого от производителей интерфейса (такого как OpenFlow) позволяет уровню управления контролировать устройства с оборудованием и программами разных производителей.

Таблица 1. Поля, распознаваемые стандартом OpenFlow.

Версия

Дата выпуска

Число полей заголовков

OF 1.0

декабрь 2009

12 (Ethernet, TCP/IPv4)

OF 1.1

февраль 2011

15 (MPLS, межтабличные метаданные)

OF 1.2

декабрь 2011

36 (ARP, ICMP, IPv6 и т. п.)

OF 1.3

июнь 2012

40

OF 1.4

октябрь 2013

41

Интерфейс OpenFlow начинался с простой абстракции, содержащей 1 таблицу правил, которая позволяла сопоставлять пакеты по дюжине полей заголовков (например, адреса MAC и IP, протокол, номера портов TCP/UDP и т. п.). За 5 лет спецификация сильно расширилась и усложнилась (Таблица 1), были добавлены другие поля заголовков и многоэтапные таблицы правил, позволяющие коммутаторам раскрыть больше своих возможностей контроллеру.

Процесс расширения числа полей не показывает признаков остановки. Например, операторы ЦОД8 все чаще хотят применять новые формы инкапсуляции пакетов (например, NVGRE, VXLAN, STT) и для этого развертывают программные коммутаторы, функциональность которых проще расширить. Вместо безостановочного расширения спецификации OpenFlow мы предлагаем поддерживать в будущих коммутаторах гибкие механизмы анализа и сопоставления полей пакетов, позволяющие контроллерам расширять свои возможности, используя базовый открытый интерфейс (например, новый OpenFlow 2.0 API). Такой обобщенный расширяемый подход будет проще, элегантней и перспективней сегодняшних стандартов OpenFlow 1.x.

   
Рисунок 1. P4 как язык программирования коммутаторов.


Недавно разработанные микросхемы показывают, что такая гибкость может быть достигнута в ASIC при терабитных скоростях [1, 2, 3]. Программирование нового поколения микросхем коммутации далеко не просто. Каждая микросхема имеет свой низкоуровневый интерфейс, похожий на программирование микрокода. В этой статье кратко описан язык высокого уровня для программирования независимых от протоколов процессоров пакетов P49. На рисунке 1 показаны связи между P4, используемым для настройки коммутатора (как обрабатывать пакеты), и имеющимися интерфейсами API (такими, как OpenFlow), которые предназначены для заполнения таблииц пересылки в коммутаторах с фиксированной функциональностью. P4 поднимает уровень абстракции для программирования сети и может служить базовым интерфейсом между контроллером и коммутаторами. Предполагается, что будущие версии OpenFlow позволят кнтроллеру сообщать коммутаторам, как им следует работать, а не ограничиваться заданием фиксированной конфигурации. Основной задачей является поиск баланса между выразительностью языка и простотой реализации на разных программных и аппаратных коммутаторах. При разработке P4 ставились три основных цели, описанные ниже.

  • Настраиваемость. Контроллер должен иметь возможность переопределять анализ и обработку пакетов в процессе работы.

  • Независимость от протоколов. Коммутатор не должен быть привязан к определенному формату пакетов. Вместо этого контроллеру следует предоставить возможность задать (i) анализатор для извлечения полей заголовков по именам и типам, а также (ii) набор типизованных таблиц «сопоставление-действие» (match+action) для обработки этих заголовков.

  • Независимость от платформы. Как программист C может абстрагироваться от специфики процессора (CPU), так и программисту контроллеров следует обеспечить возможность не знать деталей работы коммутатора, для которого программа предназначена. Компилятор должен учитывать возможности коммутатора при преобразовании независимого от платформы описания (на языке P4) в предназначенную для целевой платформы программу для найтройки конфигурации коммутатора.

В статье сначала вводится абстрактная модель пересылки в коммутаторе. Затем разъясняется необходимость создания нового языка для описания независимой от протоколов обработки пакетов. После этого рассматривается простой пример, когда оператор хочет поддерживать новое поле заголовка и обрабатывать пакеты в несколько этапов. Это служит для объяснения того, как P4 программирует заголовки, анализатор пакетов, множество таблиц match+action и потоки управления. В заключение описано, как компилятор P4 может отображать программы на целевые коммутаторы.

Предшествующие работы. В 2011 году Yadav с соавторами [4] предложили абстрактную модель пересылки для OpenFlow, но без акцента на компиляторы. Kangaroo [1] ввел понятие программируемого анализа. Недавно Song [5] предложил не связанную с протоколом пересылку, которая соответствует заявленным в статье целям, но ориентирована на сетевые процессоры. В ONF были разработаны шаблоны типизации таблиц для описания возможностей сопоставления в коммутаторах [6]. Недавняя работа NOSIX [7] соответствует цели гибкого задания таблиц match+action, но не рассматривает независимость от протоколов и язык для задания анализаторов, таблиц и управления потоками. В других недавних работах предлагается программируемый интерфейс с уровнем данных для мониторинга, контроля перегрузок и управления очередями [8, 9]. Модульный маршрутизатор Click [10] поддерживает гибкую обработку пакетов на программном уровне но не отображает ее на разные аппаратные платформы коммутации.

2. Абстрактная модель пересылки

В предлагаемой абстрактной модели (Рисунок 2) коммутатор пересылает пакеты через программируемый анализатор, за которым следует несколько этапов «сопоставление-действие», выполняемых последовательно, параллельно или в комбинации этих вариантов. Выведенная из OpenFlow, эта модель имеет три обобщения. Во-первых, OpenFlow предполагает фиксированный анализатор, а новая модель — программируемый, который позволяет определять новые заголовки. Во-вторых, OpenFlow предполагает последовательные этапы match+action, а в новой модели могут использоваться также параллельные. В третьих, новая модель предполагает транзакции на основе независимых от протокола примитивов, поддерживаемых коммутатором.

 
Рисунок 2. Абстрактная модель пересылки.


Эта модель обобщает обработку пакетов в разных устройствах пересылки (например, в коммутаторах Ethernet, балансировщиках нагрузки, маршрутизаторах) на основе разных технологий (например, коммутаторы на основе ASIC и NPU с фиксированной функциональностью, перенастраиваемые и программные коммутаторы, FPGA). Это позволяет разработать общий язык (P4) описания обработки пакетов. Это дает программистам возможность создавать независимые от платформы программы, которые компилятор преобразует в разные устройства пересылки — от небольших и сравнительно медленных коммутаторов до высокопроизводительных устройств на базе ASIC.

Управление моделью пересылки включает два типа операций — настройку (Configure) и заполнение (Populate). Операции настройки программируют анализатор, задают порядок этапов match+action, а также указывают поля заголовков, обрабатываемые на каждом этапе. Конфигурация определяет поддерживаемые протоколы и способы обработки пакетов коммутатором. Операции заполнения добавляют и удаляют записи в таблицы match+action, заданные при настройке конфигурации. Заполнение определяет правила, применяемые к пакетам в каждый момент.

В этой статье фазы настройки и заполнения считаются раздельными. В частности, коммутатору не требуется обрабатывать пакеты в процессе настройки конфигурации. Однако предполагается, что реализации будут поддерживать обработку пакетов в процессе полной или частичной перенастройки конфигурации, что позволит обновлять коммутаторы без прерывания работы. Модель осознанно допускает и поддерживает перенастройку конфигурации без прерывания пересылки.

Очевидно, что фаза настройки имеет мало значения для коммутаторов ASIC с фиксированной конфигурацией. В этом случае задача компилятора состоит лишь в проверке поддержки коммутатором программ P4. Instead, our goal is to capture the general trendtowards fast reconfigurable packet-processing pipelines, asdescribed in [2, 3].

Принимаемые пакеты сначала обрабатываются анализатором. Предполагается, что тело пакета (без заголовков) буферизуется отдельно и недоступно для операций сопоставления. Анализатор распознает и извлекает поля заголовка, определяя протоколы, поддерживаемые коммутатором. Модель не включает допущений о назначении протокольных заголовков , считая лишь, что анализируемое представление определяет набор полей для которых применяются сопоставления и действия.

Извлеченные поля заголовков передаются в таблицы match+action. Эти таблицы делятся на входные и выходные. Хотя оба типа таблиц могут менять заголовки пакетов, входные таблицы определяют выходной порт или порты и очередь, в которую помещается пакет. На основе входной обработки пакет может быть переслан, реплицирован (для групповой рассылки проброса или отправки на уровень упрапвления), отброшен, а также могут выполняться действия потока управления. Выходные таблицы match+action вносят изменения в заголовки отдельных пакетов (например, для группового копирования). С потоком можно связать таблицы действий (счетчики, указатели и т. п.) для отслеживания состояний кадр за кадром.

Пакеты могут переносить между этапами дополнительную информацию (метаданные), которые трактуются аналогично полям заголовков. Примерами метаданных могут служить входной порт, направление передачи и очередь, временная метка и передаваемые между таблицами данные, которые не связаны с полученным при анализе пакета представлением (например, идентификатор VLAN).

Дисциплины очередей обрабатываются как в OpenFlow — действия сопоставляют пакеты с очередями, для которых настроена определенная дисциплина обслуживания. Эти дисциплины (например, минимальная скорость, DRR) выбираются при настройке конфигурации коммутатора.

Хотя это и не рассматривается в статье, могут добавляться примитивы действий, позволяющие программистам реализовать новые или имеющиеся протоколы контроля перегрузок. Например, коммутатор можно запрограммировать на установку бита ECN на основании новых условий или задать свой механизм контроля перегрузок с использованием таблиц match+action.

3. Язык программирования

Абстрактная модель пересылки используется для определения языка, позволяющего выразить конфигурацию коммутатора и способы обработки пакетов. Основной целью статьи является предложение языка программирования P4. Однако ясно, что возможно существование множества языков, обладающих описываемыми здесь характеристиками. Например, языки должны выражать способы программирования анализаторов, чтобы те знали какой формат пакетов следует ожидать. Поэтому программисту нужен способ указания возможных типов. Например, программист может задать формат заголовков IPv4 и указать какие заголовки могут следовать после заголовка IP. Это служит мотивом определения анализа в P4 путем объявления допустимых типов заголовков. Например, поля TTL должны декрементироваться и проверяться, может потребоваться добавление новых туннельных заголовков, а также расчет контрольных сумм. Это побуждает использовать в P4 обязательную программу для описания обработки полей заголовков, использующую объявленные типы заголовков и примитивы набора действий.

Можно применять такие языки как Click [10], которые создают коммутаторы из модулей, написанных на C++. Язык Click является очень выразительным и хорошо подходит для описания обработки пакетов в ядре CPU. Но он недостаточно ограничен для рассматриваемой задачи, поскольку она требует языка, отображающего конвейеры parse-match-action на конкретное оборудование. Кроме того, язык Click не предназначен для архитектуры «контроллер-коммутатор» и не позволяет программистам описать таблицы match+action, которые динамически заполняются четко типизованными правилами. Наконец, в Click сложно вывести зависимости, ограничивающие параллельное выполнение.

Язык описания обработки пакетов должен позволять программисту выразить (явно или неявно) любую последовательность зависимостей между полями заголовка. Зависимости определяют какие таблицы можно применять параллельно. Например, требуется последовательное применение для таблицы маршрутизации IP и таблицы ARP, поскольку данные этих таблиц связаны зависимостью. Зависимости можно найти анализируя графы зависимости таблиц (TDG10). Эти графы описывают входные данные полей, действия и поток управления обменом данными между таблицами. На рисунке 3 показан пример графа зависимостей между таблицами для коммутатора L2/L3. Узлы TDG отобразаются непосредственно на таблицы match+action и анализ зависимостей показывает, где каждая из таблиц может размещаться в конвейере обработки. К сожалению TDG неохотно воспринимаются большинством программистов, которые предпочитают использовать для алгоритмов обработки пакетов императивные конструкции вместо графов.

В результате предлагается двухэтапный процесс компиляции. На верхнем уровне программисты задают программы обработки пакетов с использованием императивного языка, представляющего поток управления (P4), затем компилятор транслирует представление P4 в TDG для упрощения анализа зависимостей. В заключение TDG отображается на конкретную платформу коммутации. Компилятор P4 предназначен для упрощения трансляции программ P4 в TDG. Таким образом, P4 можно рассматривать как компромисс между общностью (скажем, Click), которая осложняет обнаружение зависимостей и их отображение на оборудование, и гибкостью OpenFlow 1.0, которая не позволяетперенастраивать протокольную обработку.

 
Рисунок 3. Граф связей между таблицами в коммутаторе L2/L3.


4. Пример использования языка P4

Рассмотрим P4 на простом примере. Многие сети разделены на ядро (core) и периферию (edge), оконечные хосты подключаются к периферийным устройствам, которые соединены между собой через высокопроизводительное ядро. Для поддержки такой архитектуры разработаны специальные протоколы (например, MPLS [11] и PortLand [12]), нацеленные на упрощение пересылки в ядре.

Рассмотрим пример сети L2 со стоечными коммутаторами (ToR11), связанные через двухуровневое ядро. Предположим, что число хостов возросло и таблицы L2 переполняются. MPLS помогает упростить ядро, но реализация протокола распространения меток со множеством тегов является непростой задачей. Протокол PortLand представляется интересным, но он требует переписывания MAC-адресов (это может препятствовать работе отладочных инструментов в сети), а также использования новых агентов для обработки запросов ARP. P4 позволяет описать решение с минимальными изменениями архитектуры сети. В приведенном примере mTag объединяет иерархическую маршрутизацию PortLand с простыми тегами в стиле MPLS. Маршруты через ядро представляются 32-битовыми метками, состоящими из 4 однобайтовых полей. Такая метка может указывать маршрут, заданный отправителем (source route) или указатель получателя (destination locator), подобно PortLand Pseudo MAC. Каждому коммутатору в ядре нужно проверить лишь один байт метки и выполнить коммутацию не его основе. В примере это метка, добавленная первым коммутатором ToR, но она может добавляться и сетевым адаптером хоста. NIC. Пример mTag преднамеренно упрощен для фокусировки на языке P4. Программа P4 для реального коммутатора будет значительно больше и сложнее.

4.1 Концепции P4

Программа P4 содержит определения перечисленных ниже компонент.

  • Заголовки (Header). Определение заголовка описывает порядок и структуру последовательности полей, включая их размеры и ограничения для возможных значений.

  • Анализаторы (Parser). Определение унализатора указывает способы идентификации заголовков и корректный порядок заголовков в пакетах.

  • Таблицы (Table). Таблицы «сопоставление-действие» (match+action) служат механизмами обработки пакетов. Программа P4 задает поля, которые могут использоваться в сопоставлениях и действиях.

  • Действия (Action). P4 поддерживает создание сложных действий (операций) из простых примитивов, независимых от протоколов. Эти операции доступны в таблицах match+action.

  • Программы управления (Control Program) определяют порядок применения к пакету таблиц match+action. Это простая императивная программа, описывающая прохождения пакета через таблицы.

Далее описано использование этих компонент для определения идеализированного процессора mTag в P4.

4.2 Форматы заголовков

Разработка начинается с задания форматов заголовков. Для этого было предложено несколько языков с разными сферами применения [13, 14, 15], которые были заимствованы в P4. В общем случае каждый заголовок указывается путем задания упорядоченного списка имен полей с их размерами. Необязательные аннотации полей позволяют ограничить диапазоны значений или максимальный размер полей переменного размера. Например, стандартные заголовки Ethernet и VLAN можно задать, как показано ниже.

header ethernet {
	fields {
		dst_addr : 48; // размер в битах
		src_addr : 48;
		ethertype : 16;
	}
}
header vlan {
	fields {
		pcp : 3;
		cfi : 1;
		vid : 12;
		ethertype : 16;
	}
}

Заголовок mTag можно добавить без влияния на имеющиеся определения. Имена полей показывают, что ядро имеет два уровня агрегирования. Каждый коммутатор ядра программируется с использованием правил для проверки одного из байтов по его местоположению в иерархии и направлению (вверх или вниз).

header mTag {
	fields {
		up1 : 8;
		up2 : 8;
		down1 : 8;
		down2 : 8;
		ethertype : 16;
	}
}

4.3 Анализатор пакетов

P4 предполагает, что коммутатор может реализовать машину состояний (конечный автомат), которая перебирает заголовоки пакета от начала к концу, извлекая значения по мере их поступления. Полученные значения полей передаются в таблицы match+action для обработки. P4 описывает машину состояний напрямую как набор переходов от одного заголовка к другому. Каждый из переходов может быть вызван значениями в текущем заголовке. Например, машину состояний mTag можно описать, как показано ниже.

parser start {
	ethernet;
}
parser ethernet {
	switch(ethertype) {
		case 0x8100: vlan;
		case 0x9100: vlan;
		case 0x800: ipv4;
		// Другие варианты
	}
}
parser vlan {
	switch(ethertype) {
		case 0xaaaa: mTag;
		case 0x800: ipv4;
		// Другие варианты
	}
}
parser mTag {
	switch(ethertype) {
		case 0x800: ipv4;
		// Другие варианты
	}
}

Анализ начинается из состояния start и выполняется до следующего явного состояния stop или возникновения особой (не обрабатываемой) ситуации, которая может считаться ошибкой. Извлеченные заголовки передаются в обработку match+action в конвейере коммутатора.

Анализатор для mTag очень прост и имеет лишь 4 состояния. В реальных сетях анализаторы включают гораздо больше состояний. Например, анализатор, определенный Gibb и др. [16, рисунок 3(e)], имеет сотни состояний.

4.4 Задание таблиц

Затем программист описывает, как указанные поля заголовков сопоставляются на этапах match+action (например, точное или шаблонное соответствие) и какие действия выполняются при совпадении.

В примере mTage периферийный коммутатор сопоставляет получателя L2 destination и VLAN ID, а затем выбирает mTag для добавления в заголовок. Программист определяет таблицу для сопоставления с этими полями и применения действия по добавлению заголовка mTag (см. ниже). Атрибут reads указывает сопоставляемые поля с учетом типа сопоставления (точное или иное). Атрибут actions указывает действия, которые могут быть выполнены в таблице применительно к пакету. Эти действия рассматриваются в следующем параграфе. Атрибут maxsize задает число элементов, которые могут быть включены в таблицу.

Спецификация таблицы позволяет компилятору определить размер требуемой для нее памяти и тип этой памяти (например, TCAM или SRAM).

table mTag_table {
	reads {
		ethernet.dst_addr : exact;
		vlan.vid : exact;
	}
	actions {
		// В процессе работы записи программируются
		// параметрами действия mTag.
		add_mTag;
	}
	max_size : 20000;
}

Для полноты и последующего обсуждения представлены краткие определения других таблиц, на которые ссылается программа управления (4.6 Программа управления).

table source_check {
	// Проверять mtag только на портах в ядро
	reads {
		mtag : valid; // mtag был проанализирован?
		metadata.ingress_port : exact;
	}
	actions { // Каждая запись таблицы задает 1 действие.
		// Если mTag не применим, выполняется передача в CPU 
		fault_to_cpu;
		// При наличии метки mtag она вырезается и записывается в метаданные
		strip_mtag;
		// В противном случае обработка пакета продолжается
		pass;
	}
	max_size : 64; // Одно правило на порт
}
table local_switching {
	// Определяется получатель и проверяется его локальность
	// При отсутствии переход в таблицу mtag.
}
table egress_check {
	// Проверяется определение выходного порта.
	// Пакеты м меткой не помечаются заново
	// Считывается выходной порт и проверяется наличие mTag
}

4.5 Задание действий

P4 определяет набор примитивой действий (операций), из которых можно создавать более сложные операции. Каждая программа P4 задает набор функций-действий, состоящих из таких примитивов. Эти функции просто определяют спецификации и заполнение таблиц. P4 предполагает параллельное выполнение примитивов внутри функций (коммутаторы, не поддерживающие параллельное выполнение могут исключить его).

Действие по добавлению mTag, упомянутое выше, реализуется в показанной ниже форме.

action add_mTag(up1, up2, down1, down2, egr_spec) {
	add_header(mTag);
	// Копируется VLAN ethertype в mTag
	copy_field(mTag.ethertype, vlan.ethertype);
	// Устанавливается ethertype для VLAN с целью указания mTag
	set_field(vlan.ethertype, 0xaaaa);
	set_field(mTag.up1, up1);
	set_field(mTag.up2, up2);
	set_field(mTag.down1, down1);
	set_field(mTag.down2, down2);
	// Указывается выходной порт
	set_field(metadata.egress_spec, egr_spec);
}

Если действию нужны параметры (например, значение up1 для mTag), они представляются из таблицы сопоставления.

В этом примере коммутатор помещает mTag после тега VLAN, копирует VLAN Ethertype в mTag и устанавливает Ethertype для тега VLAN в 0xaaaa для указания mTag. Обратная операция вырезания mTag из пакета и таблица для применения этого действия в периферийных коммутаторах не показаны.

Примитивы действий P4 включают:

  • set_field устанавливает значение заданного поля в заголовке (поддерживаются маски полей);

  • copy_field копирует одно поле в другое;

  • add_header указывает конкретный экземпляр заголовка (и все его поля) как действительный (пригодный);

  • remove_header удаляет (выталкивает — pop) заголовок (и все его поля) из пакета;

  • increment инкрементирует или декрементирует значение поля;

  • checksum рассчитывает контрольную сумму для некоторых полей заголовка (например, IPv4).

Предполагается, что большинство реализаций коммутаторов будет ограничивать выполнение действий изменениями заголовков, совместимыми с заданным форматом пакетов.

4.6 Программа управления

После определения таблиц и действий остается лишь задать поток управления из одной таблицы в следующую. Этот поток задается как программа из набора функций, условий и ссылок на таблицы.

 
Рисунок 4. Диаграмма переходов для mTag.


На рисунке 4 приведено графическое представление желаемого потока управления для реализации mTag на периферийном коммутаторе. После анализа таблица source_check проверяет согласованность полученного пакета и входного порта. Например, меткам mTag следует появляться только на портах, подключенных к коммутаторам ядра. таблица source_check также вырезает метки mTag из пакетов, записывая факт их наличия в метаданные. Последующие табоицы конвейера могут сопоставлять эти метаданные, чтобы пакет не был помечен заново. Затем применяется локальная таблица коммутации. Если таблица показывает «отсутствие», это говорит о том, что пакет не адресован ни одному из локально подключенных хостов. В этом случае к пакету применяется таблица mTag (см. выше). Управление локальной пересылкой и пересылкой в ядре может осуществляться в таблице egress_check, которая обрабатывает пакеты для неизвестных адресатов путем отправки уведомления стеку управления SDN. Императивное представление такого конвейера обработки пакетов приведено ниже.

control main() {
	// Проверка согласованности состояния mTag и порта
	table(source_check);
	// При отсутствии ошибок в source_check обработка продолжается
	if (!defined(metadata.ingress_error)) {
		// Попытка коммутации оконечным хостам
		table(local_switching);
		if (!defined(metadata.egress_spec)) {
			// Нет известного локального хоста, попытка установить mTag
			table(mTag_table);
		}
		// Проверка неизвестного выходного состояния или неверной
		// перемаркировки (retagging) с использованием mTag.
		table(egress_check);
	}
}

5. Компиляция программ P4

Для реализации в сети программ P4 нужен компилятор, отображающий независимое от платформы описание на оборудование конкретного целевого коммутатора или программную платформу. Это включает выделение ресурсов целевой платформы и создание подходящей для устройства конфигурации.

5.1 Компиляция анализатора пакетов

Для устройств с программируемыми анализаторами компилятор преобразует описание анализатора в машину состояний, а для фиксированных анализаторов лишь проверяет совместимость описания с анализатором целевой платформы. Создание машины состояний и записей талицы состояний описано в [16].

В таблице 2 показаны записи таблицы состояний для разделов анализатора vlan и mTag (4.3 Анализатор пакетов). Каждая запись указывает текущее состояние соответствующее значение поля и следующее состояние. Остальные элементы записи для краткости опущены.

Таблица 2. Записи таблицы состояний анализатора для примера mTag.

Текущее состояние

Искомое значение

Следующее состояние

vlan

0xaaaa

mTag

vlan

0x800

ipv4

vlan

*

stop

mTag

0x800

ipv4

mTag

*

stop

5.2 Компиляция программ управления

Императивное представление потока управления в параграфе 4.6 Программа управления является удобным способом задания логического поведения коммутатора при пересылке, но не связано явно с зависимостями между таблицами и возможностью параллельного выполнения. Поэтому компилятор используется для обнаружения зависимостей и определения возможностей параллельного выполнения. В финале компилятор генерирует целевую конфигурацию для коммутатора. Имеется множество разных целевых систем, например, программные коммутаторы [17], многоядерные программные коммутаторы [18], NPU [19], коммутаторы с фиксированной конфигурацией [20], конвейеры с перенастраиваемой таблицей сопоставления (RMT12) [2].

Как было отмечено в раздел 3. Язык программирования, компилятор использует двухэтапную трансляцию. Сначала преобразуется программа управления на языке P4 с промежуточный граф зависимостей, который анализируется для поиска зависимостей между таблицами. Затем зависящий от целевой платформы транслятор (back-end) отображает граф на соответствующие ресурсы коммутатора.

Ниже кратко описана возможная реализация mTag в коммутаторах разных типов.

Программные коммутаторы обеспечивают полную гибкость — число таблиц, их конфигурация и анализатор управляются на программном уровне. Компилятор напрямую отображает граф таблицы mTag на таблицы коммутатора. Компилятор использует информацию о типе таблиц для ограничения их размеров и критериев сопоставления (например, точное, по префиксу или шаблону) для каждой таблицы. Компилятор может также оптимизировать сопоставление со структурами данных программы.

Аппаратные коммутаторы с RAM и TCAM. Компилятор может настроить хэширование для проверки точного совпадения с использованием RAM для периферийных коммутаторов mTag. В коммутаторах ядра таблица пересылки mTag, соответствующая подмножеству битов тега, будет отображаться в TCAM.

Коммутаторы, поддерживающие параллельные таблицы. Компилятор может обнаружить зависимости между данными и настроить таблицы для параллельного или последовательного применения. В примере mTag таблицы mTag и локальная коммутация могут выполняться параллельно выполнению действий по установке mTag.

Коммутаторы, применяющие действия в конце конвейера. Для таких коммутаторов компилятор может задать на промежуточных этапах создание метаданных, которые будут применяться при финальной записи. В примере mTag добавление или удаление mTag может быть представлено в метаданных.

Коммутаторы с малым числом таблиц. Компилятор может отображать большое число таблиц P4 на меньшее число физических таблиц. В примере mTag локальная коммутация может комбинироваться с таблицей mTag. При установке коммутатором новых правил в процессе работы, компилятор транслирует «составные» правила в две таблицы P4 для генерации одной физической таблицы.

6. Заключение

SDN позволяет одному уровню управления напрямую контролировать целую сеть коммутаторов. OpenFlow поддерживает эту цель, обеспечивая один, независимый от производителя интерфейс API. Однако сегодняшние коммутаторы OpenFlow с фиксированной функциональностью распознают лишь предопределенный набор полей и обрабатывают пакеты, используя лишь небольшой набор предопределенных действий. Уровень управления не может выразить способ наиболее эффективной обработки пакетов в соответствии с требованиями программ управления.

Здесь предложен новый шаг к созданию более гибких коммутаторов, конфигурация которых задается (и может быть изменена) в полевых условиях. Программист задает обработку пакетов уровнем пересылки, не заботясь о деталях реализации. Компилятор преобразует императивную программу в граф зависимостей между таблицами, который может быть отображен на конкретные целевые коммутаторы с учетом оптимизации под конкретное оборудование.

Подчеркнем, что это лишь первый шаг, подготовленный как вклад в обсуждение OpenFlow 2.0. В этом предложении некоторые аспекты коммутаторов остаются неопределенными (например, примитивы контроля перегрузок, дисциплины очередей, мониторинг трафика). Однако предполагается, что наличие языка управления конфигурацией и компилятора, генерирующего низкоуровневые конфигурации для целевых устройств, обеспечат будущим коммутаторам большую гибкость и раскроют возможности программно-определяемых сетей.

7. Литература

[1] C. Kozanitis, J. Huber, S. Singh, and G. Varghese, “Leaping multiple headers in a single bound: Wire-speed parsing using the Kangaroo system,” in IEEE INFOCOM, pp. 830–838, 2010.

[2] P. Bosshart, G. Gibb, H.-S. Kim, G. Varghese,N. McKeown, M. Izzard, F. Mujica, and M. Horowitz,“ Forwarding metamorphosis: Fast programmable match-action processing in hardware for SDN,” in ACM SIGCOMM, 2013.

[3] “Intel Ethernet Switch Silicon FM6000.” http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ethernet-switch-fm6000-sdn-paper.pdf.

[4] N. Yadav and D. Cohn, “OpenFlow Primitive Set.” http://goo.gl/6qwbg, July 2011.

[5] H. Song, “Protocol-oblivious forwarding: Unleash the power of SDN through a future-proof forwarding plane,” in SIGCOMM HotSDN Workshop, Aug. 2013.

[6] “Openflow forwarding abstractions working group charter.” http://goo.gl/TtLtw0, Apr. 2013.

[7] M. Raju, A. Wundsam, and M. Yu, “NOSIX: A lightweight portability layer for the SDN OS,”ACM SIGCOMM Computer Communications Review, 2014.

[8] V. Jeyakumar, M. Alizadeh, C. Kim, and D. Mazieres, “Tiny packet programs for low-latency network control and monitoring,” in ACM SIGCOMM HotNetsWorkshop, Nov. 2013.

[9] A. Sivaraman, K. Winstein, S. Subramanian, andH. Balakrishnan, “No silver bullet: Extending SDN to the data plane,” in ACM SIGCOMM HotNets Workshop, Nov. 2013.

[10] E. Kohler, R. Morris, B. Chen, J. Jannotti, and M. F.Kaashoek, “The Click modular router,” ACM Transactions on Computer Systems, vol. 18,pp. 263–297, Aug. 2000.

[11] “Multiprotocol Label Switching Charter.” http://datatracker.ietf.org/wg/mpls/charter/.

[12] R. Niranjan Mysore, A. Pamboris, N. Farrington,N. Huang, P. Miri, S. Radhakrishnan, V. Subramanya, and A. Vahdat, “PortLand: A scalable fault-tolerant layer 2 data center network fabric,” in ACM SIGCOMM, pp. 39–50, Aug. 2009.

[13] P. McCann and S. Chandra, “PacketTypes: Abstract specification of network protocol messages,” in ACM SIGCOMM, pp. 321–333, Aug. 2000.

[14] G. Back, “DataScript — A specification and scripting language for binary data,” in Generative Programming and Component Engineering, vol. 2487, pp. 66–77,Lecture Notes in Computer Science, 2002.

[15] K. Fisher and R. Gruber, “PADS: A domain specific language for processing ad hoc data,” in ACM Conference on Programming Language Design and Implementation, pp. 295–304, June 2005.

[16] G. Gibb, G. Varghese, M. Horowitz, andN. McKeown, “Design principles for packet parsers,” in ANCS, pp. 13–24, 2013.

[17] “Open vSwitch website.” http://www.openvswitch.org.

[18] D. Zhou, B. Fan, H. Lim, M. Kaminsky, and D. G.Andersen, “Scalable, high performance ethernet forwarding with CuckooSwitch,” inCoNext, pp. 97–108, 2013.

[19] “EZChip 240-Gigabit Network Processor for Carrier Ethernet Applications.” http://www.ezchip.com/p_np5.htm.

[20] “Broadcom BCM56850 Series.” https://www.broadcom.com/products/Switching/Data-Center/BCM56850-Series.

Николай Малых

nmalykh@protocols.ru

1Barefoot Networks

2Intel

3Stanford University

4Princeton University

5Google

6Microsoft Research

7Software-Defined Networking

8Центр обработки данных

9Programming Protocol-independent Packet Processors.

10Table Dependency Graph

11Top-of-rack — букв., на вершине стойки.

12Reconfigurable match table

Рубрика: SDN, Языки сетевого программирования | Комментарии к записи P4 — программируемые, независимые от протокола процессоры пакетов отключены

Пакет tcpdump

image_print

PDF

http://www.tcpdump.org

Данный документ соответствует tcpdump версии 4.9.3 и libpcap версии 1.9.1.

Синтаксис

      tcpdump [ -AbdDefhHIJKlLnNOpqStuUvxX# ] [ -B buffer_size ] 
              [ -c count ] 
              [ -C file_size ] [ -G rotate_seconds ] [ -F file ] 
              [ -i interface ] [ -j tstamp_type ] [ -m module ] [ -M secret ] 
              [ --number ] [ -Q in|out|inout ] 
              [ -r file ] [ -V file ] [ -s snaplen ] [ -T type ] [ -w file ] 
              [ -W filecount ] 
              [ -E spi@ipaddr algo:secret,...  ] 
              [ -y datalinktype ] [ -z postrotate-command ] [ -Z user ] 
              [ --time-stamp-precision=tstamp_precision ] 
              [ --immediate-mode ] [ --version ] 
              [ expression ]

Программа tcpdump, включаемая во все дистрибутивы UNIX, выводит заголовки пакетов для указанных сетевых интерфейсов в соответствии с заданным логическим выражением. Программа также допускает использование с флагом -w для записи пакетов данных в файл, которым может впоследствии использоваться для анализа. Возможен и просмотр заголовков из таких файлов с помощью флага -r. Во всех случаях tcpdump имеет дело только с пакетами, соответствующими заданному логическому выражению (фильтру).

Tcpdump (если в команде не был указан флаг -c) продолжает собирать пакеты до тех пор, пока процесс не будет прерван сигналом SIGINT (например, при нажатии клавиш control-C) или SIGTERM (например, в результате команды kill(1)). Если команда используется с флагом -c, сбор пакетов кроме описанных выше способов может быть прекращен также после обработки определенного числа пакетов.

При завершении работы tcpdump выводит значения счетчиков:

  • собранных (captured) пакетов (число пакетов, полученных и обработанных tcpdump);

  • полученных фильтром (received by filter) пакетов; толкование этого значения зависит от ОС, под управлением которой работала программа tcpdump (в некоторых ОС указывается число пакетов независимо от числа совпадений с условиями фильтрации, а в других — число пакетов, соответствующих фильтрам);

  • отброшенных ядром (dropped by kernel) пакетов (число пакетов, отброшенных ядром по причине нехватки ресурсов или фильтрации внутри ядра).

На платформах, поддерживающих сигналы SIGINFO (например, BSD), могут выводиться значения перечисленных выше счетчиков по сигналу SIGINFO (этот сигнал может быть подан обычно с помощью клавиш control-T) без прерывания работы команды.

Отметим, что чтение пакетов из сетевого интерфейса может потребовать от пользователя специальных привилегий в зависимости от используемой ОС:

  • SunOS 3.x или 4.x с NIT или BPF
    требуется доступ для чтения к файлам устройств /dev/nit или /dev/bpf*.

  • Solaris с DLPI
    требуется доступ для чтения и записи к сетевому псевдо-устройству (например, /dev/le). На некоторых версиях Solaris таких прав недостаточно для работы tcpdump в режиме захвата1; в таких ситуациях для использования tcpdump требуются полномочия root или установка для tcpdump флага SUID (см. параграф Ошибка: источник перекрёстной ссылки не найден на стр. Ошибка: источник перекрёстной ссылки не найден). Отметим, что на многих (возможно, на всех) системах при работе устройства в обычном режиме вы не сможете видеть никаких исходящих пакетов, поэтому сбор данных в таком режиме может оказаться практически бесполезным.

  • HP-UX с DLPI
    требуются полномочия root или установка для tcpdump флага SUID.

  • IRIX с snoop
    требуются полномочия root или установка для tcpdump флага SUID.

  • Linux
    требуются полномочия root или установка для tcpdump флага SUID, если ваша система не использует ядро с поддержкой битов возможностей2 (таких, как CAP_NET_RAW). В последнем случае для вам потребуется установка бита CAP_NET_RAW для захвата пакетов и бита CAP_NET_ADMIN для просмотра списка устройств помощью опции -D. Для просмотра текущего состояния битов возможностей служит функция getcap, а для управления этими битами — setcap из библиотеки libcap. Дополнительную информацию о поддерживаемых битах возможностей вы найдете, воспользовавшись командой man capabilities.

  • ULTRIX и Digital UNIX/Tru64 UNIX
    всем пользователям разрешено использование программы tcpdump. Однако никому из пользователей не разрешено использовать режим захвата пакетов, пока администратор (super-user) не разрешит этот режим для данного интерфейса с помощью команды pfconfig. Захват принимаемых или передаваемых интерфейсом unicast-пакетов не будет возможен до тех пор, пока администратор (super-user) не включит для этого интерфейса режим copy-all с помощью команды pfconfig. Поскольку сбор пакетов обычно требует включения обоих упомянутых режимов, реальное использование tcpdump возможно только с позволения администратора.

  • BSD и Mac OS X
    требуется доступ для чтения к устройству /dev/bpf*. На системах BSD с поддержкой devfs (сюда относятся и системы Mac OS X) кроме установки принадлежности и прав доступа к устройствам BPF может потребоваться настройка конфигурации devfs, позволяющая задавать принадлежность и права доступа всякий раз при перезагрузке системы.

Чтение собранных пакетов из файла не требует специальных привилегий.

Опции tcpdump

Программа tcpdump позволяет в командной строке задать все опции сбора и отображения пакетов, а также спецификацию фильтров захвата, описанных ниже (параграф на стр. ). Таблица содержит список опций tcpdump и описание каждой их них. Отметим, что некоторые опции поддерживаются не всеми платформами.

Таблица 1. Опции командной строки tcpdump.

Опция

Описание

-A

Задает вывод каждого пакета (без заголовков канального уровня) в формате ASCII. Этот режим удобен для сбора трафика HTTP.

-b

Задает вывод номера автономной системы (AS) из пакетов протокола BGP в формате ASDOT вместо ASPLAIN.

-B <размер буфера>
--buffer-size=<размер буфера>

Задает размер буфера захвата пакетов для операционной системы в килобайтах (1024 байта).

-c <число пакетов>

Задает завершение работы программы после захвата заданного числа пакетов.

-C <размер файла>

Задает необходимость проверки размера файла захвата перед записью в него каждого нового пакета. Если размер файла превышает указанное значение параметра, прежний файл закрывается и создается новый файл для записи в него пакетов. Для файлов захвата используется имя, заданное параметром -w и, начиная со второго файла, к имени добавляется в качестве суффикса порядковый номер файла. Параметр задает размер файла в миллионах байтов (не в мегабайтах = 1 048 576 байт).

-d

Задает вывод дампа скомпилированного кода сопоставления пакетов в понятном человеку формате и завершение работы программы.

-dd

Выводит дамп кода сопоставления в виде фрагмента C-программы.

-ddd

Выводит дамп кода сопоставления в виде строки десятичных значений с префиксом в форме значения счетчика.

-D

Выводит список сетевых интерфейсов системы, с которых tcpdump может собирать пакеты. Для каждого сетевого интерфейса указывается имя и номер, за которыми может следовать текстовое описание интерфейса. Имя и номер интерфейса могут использоваться с флагом -i для задания сбора пакетов с одного интерфейса.

Эта опция может быть весьма полезна для систем, не дающих информации об имеющихся сетевых интерфейсах3.

Флаг -D не поддерживается, если программа tcpdump была скомпилирована со старой версией libpcap, которая не поддерживает функцию pcap_findalldevs().

-e

Выводит заголовок канального уровня в каждой строке дампа.

-E <algo:secret>

Задает использование алгоритма и секрета spi@ipaddr для расшифровки пакетов IPsec ESP, направленных по адресу ipaddr и содержащих and в поле Security Parameter Index значение spi. Комбинация spi и адреса может быть повторена с использованием в качестве разделителя запятой или новой строки. Отметим, что установка секрета для пакетов IPv4 ESP в настоящее время поддерживается. В качестве алгоритмов могут использоваться des-cbc, 3des-cbc, blowfish-cbc, rc3-cbc, cast128-cbc или none. По умолчанию применяется алгоритм des-cbc. Возможность дешифровки пакетов обеспечивается только в тех случаях, когда при компиляции tcpdump были включены опции поддержки криптографии. Параметр secret содержит ASCII-текст секретного ключа ESP. Если секрет начинается с символов 0x, будет считываться шестнадцатеричное значение. Опция предполагает использование ESP в соответствии с RFC 2406, а не RFC 1827. Эта опция поддерживается только для отладки и использовать ее с реальными секретными ключами не следует, поскольку введенный в командной строке ключ IPsec доступен другим пользователям системы4. Кроме явного указания параметров в командной строке их можно задать в файле опций, который tcpdump будет читать при получении первого пакета ESP.

-f

Задает вывод чужих адресов IPv4 в числовом формате. Использование этой опции позволяет избавиться от проблем, возникающих на серверах Sun NIS при попытках трансляции нелокальных адресов. Проверка чужеродности адреса IPv4 осуществляется с использованием адреса и маски принявшего пакет интерфейса. Если адрес и маска интерфейса недоступны (например, при использовании unnumbered-интерфейсов или при захвате пакетов со всех адресов в Linux с использованием фиктивного интерфейса any), эта опция будет работать некорректно.

-F <файл>

задает использование фильтров, содержащихся в указанном файле. В этом случае заданные в командной строке фильтры игнорируются.

-G rotate

Задает смену файла, заданного опцией -w каждые rotate секунд. Файлы будут именоваться в соответствии с опцией -w с добавлением верменной метки в формате strtime. Если формат временных меток не задан, новые файлы будут записываться вместо предшествующего. При использовании с опцией -C имена файлов будут иметь вид file<count>

-h
--help

Выводит информацию о текущих версиях tcpdump и libpcap, а также краткую справку о программе tcpdump, после чего завершает заботу.

--vervion

Выводит информацию о текущих версиях tcpdump и libpcap, после чего завершает заботу.

-H

Задает попытку декодировать заголовки 802.11s.

-i <интерфейс>
--interface=<интерфейс>

Задает сбор пакетов с указанного интерфейса. Если интерфейс не задан, tcpdump ищет в системе список доступных интерфейсов и выбирает в нем активное устройство с минимальным номером (исключая loopback).

В системах Linux, начиная с ядра 2.2 поддерживается фиктивный интерфейс с именем any, обеспечивающий сбор пакетов со всех активных интерфейсов системы. Отметим, что сбор пакетов с устройства any осуществляется в обычном (не promiscuous) режиме.

Если в системе поддерживается флаг -D, можно в качестве аргумента задавать номер интерфейса, выводимый при использовании этого флага.

-I
--monitor-mode

Переводит интерфейс в режим мониторинга, доступный лишь для IEEE 802.11 Wi-Fi в некоторых операционных системах. Следует отметить, что в этом режиме сетевой интерфейс может потерять установленную связь с беспроводной сетью и использование этой сети станет невозможным.

Эта опция влияет на вывод при использовании опции -L. При выключенной опции -I будут отображаться только те типы кадров канального уровня, которые не доступны в режиме мониторинга, а при включенной опции — только доступные в режиме мониторинга.

--immediate-mode

Задает режим непосредственного захвата (immediate), когда пакеты доставляются в tcpdump без буферизации. Такое поведение принято по умолчанию при отображении пакетов без записи в файл.

-j <тип метки>
--time-stamp-type=<тип метки>

Задает тип временных меток, обображаемых с пакетами. Имена меток задаются pcap-tstamp, но некоторые типы меток пригодны не для всех интерфейсов.

-J 
--list-time-stamp-types

Выводит список поддерживаемых для интерфейсов типов временных меток и на этом завершает работу.

--time-stamp-precision=<точность меток>

Задает точность временных меток при захвате пакетов, которая зависит от используемого оборудования. Следует отметить, что при записи меток с наносекундной точностью в файл не все программы смогут считывать такие метки и файлы.

При чтении данных из файла эта опция задает преобразование использованной при записи файла точности в указанное опцией разрешение, при котором может происходить снижение точности.

Поддерживаются значения micro (мискросекундная точность, принята по умолчанию) и nano (наносекундная точность).

-K 
--dont-verify-checksums

Отключает проверку контрольных сумм IP, TCP и UDP. Это полезно для интерфейсов, полностью или частично вычисляющих контрольные суммы на аппаратном уровне, поскольку без опции контрольные суммы TCP могут оказаться в таких случаях неверными.

-l

Задает буферизацию строк stdout. Эта опция полезна в тех случаях, когда нужно просматривать данные во время сбора пакетов. Например, команды

tcpdump -l | tee dat

или

tcpdump -l > dat & tail -f dat

обеспечивают запись пакетов в файл dat и одновременный вывод на консоль.

-L
--list-data-link-types

Задает вывод списка известных типов канального уровня и завершение работы программы. Список может зависеть от режима и , например, на некоторых платформах часть типов Wi-Fi может не поддерживаться в режиме мониторинга, а другие могут поддерживаться лишь в этом режиме.

-m <файл>

Загружает модуль определений SMI MIB из указанного файла. Эта опция может использоваться неоднократно для загрузки нескольких модулей MIB.

-M <секрет>

Задает использование общего секрета для проверки цифровых подписей в сегментах TCP с опцией TCP-MD5 (RFC 2385).

-n

Отключает преобразование адресов и номеров портов в символьные имена.

-N

Задает использование лишь хостовой части доменного имени вместо FQDN.

-# 
--number

Задает вывод номера пакета в начале строки.

-O
--no-optimize

Отключает оптимизатор кода сопоставления пакетов с фильтрами (стр. 6). Опция полезна лишь при наличии ошибок в оптимизаторе.

-p
--no-promiscuous-mode

Указывает программе, что интерфейс не нужно переводить в неразборчивый режим5. Опцию -p нельзя использовать в сокращенной форме вместе с фильтром ether host {local-hw-addr} или ether broadcast.

-Q direction 
--direction=direction

Выбирает направление приема или передачи для захвата пакетов и может принимать значение in, out или inout. Поддерживается не всеми системами.

-q

Задает вывод минимального объема информации.

-r <файл>

задает чтение данных из файла, созданного ранее с использованием команды tcpdump -w или с помощью другой программы, поддерживающей формат tcpdump (например, Ethereal). Если в качестве имени файла задан символ , используется поток данных от стандартного устройства ввода (stdin).

-S
--absolute-tcp-sequence-numbers

Задает вывод абсолютных порядковых номеров TCP взамен относительных.

-s <snaplen>
--snapshot-length=snaplen

Задает захват из каждого пакета snaplen байтов вместо отбираемых по умолчанию 68 байтов6. Значение 68 подходит для протоколов IP, ICMP, TCP и UDP, но может приводить к потере протокольной информации для некоторых пакетов DNS (стр. 16) и NFS (стр. 17). Потеря части пакетов по причине малого размера кадра захвата (snapshot) указывается в выходных данных полями вида [|proto]‘, где proto — имя протокольного уровня, на котором произошла отсечка части пакета7. Отметим, что увеличение кадра захвата приведет к дополнительным временным затратам на обработку пакетов и уменьшению числа буферизуемых пакетов, что может привести к потере части пакетов. Следует указывать минимальное значение snaplen, которое позволит обойтись без потери информации об интересующем протоколе. Установка snaplen = 0 приведет к захвату до 262144 байтов.

-T <тип>

Задает интерпретацию пакетов, выбранных с помощью фильтра (см. параграф на стр.) как пакетов указанного параметром типа. В настоящее время поддерживаются типы aodv8, carp9, cnfp10, lmp11, pgm12, pgm_zmtp113, resp14, radius, rpc15, rtp16, rtcp17, snmp18, tftp19, vat20, wb21, zmtp122 и vxlan23.

-t

Отключает вывод временных меток в каждой строке дампа.

-tt

Задает вывод в каждой строке дампа неформатированных временных меток.

-ttt

Задает вывод временных интервалов (в микросекундах) между захватом предыдущего и данного пакетов в каждой строке дампа.

-tttt

Задает вывод временных меток в принятом по умолчанию формате для каждой строки дампа.

-u

Задает вывод манипуляторов (handle) NFS без декодирования.

-U
--packet-buffered

Задает режим буферизации на уровне пакетов для файлов, когда содержимое пактеа отображается на стандартном устройстее вывода (и записывается в файл при наличии опции -w) без ожидания заполнения буфера. Флаг -U не будет поддерживаться, если программа tcpdump была скомпилирована со старой опцией libpcap, не поддерживающей функцию pcap_dump_flush().

-v

Задает вывод дополнительной информации из пакета. К такой информации может относиться значение TTL (время жизни), идентификация, общий размер, опциq IP и т. п. При использовании этого флага также выполняется дополнительная проверка целостности пакетов с помощью контрольных сумм (например, для протоколов IP и ICMP).

-vv

Задает дополнительное увеличение объема выводимой информации (например, полное декодирование пакетов SMB, вывод дополнительных полей откликов NFS и т. п.).

-vvv

Задает максимальный объем выводимой информации (например, полностью выводятся опции telnet SB … SE). При использовании вместе с ключом -X опции Telnet выводятся также в шестнадцатеричном представлении.

-V <файл>

Задает считывание списка имен из файла или со стандартного ввода (-).

-w <файл>

Задает запись необработанных (raw) пакетов в файл. Собранные в файл пакеты можно впоследствии просматривать с использованием опции -r или передавать для анализа другим программам. Если в качестве имени файла указан символ , запись осуществляется на стандартное устройство вывода (stdout).

Вывод буферизуется при записи в файл или канал, поэтому читающая файл или канал программа не будет видеть пакеты сразу (обключить буферизацию можно опцией -U).

Для файлов pcap агентством IANA зарегистрирован тип MIME application/vnd.tcpdump.pcap.

-W

При использовании с опцией -C будет ограничивать число записываемых файлов заданным значением, по достижении которого самый старый файл будет перезаписываться. При именовании файлов номера будут дополняться слева нужным числом нулей для корректной сортировки по росту номеров.

При использовании с опцией -G будет ограничивать число создаваемых при ротации по времени файлов, возвращая статус 0 при достижении предела.

При использовании с опциями -C и -G будет зацикливать ротацию файлов.

-x

Задает вывод шестнадцатеричного дампа (без заголовка канального уровня) для каждого захваченного пакета. Объем выводимой информации определяется меньшим из двух значений — размер пакета и значение параметра snaplen (см. стр. 4). Отметим, что при захвате полных кадров канального уровня дамп может включать также байты заполнения, если пакет сетевого уровня имеет малый размер.

-xx

Задает вывод шестнадцатеричного дампа для каждого пакета с включением заголовков канального уровня.

-X

Задает вывод дампа в шестнадцатеричном и ASCII-формате без заголовков канального уровня. Эта опция может быть очень удобна при анализе новых протоколов.

-XX

Задает вывод дампа в шестнадцатеричном и ASCII-формате с включением заголовков канального уровня.

-y <тип>
--linktype=datalinktype

Задает тип канального уровня, используемый при захвате пакетов. Поддерживаемые значения можно посмотреть с помощью опции -L.

-z <команда>

При использовании с опцией -C или -G будет вызывать указанную команду после закрытия каждого записываемого файла. Команда запускается параллельно tcpdump (с низким приоритетом) и не прерывает захват пакетов. Если нужно использовать команду, включающую флаги и/или аргументы, можно поместить эту команду в файл сценария, а сценарий вызывать данной опцией.

-Z user 
--relinquish-privileges=user

При работе tcpdump от имени пользователя root эта опция задает смену идентификатора пользователя и группы на идентификатор основного пользователя и группы после открытия устройства захвата или входного файла, но до открытия выходных файлов.

expression

Задает фильтр отбора пакетов. Синтаксис фильтров описан ниже.

Фильтрация при отборе пакетов

В командной строке tcpdump наряду с опциями могут задаваться выражения, определяющие фильтрацию пакетов на этапе их отбора. Если никакого фильтра не задано, программа будет собирать все пакеты.

Каждое выражение, задающее фильтр, включает один или несколько примитивов, состоящих обычно из одного или множества идентификаторов объектов и предшествующих им классификаторов. Идентификатором объекта может служить его имя или номер. Классификаторы объектов могут относиться к одному из трех видов.

type — тип

Указывает тип объекта, заданного идентификатором. В качестве типа объектов могут указываться значения host (хост), net (сеть) и port (порт). Если тип объекта не указан, предполагается значение host.

dir — направление

Задает направление по отношению к объекту. Для этого классификатора поддерживаются значения src (объект является отправителем), dst (объект является получателем), src or dst (отправитель или получатель) и src and dst (отправитель и получатель), ra, ta, addr1, addr2, addr3, addr4. Например, src foo указывает на пакеты, отправленные с хоста foo, dst net 128.3 — пакеты, адресованные в сеть 128.3.0.0/16, а src or dst port ftp-data — пакеты данных протокола FTP (порт ftp-data), передаваемые в обоих направлениях. Если классификатор dir не задан, предполагается значение src or dst. Для некоторых типов соединений (например, SLIP) и режимов отбора (например, отбор с фиктивного интерфейса any в Linux-системах) могут использоваться классификаторы inbound и outbound. Значения ra, ta, addr1, addr2, addr3, addr4 применимы только для беспроводных интерфейсов IEEE 802.11.

proto — протокол

Задает протокол, к которому должны относиться пакеты. Этот классификатор может принимать значения ether, fddi24, tr25, wlan26, ip, ip6, arp, rarp, decnet, tcp и udp. Если примитив не содержит классификатора протокола, предполагается, что данному фильтру удовлетворяют все протоколы, совместимые с типом объекта27.

Кроме объектов и классификаторов примитивы могут содержать ключевые слова gateway (шлюз), broadcast (широковещательный), less (меньше), greater (больше) и арифметические выражения.

Сложные фильтры могут содержать множество примитивов, связанных между собой с использованием логических операторов and, or и not (например, host foo and not port ftp and not port ftp-data). Для сокращения задающих фильтры выражений можно опускать идентичные списки классификаторов. Например, выражение tcp dst port ftp or ftp-data or domain будет краткой формой выражения

tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain
Допустимые примитивы фильтрации пакетов

Ниже приводится список допустимых примитивов с краткими комментариями для каждого из них.

Таблица 2. Примитивы фильтров tcpdump.

Примитив

Описание

dst host <хост>

Будет отбирать пакеты, в которых поле адреса получателя IPv4/v6 содержит адрес хоста, заданного в примитиве.

src host <хост>

Будет выбирать все пакеты, в которых поле отправителя содержит адрес указанного хоста.

host <хост>

Будет отбирать все пакеты, для которых адрес хоста указан в поле получателя или отправителя.

Все три приведенных выше выражения могут содержать идентификаторы протоколов ip, arp, rarp или ip6, как в выражении

ip host <хост>

эквивалентном фильтру:

ether proto \ip and host <хост>

Если именем задан хост, с которым связано несколько адресов IP, фильтру будут соответствовать пакеты с любым из этих адресов в заголовках пакетов.

ether dst <ehost>

Будет выбирать все кадры, в которых поле MAC-адреса получателя содержит значение ehost (имя хоста из файла /etc/ethers или шестнадцатеричное представление MAC-адреса28).

ether src <ehost>

Будет выбирать все кадры, в которых поле MAC-адреса отправителя содержит значение ehost.

ether host <ehost>

Будет отбирать все пакеты с адресом, указанным значением ehost в поле отправителя или получателя.

gateway <шлюз>

Будет отбирать все пакеты, использующие указанный именем хост в качестве шлюза29. Указанное параметром имя хоста должно преобразовываться в IP-адрес механизмами преобразования имен, доступными локальному компьютеру (/etc/hosts, DNS, NIS и т. п.), а также механизмами определения MAC-адреса по имени хоста (/etc/ethers и т. п.). Эквивалентное выражение ether host ehost and not host <хост> позволяет указывать хост по имени или адресу, заданному в файле host/ehost. Отметим, что данный примитив пока не поддерживается для конфигураций IPv6.

dst net <сеть>

Отбирает все пакеты IPv4/v6, направленные в указанную сеть. Для указания сети можно использовать имя из файла /etc/networks или номер сети. Сети IPv4 можно задавать в сокращенной форме (например, 192.168 или 10), сети IPv6 должны указываться полностью.

src net <сеть>

Выбирает все пакеты Ipv4/v6, отправленные из указанной сети.

net <сеть>

Выбирает все пакеты IPv4/v6, содержащие адреса из указанной сети в поле отправителя или получателя.

net <сеть> mask <маска>

Будет отбирать все пакеты IPv4, содержащие в поле отправителя или получателя адреса из сети, указанной с использованием маски.

net <сеть/размер маски>

Будет отбирать все пакеты IPv4/v6, содержащие в поле отправителя или получателя адреса из сети, указанной с использованием маски.

dst port <порт>

Отберет все пакеты ip/tcp, ip/udp, ip6/tcp и ip6/udp, направленные в указанный порт. Номера портов могут задаваться номерами или именами из файла /etc/services. При указании имени (протокол/порт) проверяется как порт, так и протокол. Если примитив содержит неоднозначный номер или имя порта, проверяется только порт (без протокола) и фильтру будут соответствовать пакеты обоих протоколов (tcp и udp). Например, фильтру dst port 513 будут соответствовать пакеты tcp/login и udp/who, а фильтру port domaintcp/domain и udp/domain.

src port <порт>

Отбирает все пакеты, отправленные из указанного порта.

port <порт>

Отбирает все пакеты, содержащие указанный номер порта в поле отправителя или получателя. Любое из трех перечисленных правил для портов может включать в качестве префикса идентификатор протокола tcp или udp (например, tcp src port <порт>, будет отбирать пакеты tcp, отправленные из указанного порта).

dst portrange port1-port2

Отберет пакеты ip/tcp, ip/udp, ip6/tcp и ip6/udp, направленные в указанный диапазон портов. Интерпретация параметров port такая же, как для одного порта.

src portrange port1-port2

Отберет пакеты, направленные из указанного диапазона портов.

portrange port1-port2

Отберет пакеты, в которых порт отправителя или получателя попадает в указанный диапазон.

less <размер>

Отберет пакеты, размер которых не больше указанного. Эквивалентно len <= length.

greater <размер>

Отберет пакеты, размер которых не меньше указанного. Эквивалентно len >= length.

ip proto <протокол>

Отбирает пакеты IPv4, содержащие заданный идентификатор типа в поле протокола. Типы протоколов IP можно указывать по именам или (icmp, icmp6, igmp, igrp, pim, ah, esp, vrrp, udp, tcp) или номерам. Поскольку tcp, udp и icmp используются также в качестве ключевых слов, их следует экранировать символом \. Отметим, что этот примитив не проверяет цепочки протокольных заголовков.

ip6 proto <протокол>

Отберет пакеты IPv6 указанного типа без проверки цепочки протокольных заголовков.

proto <протокол>

Отберет пакеты IPv4 и IPv6 указанного типа без проверки цепочки протокольных заголовков.

tcp, udp, icmp

Сокращение для proto <протокол>, где протокол относится к одному из указанных.

ip6 protochain <протокол>

Отберет все пакеты IPv6, содержащие в цепочке протокольных заголовков идентификатор указанного типа протокола. Например, фильтру ip6 protochain 6 будут соответствовать все пакеты IPv6 с заголовками TCP в цепочке заголовков. Такой пакет может содержать, например, заголовок аутентификации (AH), маршрутный заголовок (routing header), или заголовок опции hop-by-hop между заголовками IPv6 и TCP. Отметим, что порождаемый этим примитивом код BPF достаточно сложен и не может быть оптимизирован средствами tcpdump, поэтому использование данного фильтра может замедлять работу программы.

ip protochain <протокол>

Эквивалентно примитиву ip6 protochain protocol, но работает с пакетами IPv4.

ip protochain <протокол>

Эквивалентно ip6 protochain protocol, но работает с пакетами IPv4 и IPv6.

ether broadcast

Обеспечивает отбор всех широковещательных кадров Ethernet. Ключевое слово ether может быть опущено.

ip broadcast

Отбирает все широковещательные пакеты IPv4. Этому правилу будут соответствовать широковещательные адреса, содержащие только нули (all-zeroes) и только единицы (all-ones) с учетом маски подсети для интерфейса, который используется для отбора пакетов. Если маска подсети для интерфейса недоступна30, фильтр может работать некорректно.

ether multicast

Собирает все кадры с групповыми адресами Ethernet. Ключевое слово ether необязательно. Логически это правило эквивалентно выражению ether[0] & 1 != 0.

ip multicast

Отбирает пакеты с групповыми адресами IPv4.

ip6 multicast

Отбирает пакеты с групповыми адресами IPv6.

ether proto <протокол>

Отбирает кадры Ethernet с заданным типом протокола. Протокол может быть указан по номеру или имени31 (ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, netbeui).

При использовании правила для протоколов FDDI (например, fddi protocol arp), Token Ring (например, tr protocol arp) или IEEE 802.11 (например, wlan protocol arp) идентификация протокола выполняется на основании заголовка 802.2 Logical Link Control (LLC), который следует после заголовка FDDI, Token Ring или 802.11.

При фильтрации для большинства протоколов FDDI, Token Ring и 802.11 tcpdump проверяет только поле идентификатора протокола (protocol ID) в заголовке LLC так называемого SNAP-формата с идентификатором OUI = 0x000000 (Organizational Unit Identifier), указывающим на инкапсуляцию Ethernet. Проверка использования формата SNAP с OUI = 0x000000 не выполняется за исключением перечисленных ниже случаев:

iso

tcpdump проверяет поля DSAP32 и SSAP33 в заголовках LLC;

stp, netbeui

tcpdump проверяет поле DSAP в заголовке LLC;

atalk

проверяется формат SNAP с OUI = 0x080007 и тип (etype) AppleTalk.

Для Ethernet проверяются поля типа Ethernet для большинства протоколов. Исключения указаны ниже

iso, sap, netbeui

проверяется принадлежность к 802.3 и заголовок LLC (как это описано выше для FDDI, Token Ring и 802.11);

atalk

проверяется тип AppleTalk в кадре Ethernet и формат заголовка SNAP (как для FDDI, Token Ring и 802.11);

aarp

проверяется тип AppleTalk ARP в кадре Ethernet или использование формата 802.2 SNAP с OUI = 0x000000;

ipx

tcpdump проверяет тип IPX в кадре Ethernet, поле IPX DSAP в заголовке LLC, инкапсуляцию IPX и тип IPX в кадре SNAP.

ip, ip6, arp, rarp, atalk, aarp, decnet, iso, stp, ipx, netbeui

Сокращения для ether proto <протокол>, где указан один из протоколов.

lat, moprc, mopdl

Сокращения для ether proto <протокол>, где указан один из протоколов. Отметим, что не все приложения, использующие pcap(3PCAP), понимают эти протоколы.

decnet src <хост>

Собирает все пакеты от указанного хоста DECNET, который может быть задан по адресу в форме 10.123 или имени DECNET34.

decnet dst <хост>

Отбирает все пакеты, адресованные указанному хосту DECNET.

decnet host <хост>

Собирает все пакеты, содержащие адрес указанного хоста DECNET в поле отправителя или получателя.

llc

Отбирает пакет с заголовком 802.2 LLC, включая:

пакеты Ethernet с полем length вместо поля type, которые не являются неразобранными пакетами Netware IEEE 802.3;

пакеты IEEE 802.11;

пакеты Token Ring (без проверки LLC);

пакеты FDDI (без проверки LLC);

пакеты ATM с инкапсуляцией LLC (например, SunATM в Solaris).

llc type

Отбирает пакет с заголовком 802.2 LLC указанного типа:

i — информационные PDU (I);

s — PDU управления (S, supervisory);

u — unnumberd PDU (U);

rr — PDU готовности приемника (RR);

rnr — PDU неготовности приемника (RNR);

rej — PDU отторжения (REJ, reject);

ui — PDU ненумерованной информации (UI);

ua — PDU ненумерованных подтверждений (UA);

disc — PDU разрыва соединения (DISC, disconnect);

sabme — PDU расширенного сбалансированного режима (SABME);

test — тестовые PDU (TEST);

xid — PDU информационного обмена (XID);

frmr — PDU отторжения кадра (FRMR);

inbound

Пакеты, полученные хостом, где выполняется отбор. Поддерживается лишь некоторыми типами интерфейсов, такими как SLIP, фиктивный интерфейс Linux any и др.

outbound

Пакеты, переданные хостом, где выполняется отбор. Поддерживается лишь некоторыми типами интерфейсов, такими как SLIP, фиктивный интерфейс Linux any и др.

ifname <интерфейс>

Отбирает все пакеты, полученные от указанного интерфейса35.

on <интерфейс>

Синоним ifname.

rnr <номер>

Собирает только пакеты, записанные в файл программой pf в соответствии с правилом, имеющим указанных номер (доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf).

rulenum <номер>

Синоним для rnr.

reason <код>

Собирает только пакеты, соответствующие указанному коду причины PF. Известные коды причин включают match, bad-offset, fragment, short, normalize, memory (доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf).

rset <имя>

Собирает пакеты, соответствующие указанному именем правилу привязанного набора (доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf).

ruleset <имя>

Синоним rset.

srnr <номер>

Собирает пакеты, соответствующие указанному номером правилу привязанного набора (доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf).

subrulenum <номер>

Синоним srnr.

action <действие>

Отбирает пакеты, захваченные указанной операцией pf (pass или block, а для некоторых версий pf также nat, rdr, binat и scrub). Правило доступно только при сборе пакетов с помощью OpenBSD и FreeBSD pf.

wlan ra ehost

Отбирает пакеты с полем IEEE 802.11 RA равным ehost. Поле RA отсутствует в кадрах управления.

wlan ta ehost

Отбирает пакеты с полем IEEE 802.11 TA равным ehost. Поле TA отсутствует в кадрах управления, CTS (готовность к передаче) и ACK (подтверждение).

wlan addr1 ehost

Отбирает пакеты с первым адресом IEEE 802.11 равным ehost.

wlan addr2 ehost

Отбирает пакеты со вторым адресом IEEE 802.11 равным ehost. Второй адрес отсутствует в кадрах CTS (готовность к передаче) и ACK (подтверждение).

wlan addr3 ehost

Отбирает пакеты с третьим адресом IEEE 802.11 равным ehost. Третий адрес отсутствует в кадрах управления (control).

wlan addr4 ehost

Отбирает пакеты с четвертым адресом IEEE 802.11 равным ehost. Четвертый адрес присуствтвует только в кадрах WDS (Wireless Distribution System).

type wlan_type

Отбирает пакеты с типом кадра IEEE 802.11 wlan_type (mgt, ctl, data).

type wlan_type subtype wlan_subtype

Отбирает пакеты с типом кадра IEEE 802.11 wlan_type и субтипом wlan_subtype. Для типа mgt, субтип может принимать значения assoc-req, assoc-resp, reassoc-req, reassoc-resp, probe-req, probe-resp, beacon, atim, disassoc, auth, deauth, для типа ctl — ps-poll, rts, cts, ack, cf-end, cf-end-ack, а для data — data, data-cf-ack, data-cf-poll, data-cf-ack-poll, null, cf-ack, cf-poll, cf-ack-poll, qos-data, qos-data-cf-ack, qos-data-cf-poll, qos-data-cf-ack-poll, qos, qos-cf-poll и qos-cf-ack-poll.

subtype wlan_subtype

Отбирает пакеты с субтипом кадра IEEE 802.11 wlan_subtype, а кадр имеет тип, для которого указанный субтип определен.

dir <направление>

Отбирает кадры IEEE 802.11 указанного направления (nods, tods, fromds, dstods или число).

vlan [vlan_id]

Отбирает кадры IEEE 802.1Q VLAN. Если указан идентификатор VLAN, выбираются лишь пакеты, относящиеся в указанной виртуальной ЛВС. Первое ключевое слово vlan изменяет расчет смещения полей для оставшейся части выражения с учетом размера поля VLAN в заголовке кадра (4). Выражение vlan [vlan_id] может указываться несколько раз с учетом вложенности VLAN. Каждое такое выражение увеличивает смещение для полей на 4. Например,

vlan 100 && vlan 200

отберет кадры VLAN 200, инкапсулированные в кадры VLAN 100, а

vlan && vlan 300 && ip

отберет пакеты IPv4, инкапсулированные в кадры VLAN 300, инкапсулированные в любую виртуальную ЛВС.

mpls [label_num]

Отбирает пакеты MPLS. При наличии параметра [label_num] выбираются только пакеты с указанной меткой. Первое ключевое слово mpls меняет расчет смещения полей для оставшейся части выражения в предположении, что пакет относится к протоколу IP, инкапсулированному в MPLS. Выражение mpls [label_num] может указываться несколько раз с учетом вложенности меток. Каждое вхождение увеличивает смещение на 4.

Например, фильтр

mpls 100000 && mpls 1024

отберет пакеты с внешней меткой 100000 и внутренней меткой 1024, а

mpls && mpls 1024 && host 192.9.200.1

отберет пакеты с адресом 192.9.200.1, внутренней меткой 1024 и любой внешней меткой.

pppoed

Отбирает пакеты PPP-over-Ethernet Discovery (тип 0x8863)

pppoes [session_id]

Отбирает пакеты сессий PPP-over-Ethernet (тип 0x8864). При наличии параметра session_id будут отбираться лишь пакеты указанной сессии. Первое ключевое слово pppoes изменяет расчет смещения полей для оставшейся части выражения в предположении, что пакет относится к сессии PPPoE. Например, фильтр

pppoes 0x27 && ip

отберет пакеты IPv4, инкапсулированные в сессию PPPoE с идентификатором 0x27.

geneve [vni]

Отбирает пакеты Geneve (порт UDP 6081). При наличии параметра vni отбираются лишь соответствующие ему пакеты. Ключевое слово pppoes изменяет расчет смещения полей для оставшейся части выражения в предположении, что пакет относится к протоколу Geneve. Например, фильтр

geneve 0xb && ip

отберет пакеты IPv4, инкапсулированные с Geneve VNI 0xb (пакеты, напрямую инкапсулированные в Geneve, а также пакеты IP в кадрах Ethernet).

iso proto <протокол>

Собирает пакеты с указанным типом протокола OSI. Протокол может быть указан по номеру или имени (clnp, esis, isis).

clnp, esis, isis

Сокращение для iso proto p, где p — один из перечисленных протоколов.

l1, l2, iih, lsp, snp, csnp, psnp

Сокращение для типов IS-IS PDU.

vpi n

Собирает пакеты ATM с указанным идентификатором виртуального пути для SunATM (Solaris).

vci n

Собирает пакеты ATM с указанным идентификатором виртуального канала для SunATM (Solaris).

lane

Собирает пакеты эмуляции ЛВС (ATM LANE) для SunATM (Solaris). Первое ключевое слово lane в выражении изменяет проверки для остальной части фильтра в предположении, что пакет относится к пакетам эмуляции Ethernet или LANE LE Control. Если ключевое слово lane не указано, проверки выполняются в предположении LLC-инкапсуляции.

oamf4s

Собирает пакеты ATM для SunATM (Solaris), являющиеся сегментами потока ячеек OAM F4 (VPI=0, VCI=3).

oamf4e

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сквозным потокам OAM F4 (VPI=0, VCI=4).

oamf4

Собирает пакеты ATM для SunATM (Solaris), являющиеся сегментами сквозного потока ячеек OAM F4 (VPI=0, (VCI=3 или VCI=4)).

oam

Собирает пакеты ATM для SunATM (Solaris), являющиеся сегментами сквозного потока ячеек OAM F4 (VPI=0, (VCI=3 или VCI=4)).

metac

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сигнальным мета-устройствам (VPI=0, VCI=1).

bcc

Собирает пакеты ATM для SunATM (Solaris), относящиеся к широковещательным сигнальным устройствам (VPI=0, VCI=2).

sc

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сигнальным устройствам (VPI=0, VCI=5).

ilmic

Собирает пакеты ATM для SunATM (Solaris), относящиеся к клиентским устройствам ILMI (VPI=0, VCI=16).

connectmsg

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сигнальным устройствам и содержащие сообщения Q.2931 Setup, Call Proceeding, Connect, Connect Ack, Release, Release Done.

metaconnect

Собирает пакеты ATM для SunATM (Solaris), относящиеся к сигнальным мета-устройствам и содержащие сообщения Q.2931 Setup, Call Proceeding, Connect, Connect Ack, Release, Release Done.

expr <операция> expr

Возвращают логическое значение, соответствующее отношениям между левой и правой часть. В качестве операции могут использоваться >, <, >=, <=, =, !=, а операнды expr могут быть арифметическими выражениями, включающими целые константы (запись в стандарте C), бинарные операторы36 +, , *, /, %, &, |, ^, <<, >>, оператор размера (len) и данные из пакетов. Во всех операциях сравнения применяются целые числа без знака.

Для получения значений полей из пакетов применяется синтаксис:

proto [expr : size]

Параметр proto может содержать идентификатор одного из протоколов (ether, fddi, tr, wlan, ppp, slip, link, ip, arp, rarp, tcp, udp, icmp, ip6, radio) и задает уровень протокола37, для которого извлекаются данные. Отметим, что tcp, udp и другие протоколы верхних уровней относятся только к пакетам IPv4, а не IPv638. Параметр expr задает смещение в байтах относительно начала заголовка указанного уровня. Необязательный параметр size определяет размер интересующего поля в байтах и может принимать значения 1, 2 и 4 (по умолчанию 1 байт). Оператор размера, указываемый ключевым словом len, определяет размер пакета в байтах.

Например, выражению ether[0] & 1 != 0 будет соответствовать весь multicast-трафик, выражение ip[0] & 0xf != 5 позволяет собрать все пакеты IP, в которых присутствует поле опций, а фильтр ip[6:2] & 0x1fff = 0 соберет только нефрагментированные дейтаграммы IPv4 и первые фрагменты. При выборе полей из заголовков учитывается структура пакетов соответствующего уровня. Например, tcp[0] всегда будет возвращать первый байт заголовка TCP, игнорируя фрагменты.

Некоторые значения полей и смещений могут задаваться не только числами, но и именами. Поддерживаются значения icmptype39, icmp6type40, icmpcode, icmpcode, tcpflags41.

Примитивы в выражениях можно группировать с использованием

  • скобок42;

  • отрицания (! или not);

  • конкатенации (&& или and);

  • выбора варианта (|| или or).

Оператор отрицания имеет высший уровень приоритета, операции выбора и конкатенации имеют одинаковый приоритет и выполняются слева направо в порядке следования. Отметим, что для конкатенации недостаточно просто указать операнды рядом, а требуется явно задать операцию (&& или and).

Если идентификатор указан без ключевого слова, предполагается ключевое слово, которое до этого использовалось последним. Например, выражение

not host vs and ace

является простым сокращением от

not host vs and host ace

Отметим, что эти выражения не эквивалентны фильтру not ( host vs or ace ).

Аргументы выражений могут передаваться программе tcpdump как один или множество аргументов (используйте более удобную для вас форму). В общем случае выражения, содержащие мета-символы командного интерпретатора, должны передаваться как один аргумент, заключенный в кавычки.

Примеры фильтров

Таблица 3. Примеры фильтров tcpdump.

Фильтр

Выполняемые действия

host sundown

Все пакеты, принимаемые и передаваемые хостом sundown

host helios and \( hot or ace \)

Пакеты, передаваемые между хостом helios и любым из хостов hot или ace.

ip host ace and not helios

Пакеты передаваемые между хостом ace и любым хостом, за исключением helios.

net ucb-ether

Все пакеты, передаваемые или принимаемые хостами сети ucb-ether.

'gateway snup and (port ftp or ftp-data)'

Весь трафик ftp, проходящий через шлюз snup43.

ip and not net localnet

Весь трафик, не относящийся к хостам локальной сети.

'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net localnet'

Стартовые (SYN) и конечные (FIN) пакеты TCP, исключая соединения хостов локальной сети.

tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)

Пакеты IPv4 протокола HTTP через порт 80, исключая пакеты SYN, FIN и пакеты ACK без данных.

'gateway snup and ip[2:2] > 576'

Переданные через шлюз snup пакеты IP, размер которых превышает 576 байтов.

'ether[0] & 1 = 0 and ip[16] >= 224'

Широковещательные и групповые пакеты, которые не были переданы с использованием широковещательных и групповых адресов Ethernet.

'icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'

Все пакеты ICMP, кроме запросов и откликов echo (т. е., кроме пакетов ping).

Формат вывода

Формат вывода tcpdump зависит от протокола. Ниже приведены краткие описания и примеры для большинства используемых форматов вывода.

Временные метки

По умолчанию в начале каждой строки вывода указывается временная метка в формате hh:mm:ss.frac, с поддерживаемым ядром разрешением. Метка указывает время ее добавления ядром и может включать задержку между завершением приема пакета интерфейсом и передачей ядру прерывания для чтения пакета, а также время обработки этого прерывания.

Заголовки канального уровня

При использовании опции -e выводится содержимое заголовков канального уровня. Для сетей Ethernet информация из заголовков включает адреса отправителя и получателя, протокол и размер кадра.

Для сетей FDDI опция -e обеспечивает вывод поля управления (frame control), адресов отправителя и получателя, а также размера кадра. Значение поля управления определяет интерпретацию остальной части кадра. Обычные кадры (например, содержащие дейтаграммы IP) являются “асинхронными” с уровнем приоритета от 0 до 7 (например async4). Предполагается, что такие кадры содержат пакеты 802.2 LLC. Заголовок LLC выводится в тех случаях, когда пакет не является дейтаграммой ISO или пакетом SNAP.

В сетях Token Ring опция -e обеспечивает вывод полей контроля доступа (access control) и управления кадром (frame control), адресов отправителя и получателя, а также размера кадра. Предполагается, что кадры содержат пакеты LLC. Независимо от наличия опции -e выводится информация о заданном отправителем маршруте (source routing), если пакет содержит такую информацию.

В сетях 802.11 опция -e выводит значения полей управления (frame control), все адреса из заголовка 802.11, а также размер кадра. Предполагается, что кадры содержат пакеты LLC.

Для каналов SLIP информация канального уровня включает индикатор направления (I для входящего трафика, O — для исходящего), тип пакета и сведения о компрессии44. Поле типа пакета выводится первым и может принимать значение ip, utcp или ctcp. Для пакетов IP дополнительной информации о канале не выводится. Для пакетов TCP вслед за типом выводится идентификатор соединения. Если для пакета используется компрессия, сжатый заголовок декодируется перед выводом. Для специальных случаев45 выводятся значения *S+n и *SA+n (где n — числовое значение), которые указывают величину изменения порядкового номера для пакета и подтверждения, соответственно. Для остальных пакетов могут выводиться индикаторы изменений — U (указатель важности), W (окно), A (подтверждение), S (порядковый номер) и I (идентификатор пакета), сопровождаемые величиной изменения (+n или -n) или указателем на новое значение параметра (=n). Далее выводится информация о размере данных в пакете и размер сжатого заголовка.

Например строка вывода

O ctcp * A+6 S+49 I+6 3 (6)

относится к исходящему сжатому пакету TCP с неявным идентификатором соединения. Порядковый номер подтверждения увеличился на 6, порядковый номер пакета — на 49, идентификатор пакета — на 6. Пакет содержит 3 байта данных и 6-байтовый сжатый заголовок.

Пакеты ARP и RARP

Информация, выводимая для пакетов arp и rarp, включает тип запроса и его аргументы. Выводимой информации вполне достаточно для понимания происходящих процессов. Ниже показан пример вывода для случая, когда хост rtsg открывает сессию rlogin с хостом csam:

arp who-has csam tell rtsg
arp reply csam is-at CSAM

Первая строка показывает запрос arp от хоста rtsg для получения адресов (MAC и IP) хоста csam. В ответ на это csam возвращает свои адреса (в примере IP-адрес обозначен как csam, а MAC-адрес — как CSAM). Если ввести команду с опцией -n, результат будет иметь вид

arp who-has 128.3.254.6 tell 128.3.254.68
arp reply 128.3.254.6 is-at 02:07:01:00:01:c4

Если же воспользоваться опцией -e, можно увидеть, что первый пакет является широковещательным (MAC-адрес отправителя показан как RSTG), поле типа содержит значение 0806 (ETHER_ARP), а размер пакета составляет 64 байта.

RTSG Broadcast 0806  64: arp who-has csam tell rtsg
CSAM RTSG 0806  64: arp reply csam is-at CSAM
Пакеты IPv4

Если заголовок канального уровня не выводится, для пакетов IPv4 после временной метки указывается заголовок IP. При наличии опции -v содержимое заголовка IPv4 указывается в скобках после заголовка IP или канального уровня. Базовый формат этой информации имеет вид

tos tos, ttl ttl, id id, offset offset, flags [flags], proto proto, length length, options (options)

Поле tos указывает тип обслуживания, отличные от нуля биты ECN указываются как ECT(1), ECT(0) или CE. Поле ttl указывает «время жизни» (нулевое значение опускается), id — поле идентификации IP, offset — смещение фрагмента, показывающее, является ли пакет частью фрагментированной дейтаграммы. Поле flags содержит флаги MF и DF — при установленном флаге MF выводится +, а при установленном флаге F — DFP. Если флаги не установлены, выводится точка (.). Поле proto содержит идентификатор протокола, length указывает общий размер пакета, а options — опции IP, если они имеются.

Далее для пакетов TCP и UDP указываются IP-адреса отправителя и получателя, а также номера портов TCP или UDP (номер пора отделяется от адреса точкой), а между отправителем и получателем размещается символ >. Для других протоколов выводятся адреса, разделенные символом >. При наличии данных вышележащего протокола, она выводится вслед за указанными полями.

Для фрагментированных дейтаграмм IP первый фрагмент содержит заголовок вышележащего протокола, а остальные фрагменты этот заголовок не включают. Данные фрагментации выводятся лишь при наличии опции -v.

Пакеты TCP

Формат вывода для протокола TCP (RFC 793) в общем случае имеет вид

src > dst: Flags [tcpflags], seq data-seqno, ack ackno, win window, urg urgent, options [opts], length len

Поля src и dst содержат IP-адреса и номера портов для отправителя и получателя. Поле Flags содержит комбинацию символов S (SYN), F (FIN), P (PUSH), R (RST), W (ECN CWR) и E (ECN-Echo) в соответствии с установленными для пакета флагами или один символ “.” (нет флагов). Поле data-seqno описывает занятую данным пакетом часть пространства порядковых номеров. Поле ack содержит порядковый номер, ожидаемый для следующей порции данных, передаваемой через это соединение в обратном направлении. Поле window показывает число байтов в приемном буфере, доступных для обратного направления в этом соединении. Поле urg показывает состояние флага важности (urgent) для данных из этого пакета. Поле options содержит опции TCP, заключенные в угловые скобки.

Поля src, dst и flags присутствуют во всех случаях, вывод остальных полей зависит от данных в заголовке TCP.

Ниже показан набор пакетов, передаваемых при организации хостом rtsg сессии rlogin с хостом csam.

rtsg.1023 > csam.login: S 768512:768512(0) win 4096 <mss 1024>
csam.login > rtsg.1023: S 947648:947648(0) ack 768513 win 4096 <mss 1024>
rtsg.1023 > csam.login: . ack 1 win 4096
rtsg.1023 > csam.login: P 1:2(1) ack 1 win 4096
csam.login > rtsg.1023: . ack 2 win 4096
rtsg.1023 > csam.login: P 2:21(19) ack 1 win 4096
csam.login > rtsg.1023: P 1:2(1) ack 21 win 4077
csam.login > rtsg.1023: P 2:3(1) ack 21 win 4077 urg 1
csam.login > rtsg.1023: P 3:4(1) ack 21 win 4077 urg 1

Первая строка показывает, что порт TCP с номером 1023 хоста rtsg отправил пакет в порт login хоста csam. Символ S говорит о наличии в пакете флага SYN. Порядковый номер пакета равен 768512 и данных в пакете не содержится46. Пакет не содержит в себе подтверждения, доступный размер приемного окна составляет 4096 байтов, а запрошенное значение MSS составляет 1024 байта.

Сайт csam отправляет в ответ подобный полученному пакет, включающий подтверждение для полученного от rtsg пакета SYN. После этого rtsg подтверждает хосту csam получение от него пакета SYN. Точка (.) в поле флагов говорит о том, что пакет не содержит ни одного флага. Данных в пакете не содержится, поэтому в строке вывода отсутствуют значения порядковых номеров. Отметим, что для подтверждения в строке 3 указан порядковый номер 1. Когда tcpdump видит первый пакет в данном соединении, выводится порядковый номер из этого пакета. Для последующих пакетов данного соединения выводятся значения разницы между порядковым номером для текущего пакета и начальным порядковым номером. Это значит, что для всех пакетов, кроме первого, порядковые номера указываются относительно начала потока данных для соединения и первый байт данных имеет номер 1. Опция -S (стр. 4) отключает относительную нумерацию и обеспечивает вывод порядковых номеров в соответствии со значениями в пакетах.

В строке 6 показан пакет, который rtsg отправляет хосту csam с 19 байтами данных (байты со 2 по 20). Пакет передается с флагом PUSH. Строка 7 содержит отправленное хостом csam подтверждение приема данных от хоста rtsg вплоть до байта с номером 21 (не включая этот байт). Большая часть этих данных сохраняется в приемном буфере, поскольку csam показывает уменьшение приемного окна на 19 байтов. В этом пакете csam также передает хосту rtsg 1 байт данных. В строках 8 и 9 показана передача хостом csam двух важных (urg) байтов данных, отправленных с использованием флага выталкивания PUSH.

Если используется достаточно малый кадр захвата (см. описание опции -s на стр. 4), tcpdump может не получить заголовок TCP полностью. В таких случаях интерпретируется полученная часть заголовка, а в строке вывода помещается маркер [|tcp], показывающий невозможность полной интерпретации. Если заголовок содержит некорректную опцию47, строка вывода будет содержать маркер [bad opt] и последующие опции не будут интерпретироваться, поскольку невозможно корректно определить начало следующей опции. Если поле размера заголовка указывает на присутствие опций, но размер пакета IP недостаточно велик для включения всех опций в пакет, tcpdump будет помещать в строке вывода маркер [bad hdr length].

Сбор пакетов TCP с заданными комбинациями флагов (SYN-ACK, URG-ACK и т. п.)

Поле флагов заголовка TCP содержит 8 элементов — CWR | ECE | URG | ACK | PSH | RST | SYN | FIN.

Предположим, что нужно собрать пакеты, используемые для организации нового соединения TCP. Напомним, что протокол TCP использует 3-этапную процедуру организации новых соединений, как показано ниже.

  1. Инициатор соединения передает пакет с установленным флагом SYN.

  2. Получатель этого пакета передает отклик с флагами SYN и ACK.

  3. Инициатор передает в ответ пакет с флагом ACK.

Создадим фильтр, который будет собирать пакеты, содержащие только флаг SYN (этап 1). Пакеты этапа 2 (SYN-ACK) не будут включаться, поскольку они являются просто откликами на стартовый запрос SYN. Прежде, чем строить выражение для фильтра, вспомним структуру заголовка TCP без опций.

Таблица 4. Структура заголовка TCP.

0 15

31

Порт отправителя

Порт получателя

Порядковый номер

Номер подтверждения

HL

резерв

C

E

U

A

P

R

S

F

Размер окна

Контрольная сумма TCP

Указатель важности

Заголовок TCP состоит из 20 октетов, если не используются необязательные поля опций. Первая строка таблицы 4 соответствует октетам 0 — 3, вторая — октетам 4 — 7 и т. д. Поле битов управления (флагов) TCP содержится в октете 13. Пронумеруем биты флагов справа налево (в соответствии с ростом значимости битов).

Таблица. 5 Биты флагов TCP.

7

6

5

4

3

2

1

0

27=128

26=64

25=32

24=16

23=8

22=4

21=2

20=1

CWR

ECE

URG

ACK

PSH

RST

SYN

FIN

Таким образом, значение октета флагов при наличии в нем только флага SYN будет составлять

0*128 + 0*64 + 0*32 + 0*16 + 0*8 + 0*4 + 1*2 + 0*1 = 2

и для выделения пакетов с флагом SYN можно воспользоваться выражением

tcp[13] == 2

Указав интересующий интерфейс, мы можем собрать пакеты с помощью команды

tcpdump -i <интерфейс> tcp[13] == 2

Эту команду можно перевести на человеческий язык словами: «Собрать с указанного интерфейса пакеты TCP, имеющие в тринадцатом октете заголовка значение 2».

Далее предположим, что нужно собрать пакеты с флагом SYN, независимо от состояния флага ACK и иных флагов. Посмотрим, какое значение будет иметь октет флагов для пакетов SYN-ACK:

|C|E|U|A|P|R|S|F|
|0 0 0 1 0 0 1 0|

В десятичном формате значение 00010010 будет равно 18

0*128 + 0*64 + 0*32 + 1*16 + 0*8 + 0*4 + 1*2 + 0*1 = 18

Однако, мы не можем использовать выражение

tcp[13] == 18

поскольку ему будут соответствовать только пакеты с установленными флагами SYN и ACK, но не будут соответствовать пакеты, имеющие только флаг SYN, который интересует нас в первую очередь.

Для сбора пакетов SYN, независимо от значения флага ACK, следует использовать маску 00000010 (десятичное значение 2). Таким образом, мы можем ввести выражение:

tcpdump -i <интерфейс> 'tcp[13] & 2 == 2'

которое позволит нам собирать пакеты с установленным флагом SYN независимо от присутствия других флагов. Выражение нужно поместить в кавычки или использовать символ \ для экранирования специального символа &.

Пакеты UDP

Формат вывода пакетов UDP можно проиллюстрировать на примере пакета rwho

actinide.who > broadcast.who: udp 84

Приведенная строка говорит о том, что порт who хоста actinide передал дейтаграмму UDP в порт who с использованием широковещательного адреса IP. Пакет содержит 84 байта пользовательских данных.

Для некоторых служб, работающих по протоколу UDP, распознаются протоколы вышележащего уровня (по номеру порта) и для таких протоколов выводится соответствующая информация. В частности, tcpdump выводит дополнительные сведения для пакетов DNS48 и вызовов NFS с помощью Sun RPC49.

Запросы UDP к серверам DNS

Формат вывода для запросов DNS имеет вид

src > dst: id op? flags qtype qclass name (len)

Например

h2opolo.1538 > helios.domain: 3+ A? ucbvax.berkeley.edu. (37)

говорит, что хост h2opolo запрашивает у сервера имен helios адресную запись (qtype=A) для имени ucbvax.berkeley.edu. Идентификатор запроса имеет значение 3. Знак + показывает наличие флага recursion desired50. Размер пакета составляет 37 байтов без учета заголовков UDP и IP. Поскольку пакет содержит обычный запрос, поле op опущено. Если бы это поле содержало иную операцию, соответствующий код был бы выведен между 3 и +. Поле qclass также содержит стандартное значение C_IN, которое опущено при выводе. Любое другое значение qclass было бы выведено вслед за символом A.

При анализе пакета проверяется наличие в нем аномалий и в результате такой проверки строка вывода может содержать дополнительные поля, заключенные в квадратные скобки. Если запрос содержит разделы answer (ответ), authority records (запись о полномочиях) или additional records (дополнительные записи), значения ancount, nscount или arcount выводятся как [na], [nn] или [nau], где n показывает значение соответствующего счетчика. Если установлены какие-либо биты отклика (AA, RA или rcode) или в байтах 2 и 3 установлены любые биты MBZ (должно быть нулем), выводится поле [b2&3=x], где x — шестнадцатеричное значение байтов 2 и 3 из заголовка.

UDP-отклики от серверов DNS

Для вывода откликов сервера имен используется формат

src > dst:  id op rcode flags a/n/au type class data (len)

Например,

helios.domain > h2opolo.1538: 3 3/3/7 A 128.32.137.3 (273)
helios.domain > h2opolo.1537: 2 NXDomain* 0/1/0 (97)

Первая строка показывает, что сервер helios отвечает на запрос с id=3 от хоста h2opolo сообщениям с тремя записями answer, 3 записями NS и 7 дополнительными записями. Первая запись answer имеет тип A (адрес) и содержит IP-адрес указанного в запросе хоста (128.32.137.3). Общий размер отклика составляет 273 байта без учета заголовков UDP и IP. Поля op (Query) и код отклика (NoError) были опущены при выводе.

Во второй строке helios отвечает на запрос 2 с кодом NXDomain (несуществующий домен) без записей answer, с одной записью NS и без записей authority. Символ * показывает, установленный бит полномочного отклика (authoritative answer). Ввиду отсутствия записей answer не выводится никакой информации о типе, классе и данных.

В строке вывода могут также появляться индикаторы флагов RA (рекурсия доступна) “ и TC (усеченное сообщение) “|”. Если раздел question (вопрос) не содержит в точности одну запись, выводится поле [nq].

Отметим, что запросы и отклики DNS могут быть достаточно велики и принятое по умолчанию значение кадра захвата (68 байтов) может не обеспечить достаточное количество данных из пакета. Для просмотра трафика DNS целесообразно увеличить размер кадра захвата вдвое с помощью опции -s 128.

Декодирование SMB/CIFS

Программа tcpdump поддерживает функции декодирования пакетов SMB/CIFS/NBT, использующих порты UDP/137, UDP/138 и TCP/139. Поддерживаются также некоторые примитивы декодирования данных IPX и NetBEUI SMB.

По умолчанию декодирование происходит с минимальным выводом информации, а для увеличения информативности служит опция -v. Отметим, что при использовании опции -v один пакет SMB может занимать больше экранной страницы, поэтому указывайте опцию только при необходимости, чтобы не утонуть в море выводимых на экран данных.

При декодировании сеансов SMB, содержащих текстовые строки Unicode может потребоваться установка переменной окружения USE_UNICODE =1.

Информацию о формате пакетов SMB вы сможете найти на сайте www.cifs.org или одном из зеркал samba.org.

Запросы и отклики NFS

Запросы и отклики Sun NFS51 имеют вид:

src.sport > dst.nfs: NFS request xid xid len op args 
src.nfs > dst.dport: NFS reply xid xid reply stat len op results

Ниже показан пример вывода информации для пакетов NFS

sushi.6709 > wrl.nfs: 
   112 readlink fh 21,24/10.73165
wrl.nfs > sushi.6709: 
   reply ok 40 readlink "../var"
sushi.201b > wrl.nfs: 
   144 lookup fh 9,74/4096.6878 "xcolors"
wrl.nfs > sushi.201b: 
   reply ok 128 lookup fh 9,74/4134.3150

Первая строка показывает, что хост sushi передает транзакцию с идентификатором 670952 хосту wrl. Размер запроса составляет 112 байтов без учета заголовков UDP и IP. Запрашиваемая операция readlink53 для файла с идентификатором (handle) fh 21,24/10.731657119 была успешно выполнена и хост wrl возвращает результат ok с содержимым символьной ссылки.

Затем sushi запрашивает у хоста wrl поиск файла xcolors в каталоге 9,74/4096.6878 и wrl возвращает отклик с идентификатором транзакции.

При использовании опции -v вывод становится более информативным54

sushi.1372a > wrl.nfs: 148 read fh 21,11/12.195 8192 bytes @ 24576
wrl.nfs > sushi.1372a: reply ok 1472 read REG 100664 ids 417/0 sz 29388

В первой строке показан запрос sushi к хосту wrl на чтение 8192 байтов из файла 21,11/12.195, начиная со смещения 24576. Хост wrl возвращает результат ok, показанный во второй строке пакет является первым фрагментом отклика, содержащим 1472 байта прочитанных данных. Последующие фрагменты не имеют заголовков NFS и UDP, поэтому информация об этих пакетов может не появиться на экране, если вы задали в команде тот или иной фильтр. Благодаря использованию опции -v выводятся также некоторые атрибуты прочитанного файла (REG — обычный файл, восьмеричное представление прав доступа, идентификаторы владельца и группы, а также размер файла).

При использовании опции -vv объем выводимой информации может дополнительно возрасти.

Отметим, что запросы NFS могут быть достаточно большими и при использовании опции -v выводимая информация может занять несколько экранных страниц. В некоторых случаях будет полезно уменьшить размер кадра захвата с помощью опции -s (например, -s 192).

Отклики NFS не указывают явно операции RPC, вместо этого tcpdump сохраняет информацию о последних запросах и при выводе откликов указывает соответствующие идентификаторы транзакций.

Запросы и отклики AFS

Вывод информации для запросов и откликов AFS55 имеет вид

src.sport > dst.dport: rx packet-type
src.sport > dst.dport: rx packet-type service call call-name args
src.sport > dst.dport: rx packet-type service reply call-name args

Ниже показан пример вывода информации для пакетов AFS

elvis.7001 > pike.afsfs:
     rx data fs call rename old fid 536876964/1/1 ".newsrc.new"
     new fid 536876964/1/1 ".newsrc"
pike.afsfs > elvis.7001: rx data fs reply rename

В первой строке хост elvis передает пакет RX хосту pike. Этот пакет адресован файловому серверу (fs) и начинает вызов удаленной процедуры (RPC). Вызов RPC содержит команду rename (переименовать) с идентификатором старого каталога 536876964/1/1 и именем .newsrc.new, а также новым идентификатором 536876964/1/1 и именем .newsrc. Хост pike возвращает отклик RPC с информацией об изменении имени файла.

В общем случаем все пакеты AFS RPC декодируются по меньшей мере как имена процедур RPC. Во многих случаях декодируется также один или несколько передаваемых процедуре аргументов.

Формат вывода должен быть понятен для тех, кто знаком с AFS и RX.

При использовании опции -v обеспечивается вывод дополнительной информации (идентификаторы вызовов RX, номера вызовов, порядковые номера, флаги пакетов RX). Опция -vv дополнительно увеличивает объем выводимой информации (в частности, сведений о согласовании MTU для пакетов RX ack), а опция -vvv обеспечивает также вывод параметров безопасности и идентификаторов сервиса.

Для пакетов abort выводятся коды ошибок (за исключением пакетов Ubik, поскольку эти пакеты используются для обозначения пакетов yes vote протокола Ubik).

Отметим, что запросы AFS могут быть достаточно велики, поэтому использование флага -v иной раз будет приводить к выводу для пакета многостраничной информации. Можно задать размер кадра захвата с помощью опции -s для обеспечения более читаемых результатов (например, -s 256).

Отклики AFS явно не указывают операции RPC, поэтому tcpdump отслеживает последние запросы и помечает отклики идентификаторами соответствующих запросов.

KIP AppleTalk (DDP по протоколу UDP)

Пакеты AppleTalk DDP, инкапсулированные в дейтаграммы UDP, извлекаются из дейтаграмм и отображаются как пакеты DDP (заголовки UDP отбрасываются). Для преобразования имен сетей и хостов AppleTalk служит файл /etc/atalk.names, строки которого имеют форму адрес (номер) — имя

1.254     ether
16.1      icsd-net
1.254.110 ace

В приведенном примере первые две строки содержат имена сетей AppleTalk, а третья — имя хоста56. Для разделения номера и имени в файле могут служить пробелы или символы табуляции. Файл /etc/atalk.names может содержать пустые строки и строки комментариев, начинающиеся с символа #.

Адреса AppleTalk выводятся в формате net.host.port, например,

144.1.209.2 > icsd-net.112.220
office.2 > icsd-net.112.220
jssmag.149.235 > icsd-net.2

Если файл /etc/atalk.names не содержит записи для той или иной сети или хоста, соответствующее поле выводится в цифровом формате. В первой строке показан пакет NBP (DDP порт 2), отправленный узлом 209 сети 144.1 в порт 220 узла 112 сети icsd-net. Вторая строка отличается от первой только тем, что указано также символьное имя отправителя (office). В третьей строке показан пакет, отправленный из порта 235 хостом 149 сети jssmag всем хостам57 сети icsd-net, прослушивающим порт NBP

Пакеты протоколов NBP (name binding protocol) и ATP (AppleTalk transaction protocol) выводятся с интерпретацией их содержимого. Для остальных протоколов просто выводится дамп имени протокола или его номера, если имя неизвестно, и размер пакета.

Пакеты NBP выводятся в формате, подобном приведенному ниже:

icsd-net.112.220 > jssmag.2: nbp-lkup 190: "=:LaserWriter@*"
jssmag.209.2 > icsd-net.112.220: nbp-reply 190: "RM1140:LaserWriter@*" 250
techpit.2 > icsd-net.112.220: nbp-reply 190: "techpit:LaserWriter@*" 186

Первая строка показывает запрос на преобразование имени для принтеров LaserWriter, переданный хостом 112 сети icsd по широковещательному адресу сети jssmag. Идентификатор запроса nbp имеет значение 190. Вторая строка содержит отклик на этот запрос от хоста jssmag.209, сообщающего о наличии ресурса LaserWriter с именем RM1140, зарегистрированного на порту 250. В третьей строке показан другой отклик на тот же запрос, говорящий, что хост techpit имеет ресурс LaserWriter с именем techpit, зарегистрированный на порту 186.

Пример формата вывода пакетов ATP показан ниже:

jssmag.209.165 > helios.132: atp-req  12266<0-7> 0xae030001
helios.132 > jssmag.209.165: atp-resp 12266:0 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:1 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:2 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:4 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:6 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp*12266:7 (512) 0xae040000
jssmag.209.165 > helios.132: atp-req  12266<3,5> 0xae030001
helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000
helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000
jssmag.209.165 > helios.132: atp-rel  12266<0-7> 0xae030001
jssmag.209.133 > helios.132: atp-req* 12267<0-7> 0xae030002

Хост jssmag.209 инициирует транзакцию 12266 с хостом helios, запрашивая до 8 пакетов (<0-7>). Шестнадцатеричное число в конце строки содержит значение поля userdata из запроса.

Хост helios отвечает на полученный запрос 8 пакетами по 512 байтов. Число после номера транзакции указывает порядковый номер пакета для данной транзакции, а число в скобках — размер данных в пакете без учета заголовка ATP. Символ * для пакета 7 показывает наличие флага EOM.

Хост jssmag.209 после получения пакетов запрашивает повторную передачу пакетов 3 и 5, а helios повторяет эти пакеты, после чего jssmag.209 завершает транзакцию. В последней строке показан новый запрос хоста jssmag.209. Символ * показывает, что флаг XO (exactly once) для пакета не установлен.

Перевод на русский язык

Николай Малых

nmalykh@protocols.ru

1Promiscuous — “Неразборчивый” режим, при котором драйвер устройства захватывает все передаваемые через среду пакеты. В нормальном режиме драйвер обычно читает из среды лишь пакеты, адресованные данному устройству.

2Поддержка “битов возможностей” (capability bit) обеспечивается в ядре Linux начиная с версии 2.2.

3Например, Windows или UNIX-системы, в которых не поддерживается команда ifconfig -a

4Например, его можно увидеть с помощью команды ps.

5Интерфейс может быть переведен в неразборчивый режим другими программами, поэтому использование флага -p отнюдь не гарантирует работу интерфейса в обычном режиме — программа просто не будет переводить этот интерфейс в неразборчивый режим. Кроме того, даже в обычном режиме захватываться будут не только пакеты, адресованные этому интерфейсу, поскольку в сети всегда присутствуют широковещательные пакеты и могут использоваться пакеты с групповыми адресами (multicast).

6В SunOS NIT минимум составляет 96 байтов.

7Например, при захвате пакетов в сети Ethernet с помощью команда tcpdump -s 12 на выходе будут появляться строки вида 22:31:43.385357 [|ether], показывающие, что отсечка пакетов произошла на уровне Ethernet.

8Протокол Ad-hoc On-demand Distance Vector.

9Common Address Redundancy Protocol — базовый протокол для избыточных (резерных) адресов.

10Протокол Cisco NetFlow.

11Link Management Protocol — протокол управления каналом.

12Pragmatic General Multicast.

13ZMTP/1.0 внутри PGM/EPGM.

14REdis Serialization Protocol.

15Протокол Remote Procedure Call (удаленный вызов процедур).

16Протокол Real-Time Applications (приложения в реальном масштабе времени).

17Протокол управления приложениями реального времени (Real-Time Applications control protocol).

18Простой протокол сетевого управления (Simple Network Management Protocol).

19Тривиальный протокол обмена файлами (Trivial File Transfer Protocol).

20Visual Audio Tool.

21Распределенные доски White Board.

22ZeroMQ Message Transport Protocol 1.0.

23Virtual eXtensible Local Area Network.

24fddi в действительности является псевдонимом ether и при анализе примитива оба классификатора трактуются как “канальный уровень, используемый указанным интерфейсом”. Заголовки FDDI содержат адреса отправителя и получателя, подобные адресам Ethernet, поля типа также зачастую содежат значения, подобные используемым для Ethernet, поэтому можно фильтровать эти поля в кадрах FDDI как и аналогичные поля кадров Ethernet. Заголовки FDDI содержат и другие поля, но их нельзя указать в фильтрах.

25tr является псевдонимом ether, поскольку оба типа кадров используют весьма похожую структуру заголовков.

26Идентификатор протокола wlan (беспроводные сети 802.11) является псевдонимом ether. В заголовках 802.11 адрес получателя содержится в поле DA, отправителя — в поле SA, а поля BSSID, RA и TA не проверяются фильтрами.

27Например, примитиву src foo будут соответствовать все пакеты ip, arp и rarp, исходящие от хоста foo.

28MAC-адрес записывается в формате xx:xx:xx:xx:xx:xx

29Т. е., адрес отправителя или получателя на канальном уровне (например, ethernet) соответствует адресу хоста, заданному значением <шлюз>, но IP-адреса отправителя и получателя в заголовке пакета не совпадают с IP-адресом указанного шлюза.

30Интерфейс не имеет маски или сбор пакетов осуществляется со всех интерфесов хоста Linux (интерфейс any).

31Перечисленные здесь имена протоколов могут использоваться также в качестве ключевых слов, поэтому имени протокола должен предшествовать символ \ (например, \arp).

32Destination Service Access Point — точка доступа к сервису для получателя.

33Source Service Access Point — точка доступа к сервису для отправителя.

34Поддержка имен DECNET обеспечивается только на хостах ULTRIX, настроенных для использования DECNET.

35Это правило применимо только к пакетам, собранным в файл с помощью программы pf (OpenBSD).

36Операторы % и ^ поддерживаются фильтрами в ядре Linux, начиная с версии 3.7, а в остальных случаях эти операторы используют фильтры в пользовательском прстранстве, что существенно повышает издержки при отборе и может вести к потере пакетов.

37Протоколы ether, fddi, wlan, tr, ppp, slip и link указывают на канальный уровень, radio указывает «радио-заголовок», добавляемый к некоторым выборкам 802.11.

38Поддержка IPv6 будет реализована в следующих версиях.

39Поле типа ICMP, которое может принимать значения icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply.

40Поле типа ICMPv6, которое может принимать значения icmp6-echo, icmp6-echoreply, icmp6-multicastlistenerquery, icmp6-multicastlistenerreportv1, icmp6-multicastlistenerdone, icmp6-routersolicit, icmp6-routeradvert, icmp6-neighborsolicit, icmp6-neighboradvert, icmp6-redirect, icmp6-routerrenum, icmp6-nodeinformationquery, icmp6-nodeinformationresponse, icmp6-ineighbordiscoverysolicit, icmp6-ineighbordiscoveryadvert, icmp6-multicastlistenerreportv2, icmp6-homeagentdiscoveryrequest, icmp6-homeagentdiscoveryreply, icmp6-mobileprefixsolicit, icmp6-mobileprefixadvert, icmp6-certpathsolicit, icmp6-certpathadvert, icmp6-multicastrouteradvert, icmp6-multicastroutersolicit, icmp6-multicastrouterterm

41Для флагов TCP можно указать идентификаторы tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-ack, tcp-urg, tcp-ece, tcp-cwr.

42В зависимости от используемого командного интерпретатора перед символами открывающих и закрывающих скобок может потребоваться включение символа экранирования.

43Кавычки позволяют избавиться от ошибок при анализе скобок командным интерпретатором.

44Компрессия заголовков TCP/IP для каналов SLIP описана в RFC 1144.

45RFC 1144 определяет как специальные случаи интерактивный трафик и передачу больших объемов трафика.

46Об этом говорит запись first:last(nbytes), в которой указывается порядковый номер первого байта в этом и следующем за ним (т. е. номер последнего байта в данном пакете + 1) пакетах и число байтов, содержащихся в пакете.

47Размер опции слишком мал или выходит за пределы указанного размера заголовка.

48Спецификация протокола DNS (Domain Name System) приведена в RFC 1034 и RFC 1035.

49Спецификация протокола RPC (Remote Procedure Call — удаленный вызов процедур) содержится в RFC 1050.

50При отсутствии записи на сервере имен следует сделать рекурсивный запрос к другому серверу.

51Network File System — сетевая файловая система.

52Номер, указанный после имени отправителя, задает не порт, а номер транзакции.

53Прочесть символьную ссылку.

54При использовании опции -v будут выводиться также поля заголовков IP (TTL, ID, length, fragmentation), которые опущены в приведенном примере.

55Andrew File System.

56Хост отличается от сети наличием в номере третьего октета.

57Отметим, что широковещательный адрес 255 задается просто именем или номером сети без указания хоста. По этой причине разумно сохранять имена хостов и сетей в файле /etc/atalk.names отдельно.

Рубрика: Linux | Комментарии к записи Пакет tcpdump отключены

Тестирование производительности сети с помощью iperf

image_print

PDF

Документ соответствует iperf версии 2.0.14a (20 Jan 2020) pthreads.

Синтаксис

iperf -s [options]
iperf -c server [options]
iperf -u -s [options]
iperf -u -c server [options]

Описание

Пакет iperf служит для измерения производительности работы сети. Программа позволяет измерять пропускную способность на основе протоколов TCP и UDP. Для проведения теста нужен сервер, принимающий и отбрасывающий пакеты, и клиент, который генерирует тестовые пакеты. Клиент и сервер могут размещаться на одном (локальные тесты) или разных (тесты сети) хостах локальной или распределенной сети.

Для создания пакетов клиент использует многопотоковый (multithread) режим, что позволяет эффективно загрузить загрузить имеющиеся в системе процессорные ядра.

Опции

-b, —bandwidth

Задает полосу текстового потока и может также задавать стандартное отклонение от нормального распределения в форме <mean>,[<stdev>], которое обычно указывается в выводе. Значения могут задаваться с символьными суффиксами1.

-e, —enhanced

Задает расширенный формат вывода. В тестах UDP при расширенном выводе предполагается синхронизация часов клиента и сервера по протоколу NTP или PTP. На точность измерения задержки UDP оказывает влияние точность эталонных (опорных) часов.

-f, —format [abkmgBKMG]

Задает формат вывода и может включать значения a (адаптивный), b (биты), B (байты), k (килобиты), m (мегабиты), g (гигабиты), K (килобайты), M (мегабайты), G (гигабайты).

-h, —help

Выводит справочную информацию о программе.

-i, —interval < n[p] | f >

Задает интервал выборки или отображения n секунд (принято по умолчанию) или n пакетов (суффикс p). При использовании f интервал задает группа (burst) или кадр.

-l, —len n[kmKM]

Задает размер буфера чтения-записи (TCP) или размер пакетов (UDP) и может использовать суффиксы k, m, K, M1. По умолчанию для TCP принято n = 128K, для UDP — n = 1470.

—l2checks

Задает проверку размера кадров L2 для принятых пакетов UDP (требуется поддержка сокета пакетов).

-m, —print_mss

Задает вывод максимального размера сегментов TCP (MSS2, MTU — заголовок TCP/IP).

—NUM_REPORT_STRUCTS <count>

Переопределяет принятый по умолчанию размер общей памяти для потоков (thread) трафика и блока отчетов для снижения числа конфликтов блокировки семафора (mutex). Принятого по умолчанию значения 5000 должно быть достаточно для сетей 1 Гбит/с. Значение следует увеличит при наличии предупреждений о слишком медленных потоках. При отсутствии таких предупреждений увеличение параметра приведет лишь к дополнительному расходу памяти.

-o, —output filename

Задает запись вывода и сообщений об ошибках в указанный файл.

-p, —port n

Задает порт, используемый сервером (по умолчанию 5001).

-u, —udp

Задает использование протокола UDP вместо принятого по умолчанию TCP.

-w, —window n[kmKM]

Задает размер окна TCP (размер буфера сокета).

-z, —realtime

Запрашивает использование планировщика в реальном масштабе времени (если он поддерживается).

-B, —bind host[:port][%dev]

Задает привязку к IP-адресу хоста или групповому адресу, а также может задавать привязку к порту.

-C, —compatibility

Служит для совместимости со старыми версиями, не передающими дополнительных сообщений.

-M, —mss n

Задает максимальный размер сегмента TCP (MTU — 40 байтов).

-N, —nodelay

Отключает задержку TCP (алгоритм Nagle).

-v, —version

Выводит информацию о версии программы и завершает работу.

-x, —reportexclude [CDMSV]

Исключает отчеты о соединениях (C), данных (D), групповых пакетах (M), настройках (S) и сервере (V).

-y, —reportstyle C|c

Установка значения C или c задает вывод в формате CSV3.

-Z, —tcp-congestion

Задает используемый по умолчанию алгоритм контроля насыщения для новых соединений. Платформа должна поддерживать setsockopt TCP_CONGESTION. (см. sysctl и tcp_allowed_congestion_control).

Опции сервера

-b, —bandwidth n[kmgKMG]

Задает целевую скорость чтения n и может использовать описанные выше суффиксы (только для сервера TCP).

-s, —server

Задает работу в режиме сервера.

—histogram[=binwidth[u],bincount,[lowerci],[upperci]]

Задает вывод гистограмм задержки для пакетов (опция -u) или групп (burst) и кадров (опция —trip-times или —isochronous). binwidth — продолжительность элемента (по умолчанию 1 мсек, для мксек суффикс u), bincount — общее число элементов (по умолчанию 1000), ci — доверительный интервал между 0-100% (по умолчанию от 5% до 95%).

-B, —bind ip | ip%device

Задает привязку к IP-адресу получателя, а также может задавать привязку к порту и входному интерфейсу. Приниматься будут лишь пакеты, соответствующие заданным опцией параметрам. Опция полезна также при групповой адресации. Например, iperf -s -B 224.0.0.1%eth0 будет задавать прием групповых пакетов на входном интерфейсе eth0.

-D, —daemon

Задает работу сервера в режиме демона. В Windows это ведет к запуску заданной команды как IperfService с установкой службы при необходимости. Служба не настраивается на автоматический запуск или перезапуск и при небходимости это можно организовать с помощью сценарий инициализации или команды Windows sc.

-H, —ssm-host host

Задает хост отправителя (адрес IP) для групповых пакетов SSM (т. е. S в S,G)

-R, —remove

Удаляет службу IPerfService (только Windows).

-U, —single_udp

Задает работу в режиме UDP с одним потоком (thread).

-V, —ipv6_domain

Включает прием пакетов IPv6 путем установки домена и сокета AF_INET6 (можно принимать сразу IPv4 и IPv6).

Опции клиента

-b, —bandwidth n[kmgKMG] | npps

Задает целевую полосу в бит/с (по умолчанию 1 Мбит/с) или пакет/с для трафика TCP или UDP. Значение параметра может указываться с суффиксом, задающим единицу измерения. Кроме того, поддерживается возможность задать среднее и стандартное отклонение от нормального распределения (mean,standard)

-c, —client host | host%device

Задает работу в режиме клиента с сервером host. Необязательный параметр %device указывает выходной интерфейс (SO_BINDTODEVICE).

—connect-only

Задает лишь организацию соединений TCP без передачи реального трафика, что может быть полезно для измерения времени TCP connect().

-d, —dualtest

Задает выполнение теста одновременно в обоих направлениях.

—fq-rate n[kmgKMG]

Задает скорость, используемую при беспристрастных очередях на уровне соектов, в битах или байтах в секунду. Параметр может содержать суффикс для задания единиц измерения (строчные буквы указывают единицы в битах, прописные — в байтах). Опция доступна лишь на платформах, поддерживающих опцию сокетов SO_MAX_PACING_RATE.

—incr-dstip

Задает инкрементирование IP-адреса получателя при использовании опции -P.

—ipg n

Задает межпакетный интервал (в миллисекундах) в изохронном кадре (burst). Требует опции —isochronous

—isochronous[=fps:mean,stdev]

Задает передачу изохронного трафика с заданным числом кадров в секунду и нагрузкой, указанной средним и стандартным отклонением (mean, stdev) от нормального распределения (по умолчанию 60:20m,0). Скорость может указываться с суффиксом для задания единиц измерения (строчные буквы указывают единицы в битах, прописные — в байтах).

—no-connect-sync

По умолчанию паралельные потоки трафика (-P больше 1) будут синхронизироваться до организации соединений TCP и реальной передачи трафика, т. е. потоки (thread) сначала завершают согласование TCP 3WHS (возможно с ошибкой) и лишь после этого начинается передача трафика. Эта опция отключает такую синхронизацию и каждый поток начинает передаваться сразу после организации соединения.

—no-udp-fin

Отключает выполнение завершающего обмена UDP от сервера к клиенту, в результате чего у клиента не будут выводиться сообщения от сервера. Все пакеты в тесте будут передаваться только от клиента к серверу без передачи пакетов в обратном направлении. Эта опция устанавливается клиентом и передается серверу (начиная с версии 2.0.14).

-n, —num n[kmKM]

Число байтов для передачи (вместо -t)

-r, —tradeoff

Выполнять двухсторонние тесты по направлениям, сначала от клиента к серверу, затем обратно.

-t, —time n

Время прослушивания новых соединений (в секундах), приема или передачи трафика. По умолчанию передача длится 10 секунд, а прием и прослушивание не ограничены во времени.

—trip-times

Включает измерение задержки записи (или передачи данных) в тесте TCP. Требуется синхронизация часов.

—txdelay-time

Время (в секундах) удержания или задержки между организацией соединения TCP и записью в сокет, а для UDP — задержки между стартом потока трафика и первой записью.

—txstart-time n.n

Устанавливает начало передачи (n.n) по времени unix или epoch (с поддержкой наносекундного разрешения, например, 1536014418.839992457).

-B, —bind ip | ip:port | ipv6 -V | [ipv6]:port -V

Задает IP-адрес отправителя, а также позволяет задать порт отправителя и выходное устройство (%device) для передачи пакетов. Опция влияет на системные вызовы bind() и обычно служит для привязки к определенному адресу IP и порту отправителя (например, iperf -c <host> -B 192.168.100.2:6002). Это задает источник пакетов но не применяется при маршрутизации. Здесь может возникнуть путаница при просмотре маршрутов и устройств. Например, если IP-адрес интерфейса eth0 указан в опции -B, а таблица маршрутизации для IP-адреса получателя (опция -c) указывает выходной интерфейс eth1, хост будет передавать через интерфейс eth1 пакеты с IP-адресом интерфейса eth0. Для задания выходного интерфейса в системе с несколькими подключениями следует применять форму -c <host>%device (требуются полномочия root) для обхода поиска в таблице маршрутизации хоста или настроить таблицу маршрутизации хоста для каждой опции -B соответствующим образом и задать выходные интерфейсы в правилах.

Указание выходного интерфейса требуется при использовании адресов IPv6 link-local.

-F, —fileinput name

Задает считывание передаваемых данных из файла.

-I, —stdin

Задает считывание передаваемых данных со стандартного устройства ввода (stdin).

-L, —listenport n

Задает порт для приема возвращаемых пакетов.

-P, —parallel n

Задает число параллельных потоков (thread), запускаемых клиентом.

-R, —reverse

Задает обращение (реверс) потока трафика после обмена заголовками и может быть полезно при тестировании через межсетевые экраны4.

-S, —tos

Устанавливает значение поля IP_TOS для сокета (1 байт).

-T, —ttl n

Задает TTL для группового трафика (по умолчанию 1)

-V, —ipv6_domain

Задает домен для IPv6 (передача пакетов по IPv6).

-X, —peerdetect

Задает определение версии сервера до начала обмена трафиком.

-Z, —linux-congestion algo

Задает алгоритм контроля насыщения TCP (только для Linux).

Примеры

Тест TCP (клиент)

iperf -c <host> -e -i 1 
------------------------------------------------------------ 
Client connecting to <host>, TCP port 5001 with pid 5149 
Write buffer size:  128 KByte 
TCP window size:  340 KByte (default) 
------------------------------------------------------------ 
[  3] local 45.56.85.133 port 49960 connected with 45.33.58.123 port 5001 (ct=3.23 ms) 
[ ID] Interval        Transfer    Bandwidth       Write/Err  Rtry     Cwnd/RTT        NetPwr 
[  3] 0.00-1.00 sec   126 MBytes  1.05 Gbits/sec  1006/0        0       56K/626 us  210636.47 
[  3] 1.00-2.00 sec   138 MBytes  1.15 Gbits/sec  1100/0      299     483K/3884 us  37121.32 
[  3] 2.00-3.00 sec   137 MBytes  1.15 Gbits/sec  1093/0       24     657K/5087 us  28162.31 
[  3] 3.00-4.00 sec   126 MBytes  1.06 Gbits/sec  1010/0      284     294K/2528 us  52366.58 
[  3] 4.00-5.00 sec   117 MBytes   980 Mbits/sec  935/0       373     487K/2025 us  60519.66 
[  3] 5.00-6.00 sec   144 MBytes  1.20 Gbits/sec  1149/0        2     644K/3570 us  42185.36 
[  3] 6.00-7.00 sec   126 MBytes  1.06 Gbits/sec  1011/0      112     582K/5281 us  25092.56 
[  3] 7.00-8.00 sec   110 MBytes   922 Mbits/sec  879/0        56     279K/1957 us  58871.89 
[  3] 8.00-9.00 sec   127 MBytes  1.06 Gbits/sec  1014/0       46     483K/3372 us  39414.89 
[  3] 9.00-10.00 sec  132 MBytes  1.11 Gbits/sec  1054/0        0     654K/3380 us  40872.75 
[  3] 0.00-10.00 sec 1.25 GBytes  1.07 Gbits/sec  10251/0    1196      -1K/3170 us  42382.03

где (с учетом -e)

ct=

Время соединения TCP (время трехэтапного согласования 3WHS).

Write/Err

Общее число успешных записей в сокет и общее число некритических ошибок записи в сокет.

Rtry

Общее число попыток TCP.

Cwnd/RTT (только *nix)

Окно насыщения TCP и время кругового обхода (выборка)

NetPwr (только *nix)

Отношение пропускной способности к RTT.

Тест TCP (сервер)

iperf -s -e -i 1 -l 8K 
------------------------------------------------------------ 
Server listening on TCP port 5001 with pid 13430 
Read buffer size: 8.00 KByte 
TCP window size: 85.3 KByte (default) 
------------------------------------------------------------ 
[  4] local 45.33.58.123 port 5001 connected with 45.56.85.133 port 49960 
[ ID] Interval        Transfer    Bandwidth       Reads   Dist(bin=1.0K) 
[  4] 0.00-1.00 sec   124 MBytes  1.04 Gbits/sec  22249    798:2637:2061:767:2165:1563:589:11669 
[  4] 1.00-2.00 sec   136 MBytes  1.14 Gbits/sec  24780    946:3227:2227:790:2427:1888:641:12634 
[  4] 2.00-3.00 sec   137 MBytes  1.15 Gbits/sec  24484    1047:2686:2218:810:2195:1819:728:12981 
[  4] 3.00-4.00 sec   126 MBytes  1.06 Gbits/sec  20812    863:1353:1546:614:1712:1298:547:12879 
[  4] 4.00-5.00 sec   117 MBytes   984 Mbits/sec  20266    769:1886:1828:589:1866:1350:476:11502 
[  4] 5.00-6.00 sec   143 MBytes  1.20 Gbits/sec  24603    1066:1925:2139:822:2237:1827:744:13843 
[  4] 6.00-7.00 sec   126 MBytes  1.06 Gbits/sec  22635    834:2464:2249:724:2269:1646:608:11841 
[  4] 7.00-8.00 sec   110 MBytes   921 Mbits/sec  21107    842:2437:2747:592:2871:1903:496:9219 
[  4] 8.00-9.00 sec   126 MBytes  1.06 Gbits/sec  22804    1038:1784:2639:656:2738:1927:573:11449 
[  4] 9.00-10.00 sec   133 MBytes 1.11 Gbits/sec  23091    1088:1654:2105:710:2333:1928:723:12550 
[  4] 0.00-10.02 sec  1.25 Gbytes 1.07 Gbits/sec  227306   9316:22088:21792:7096:22893:17193:6138:120790

где (с учетом -e)

Reads

Общее число считываний сокета.

Dist(bin=size)

8 элементов (bin) гистограммы чтения, возвращенных клиентом и разделяемых двоеточиями. В примере это элементы 0-1K, 1K-2K, .., 7K-8K.

Тест TCP (сервер) с опцией —trip-times на стороне клиента

iperf -s -e -i 1 

------------------------------------------------------------ 
Server listening on TCP port 5001 with pid 30369 
Read buffer size:  128 KByte 
TCP window size: 85.3 KByte (default) 
------------------------------------------------------------ 
[  4] local 10.19.87.7 port 5001 connected with 10.19.87.10 port 43338 (trip-times) 
[ ID] Interval        Transfer    Bandwidth       Reads   Dist(bin=16.0K)           Burst Latency avg/min/max/stdev (cnt/size) inP      NetPwr 
[  4] 0.00-1.00 sec   112 MBytes   941 Mbits/sec  7000    1552:5447:1:0:0:0:0:0     8.749/ 1.583/10.340/ 1.011 ms (897/131127) 1029057 bytes 13444.08 
[  4] 1.00-2.00 sec   112 MBytes   941 Mbits/sec  7015    1562:5453:0:0:0:0:0:0     8.790/ 7.131/10.443/ 0.878 ms (898/131050) 1034467 bytes 13387.92 
[  4] 2.00-3.00 sec   112 MBytes   941 Mbits/sec  7009    1543:5466:0:0:0:0:0:0     8.799/ 7.050/10.389/ 0.869 ms (897/131170) 1035306 bytes 13371.80 
[  4] 3.00-4.00 sec   112 MBytes   941 Mbits/sec  7032    1589:5442:1:0:0:0:0:0     8.810/ 7.128/10.437/ 0.877 ms (898/131047) 1036818 bytes 13356.91 
[  4] 4.00-5.00 sec   112 MBytes   941 Mbits/sec  7013    1556:5457:0:0:0:0:0:0     8.805/ 7.244/10.352/ 0.874 ms (898/131050) 1036239 bytes 13365.03 
[  4] 5.00-6.00 sec   112 MBytes   941 Mbits/sec  6999    1554:5440:3:1:0:0:0:1    10.384/ 7.257/12.712/ 1.284 ms (898/131050) 1222077 bytes 11332.64 
[  4] 6.00-7.00 sec   112 MBytes   941 Mbits/sec  7015    1568:5447:0:0:0:0:0:0    10.682/ 8.714/12.711/ 1.121 ms (898/131045) 1257085 bytes 11016.23 
[  4] 7.00-8.00 sec   112 MBytes   941 Mbits/sec  7010    1557:5453:0:0:0:0:0:0    10.683/ 8.681/12.695/ 1.125 ms (898/131050) 1257237 bytes 11015.71 
[  4] 8.00-9.00 sec   112 MBytes   941 Mbits/sec  7016    1570:5446:0:0:0:0:0:0    10.674/ 8.704/12.679/ 1.128 ms (897/131193) 1256177 bytes 11024.46 
[  4] 9.00-10.00 sec  112 MBytes   941 Mbits/sec  7062    1624:5438:0:0:0:0:0:0    10.693/ 8.624/12.681/ 1.127 ms (898/131047) 1258342 bytes 11005.49 
[  4] 10.00-10.01 sec  1.28 MBytes 939 Mbits/sec  80      17:63:0:0:0:0:0:0        11.582/ 8.761/12.361/ 1.191 ms (11/121860) 1359148 bytes 10131.78 
[  4] 0.00-10.01 sec  1.10 GBytes  941 Mbits/sec  70251   15692:54552:5:1:0:0:0:1   9.699/11.582/11.582/ 0.000 ms (8988/131072) 1141261 bytes 12133.03 

где (с учетом -e)

Burst Latency

Односторонная задержка TCP от write() до read() в формате среднее/минимальное/максимальное/стандартное отклонение. Требуется синхронизация часов клиента и сервера от одного источника (например, по протоколу PTP). Рекомендуется применять опорный источник GPS OCXO.

cnt

Число принятых завершенных групп (burst), использованных для расчета задержки.

size

Средний размер группы (burst) в байтах (только для оценки).

inP

Сокращение для in progress (в работе). Указывает среднее число байтов, находящихся в обработке или «на лету» (в сети) с точки зрения записывающего приложения5.

NetPwr

Отношение пропускной способности к задержке в одном направлении.

Тест UDP (клиент)

iperf -c <host> -e -i 1 -u -b 10m 
------------------------------------------------------------ 
Client connecting to <host>, UDP port 5001 with pid 5169 
Sending 1470 byte datagrams, IPG target: 1176.00 us (kalman adjust) 
UDP buffer size:  208 KByte (default) 
------------------------------------------------------------ 
[  3] local 45.56.85.133 port 32943 connected with 45.33.58.123 port 5001 
[ ID] Interval        Transfer     Bandwidth      Write/Err  PPS 
[  3] 0.00-1.00 sec  1.19 MBytes  10.0 Mbits/sec  852/0      851 pps 
[  3] 1.00-2.00 sec  1.19 MBytes  10.0 Mbits/sec  850/0      850 pps 
[  3] 2.00-3.00 sec  1.19 MBytes  10.0 Mbits/sec  850/0      850 pps 
[  3] 3.00-4.00 sec  1.19 MBytes  10.0 Mbits/sec  851/0      850 pps 
[  3] 4.00-5.00 sec  1.19 MBytes  10.0 Mbits/sec  850/0      850 pps
[  3] 5.00-6.00 sec  1.19 MBytes  10.0 Mbits/sec  850/0      850 pps 
[  3] 6.00-7.00 sec  1.19 MBytes  10.0 Mbits/sec  851/0      850 pps 
[  3] 7.00-8.00 sec  1.19 MBytes  10.0 Mbits/sec  850/0      850 pps 
[  3] 8.00-9.00 sec  1.19 MBytes  10.0 Mbits/sec  851/0      850 pps 
[  3] 0.00-10.00 sec 11.9 MBytes  10.0 Mbits/sec  8504/0     850 pps 
[  3] Sent 8504 datagrams 
[  3] Server Report: 
[  3] 0.00-10.00 sec 11.9 MBytes 10.0 Mbits/sec 0.047 ms 0/ 8504 (0%) 0.537/ 0.392/23.657/ 0.497 ms 850 pps 2329.37 

где (с учетом -e)

Write/Err

Общее число успешных записей в сокет и некритичных ошибок при записи в сокет.

PPS

Число переданных в секунду пакетов.

Тест UDP (сервер)

iperf -s -e -i 1 -u 
------------------------------------------------------------ 
Server listening on UDP port 5001 with pid 13496 
Receiving 1470 byte datagrams 
UDP buffer size:  208 KByte (default) 
------------------------------------------------------------ 
[  3] local 45.33.58.123 port 5001 connected with 45.56.85.133 port 32943 
[ ID] Interval        Transfer     Bandwidth        Jitter   Lost/Total      Latency avg/min/max/stdev      PPS      NetPwr 
[  3] 0.00-1.00 sec  1.19 MBytes  10.0 Mbits/sec   0.057 ms    0/  851 (0%)  0.475/ 0.408/ 1.898/ 0.090 ms  851 pps  2633.56 
[  3] 1.00-2.00 sec  1.19 MBytes  10.0 Mbits/sec   0.039 ms    0/  851 (0%)  0.669/ 0.405/16.256/ 1.375 ms  850 pps  1869.32 
[  3] 2.00-3.00 sec  1.19 MBytes  10.0 Mbits/sec   0.038 ms    0/  850 (0%)  0.795/ 0.395/23.657/ 2.138 ms  850 pps  1572.05 
[  3] 3.00-4.00 sec  1.19 MBytes  10.0 Mbits/sec   0.045 ms    0/  850 (0%)  0.475/ 0.403/ 3.477/ 0.148 ms  850 pps  2628.58 
[  3] 4.00-5.00 sec  1.19 MBytes  10.0 Mbits/sec   0.043 ms    0/  851 (0%)  0.463/ 0.400/ 1.458/ 0.068 ms  850 pps  2699.88 
[  3] 5.00-6.00 sec  1.19 MBytes  10.0 Mbits/sec   0.032 ms    0/  850 (0%)  0.486/ 0.404/ 2.658/ 0.154 ms  850 pps  2572.21 
[  3] 6.00-7.00 sec  1.19 MBytes  10.0 Mbits/sec   0.055 ms    0/  850 (0%)  0.469/ 0.404/ 2.768/ 0.108 ms  850 pps  2664.82 
[  3] 7.00-8.00 sec  1.19 MBytes  10.0 Mbits/sec   0.039 ms    0/  851 (0%)  0.571/ 0.400/12.452/ 0.855 ms  850 pps  2192.68 
[  3] 8.00-9.00 sec  1.19 MBytes  10.0 Mbits/sec   0.083 ms    0/  850 (0%)  0.475/ 0.392/ 3.702/ 0.196 ms  850 pps  2628.29 
[  3] 9.00-10.00 sec 1.19 MBytes  10.0 Mbits/sec   0.047 ms    0/  850 (0%)  0.493/ 0.396/ 6.010/ 0.343 ms  850 pps  2534.89 
[  3] 0.00-10.00 sec 11.9 MBytes  10.0 Mbits/sec   0.047 ms    0/ 8504 (0%)  0.537/ 0.392/23.657/ 0.867 ms  850 pps  2329.37 

где (с учетом -e)

Latency

Сквозная задержка в формате средняя/минимальня/максимальная/стандартная. Для теста требуется синхронизация часов клиента и сервера от одного источника (например, по протоколу PTP). Рекомендуется источник синхронизации GPS OCXO.

PPS

Число принятых в секунду пакетов.

NetPwr

Отношение пропускной способности к задержке.

Изохронный тест UDP (клиент)

iperf -c 192.168.100.33 -u -e -i 1 --isochronous=60:100m,10m --realtime 
------------------------------------------------------------ 
Client connecting to 192.168.100.33, UDP port 5001 with pid 14971 
UDP isochronous: 60 frames/sec mean= 100 Mbit/s, stddev=10.0 Mbit/s, Period/IPG=16.67/0.005 ms 
UDP buffer size:  208 KByte (default) 
------------------------------------------------------------ 
[  3] local 192.168.100.76 port 42928 connected with 192.168.100.33 port 5001 
[ ID] Interval        Transfer     Bandwidth      Write/Err  PPS  frames:tx/missed/slips
[  3] 0.00-1.00 sec  12.0 MBytes   101 Mbits/sec  8615/0     8493 pps   62/0/0 
[  3] 1.00-2.00 sec  12.0 MBytes   100 Mbits/sec  8556/0     8557 pps   60/0/0 
[  3] 2.00-3.00 sec  12.0 MBytes   101 Mbits/sec  8586/0     8586 pps   60/0/0 
[  3] 3.00-4.00 sec  12.1 MBytes   102 Mbits/sec  8687/0     8687 pps   60/0/0 
[  3] 4.00-5.00 sec  11.8 MBytes  99.2 Mbits/sec  8468/0     8468 pps   60/0/0 
[  3] 5.00-6.00 sec  11.9 MBytes  99.8 Mbits/sec  8519/0     8520 pps   60/0/0 
[  3] 6.00-7.00 sec  12.1 MBytes   102 Mbits/sec  8694/0     8694 pps   60/0/0 
[  3] 7.00-8.00 sec  12.1 MBytes   102 Mbits/sec  8692/0     8692 pps   60/0/0 
[  3] 8.00-9.00 sec  11.9 MBytes   100 Mbits/sec  8537/0     8537 pps   60/0/0 
[  3] 9.00-10.00 sec 11.8 MBytes  99.0 Mbits/sec  8450/0     8450 pps   60/0/0 
[  3] 0.00-10.01 sec  120 MBytes   100 Mbits/sec  85867/0    8574 pps  602/0/0 
[  3] Sent 85867 datagrams 
[  3] Server Report: 
[  3] 0.00-9.98 sec 120 MBytes 101 Mbits/sec 0.009 ms 196/85867 (0.23%) 0.665/ 0.083/ 1.318/ 0.174 ms 8605 pps 18903.85

где (с учетом -e)

frames:tx/missed/slips

Общее число изохранных кадров или групп (burst), общее число не переданных идентификаторов кадров, общее число проскальзываний (slip) кадров

Изохронный тест UDP (сервер)

iperf -s -e -u --udp-histogram=100u,2000 --realtime 
------------------------------------------------------------ 
Server listening on UDP port 5001 with pid 5175 
Receiving 1470 byte datagrams 
UDP buffer size:  208 KByte (default) 
------------------------------------------------------------ 
[  3] local 192.168.100.33 port 5001 connected with 192.168.100.76 port 42928 isoch (peer 2.0.13-alpha) 
[ ID] Interval        Transfer     Bandwidth        Jitter   Lost/Total        Latency avg/min/max/stdev PPS            NetPwr  Frames/Lost 
[  3] 0.00-9.98 sec   120 MBytes   101 Mbits/sec   0.010 ms  196/85867 (0.23%)  0.665/ 0.083/ 1.318/ 0.284 ms 8585 pps  18903.85  601/1 
[  3] 0.00-9.98 sec   T8(f)-PDF:   bin(w=100us):cnt(85671)=1:2,2:844,3:10034,4:8493,5:8967,6:8733,7:8823,8:9023,9:8901,10:8816,11:7730,12:4563,13:741,14:1    (5.00/95.00%=3/12,Out-liers=0,obl/obu=0/0) 
[  3] 0.00-9.98 sec F8(f)-PDF: bin(w=100us):cnt(598)=15:2,16:1,17:27,18:68,19:125,20:136,21:103,22:83,23:22,24:23,25:5,26:3 (5.00/95.00%=17/24,Outliers=0,obl/obu=0/0) 

где (с учетом -e)

Frames/lost

Общее число полученных кадров (групп), общее число потерянных или ошибочных кадров.

T8-PDF(f)

Гистограмма задержки для пакетов.

F8-PDF(f)

Гистограмма задержки для кадров.

Примечания

  1. Установка параметров окружения в iperf не поддерживается должным образом, как можно видеть в исходном коде.

  2. Опция -B задает привязку на логическом (ip) и физическом (%device) уровне для клиента и сервера. У клиента влияет на системные вызовы bind() и обычно служит для привязки к определенному адресу IP и порту отправителя (например, iperf -c <host> -B 192.168.100.2:6002). Это задает источник пакетов но не применяется при маршрутизации. Здесь может возникнуть путаница при просмотре маршрутов и устройств. Например, если IP-адрес интерфейса eth0 указан в опции -B, а таблица маршрутизации для IP-адреса получателя (опция -c) указывает выходной интерфейс eth1, хост будет передавать через интерфейс eth1 пакеты с IP-адресом интерфейса eth0. Для задания выходного интерфейса в системе с несколькими подключениями следует применять форму -c <host>%device (требуются полномочия root) для обхода поиска в таблице маршрутизации хоста или настроеить таблицу маршрутизации хоста соответствующим образом.

  3. Время соединения (трехэтапного согласования) TCP можно увидеть на стороне клиента iperf при работе с опцией -e (—enhanced). Поле ct=<value> в сообщениях о соединении (например. [ 3] local 192.168.1.4 port 48736 connected with 192.168.1.1 port 5001 (ct=1.84 ms) показывает, что 3WHS составляет 1,84 мсек).

  4. Параметр NetPwr6 является экспериментальным. Значение поля определяется отношением пропускной способности к задержке в сети. Для TCP в качестве задержки применяется период кругового обхода (RTT), для UDP — измеренное время сквозной задержки. Не следует воспринимать слово «мощность» (power) буквально, как величину работы, выполненной за единицу времени. Следует также отметить, что должна использоваться опция -i interval с протоколом TCP для задания частоты выборки RTT.

Сведения об ошибках

См. https://sourceforge.net/p/iperf2/tickets/

Авторы

Программа iperf2, созданная на основе iperf (разработка Mark Gates и Alex Warshavsky), стала более удобной и функциональной. В разработке участвовали Ajay Tirumala, Jim Ferguson, Jon Dugan <jdugan at x1024 dot net>, Feng Qin, Kevin Gibbs, John Estabrook <jestabro at ncsa.uiuc.edu>, Andrew Gallatin <gallatin at gmail.com>, Stephen Hemminger  <shemminger at linux-foundation.org>, Tim Auckland <tim.auckland at gmail.com>, Robert J. McMahon <rjmcmahon at rjmcmahon.com>.

Исходный код

http://sourceforge.net/projects/iperf2/

Перевод на русский язык

Николай Малых

nmalykh@protocols.ru

1Некоторые числовые опции поддерживают указание единиц в форме <value>c (например, 10M), где c задает единицу измерения и может принимать значени k, m, g, K, M, G. Символы нижнего регистра указывают единицы на основе десятичных значений (103, 106, 109), а символы верхнего регистра — на основе двоичных (2n — 1K = 1024, 1M = 1048576, 1G = 1073741824).

2Maximum segment size.

3Comma separated values — разделенные запятыми значения.

4Опции —reverse (-R), -r и -d вызывают путаницу. Если нужно выполнить тест церез шлюз NAT, следует применять опцию —reverse (или -R в системах, отличных от Windows). Опции -d и -r сохранены для совместимости. Вновь открытые и исходные сокеты работают в полнодуплексном режиме. Работа через межсетевой экран обычно требует использовать -d, опция -r нужна при работе через шлюз NAT. Кроме того, установка —reverse -b <rate> дает несколько отличающийся эффект. Для TCP это будет ограничивать скорость на читающей стороне, т. е. скорость чтения клиентом iperf из полнодуплексного сокета. Это будет приводить к использования стандартного контроля насыщения TCP для реверсированного трафика. Опции —reverse -b <rate> должны применяться на передающей стороне (т. е., на обращенном сервере) для трафика UDP, поскольку здесь нет управления потоком трафика.

5Закон Литтла (Little) в теории очередей определяет среднее число элементов (L) в стационарной системе очередей на основе средне-взвешенного времени (W) нахождения элемента в системе и среднего числа элементов, прибывающих в систему за единицу времени (lambda). Математически это выражается в форме L = lambda * W. Здесь элементами TCP являются байты, а UDP — пакеты.

6Network power — «мощность» сети.

Рубрика: Linux | Комментарии к записи Тестирование производительности сети с помощью iperf отключены

Справочник по командному процессору Bash

image_print

PDF

Редакция 5.0 для Bash версии 5.0.

Декабрь 2018 г.

Chet Ramey, Case Western Reserve University.

Brian Fox, Free Software Foundation.

Этот документ является кратким описанием свойств командного процессора (оболочки) Bash (версия 5.0, 7 декабря 2018 г.). Данная редакция 5.0 обновлена 7 декабря 2018 г. Copyright c 1988–2018 Free Software Foundation, Inc.

Разрешается копировать, распространять и/или изменять этот документ в соответствии с лицензией GNU Free Documentation License версии 1.3 млм более поздней версии, опубликованной Free Software Foundation, без инвариантных разделов, а также текста передней и задней обложки. Копия лицензии представлена в разделе Приложение C. GNU Free Documentation License.

Оглавление

Исключено в варианте HTML.

1. Введение

1.1. Что такое Bash?

Bash является «оболочкой» или интерпретатором команд для операционных систем GNU. Имя служит сокращением Bourne-Again Shell. Stephen Bourne является автором прямого предка современного интерпретатора Unix sh из седьмой редакции Bell Labs Research Unix.

Интерпретатор bash в значительной степени совместим с sh и включает полезные свойства интерпретаторов Korn (ksh) и C (csh). Предполагается, что это будет совместимая реализация части Shell and Tools спецификации IEEE POSIX (IEEE Standard 1003.1). Интерпретатор предлагает функциональные улучшения sh для интерактивного и программируемого применения. Хотя операционные системы GNU включают другие интерпретаторы, такие как csh, по умолчанию применяется bash. Как и другие программы GNU интерпретатор bash является переносимым. В настоящее время он работает практически на всех версиях Unix и некоторых других операционных систем. Имеются независимые реализации для платформ MS-DOS, OS/2 и Windows.

1.2. Что такое оболочка?

В своей основе оболочка является макропроцессором, выполняющим команды. Термина макропроцессор обозначает функциональность преобразования текста и символов в более крупные выражения.

Оболочки Unix являются одновременно интерпретаторами команд и языками программирования. В качестве интерпретатора команд оболочка служит интерфейсом между пользователем и обширным набором утилит GNU. Свойства языка программирования позволяют комбинировать эти утилиты. Могут создаваться файлы с командами, которые сами могут служить командой. Эти новые команды имеют такой же статус как системные команды в каталогах типа /bin, давая пользователям и группам возможность организации среды для автоматизации своих задач. Оболочки могут использоваться в интерактивном или командном режиме. В первом случае выполняются команды, введенные пользователем, во втором — считанные из файла.

Оболочка позволяет выполнять команды GNU в синхронном или асинхронном режиме. В синхронном режиме оболочка ждет завершения команды перед восприятием последующего ввода, асинхронные команды могут выполняться параллельно с чтением и выполнением оболочкой других команд. Перенаправление позволяет контролировать ввод и вывод команд. Кроме того, оболочка позволяет контролировать содержимое командных сред.

Оболочки включают небольшой набор внутренних команд (builtin), реализующих функции, которые невозможно или неудобно реализовать в отдельных утилитах. Например, команды cd, break, continue и exec не могут быть реализованы вне оболочки, поскольку они напрямую манипулируют этой оболочкой. Команды history, getopts, kill или pwd, наряу с другими, могут быть реализованы в отдельных утилитах, но внутренние команды более удобны. Хотя интерпретация и выполнение команд важны, большая часть возможностей (и сложностей) оболочек связана со встроенными языками программирования. Подобно языкам высокого уровня они включают переменные, конструкции управления потоком, кавычки и функции.

Оболочки предоставляют также функции, предназначенные для интерактивного применения, а не для программирования. Эти интерактивные функции включают управление заданиями, редактирование команд, историю команд и псевдонимы.

2. Определения

POSIX

Семейство стандартов для открытых систем на базе Unix. Bash относится в основном к части Shell and Utilities стандарта POSIX 1003.1.

blank

Символ пробела или табуляции.

builtin — внутренняя команда

Команда, реализованная внутри оболочки, а не во внешней программе на файловой системе.

control operator — оператор управления

Маркер, выполняющий функцию управления. Это может быть перевод строки или одна из последовательностей ||, &&, &, ;, ;;, ;&, ;;&, |, |&, (, ).

exit status — статус выхода

Значение, возвращаемое командой по завершении (0 — 255).

field — поле

Блок текста, являющийся результатом одного или нескольких shell-преобразований (expansion). После преобразования при выполнении команды результирующие поля применяются как имена команд и аргументы.

filename имя файла

Строка символов, служащая для идентификации файла.

job -задание

Набор процессов, образующих конвейер (pipeline), и все процессы-потомки, относящиеся к одной группе.

job control — управление заданием

Механизм, с помощью которого можно селективно останавливать (suspend) и возобновлять (resume) процессы.

metacharacter — мета-символ

Символ, который при использовании без кавычек является разделителем слов. Метасимволы включают пробел, символ табуляции, перевод строки, а также символы |, &, ;, (, ), <, и >.

name — имя

Слово, состоящее лишь из букв, цифр и символов подчеркивания, начинающееся с буквы или символа подчеркивания. Имена используется для shell-переменных и функций, иногда их называют идентификаторами.

operator — оператор

Оператор управления или перенаправления (см. параграф 3.6. Перенаправление). Оператор содержит хотя бы один мета-символ без кавычек.

process group — группа процессов

Набор связанных процессов, имеющих общий идентификатор группы.

process group ID — идентификатор группы процессов

Уникальный идентификатор, представляющий группу процессов при их выполнении.

reserved word — зарезервированное слово

Слово, имеющее в оболочке специальное назначение. Большинство зарезервированных слов служит для создания конструкций управления потоком, например, for и while.

return status — статус возврата

Синоним статуса выхода (завершения).

signal — сигнал

Механизм, с помощью которого ядро может уведомить процесс о произошедшем в системе событии.

special builtin — специальная внутренняя команда

Внутренняя команда оболочки, указанная стандартном POSIX как специальная (особая).

token — маркер

Последовательность символов, воспринимаемая оболочкой как единый блок. Маркер — это слово или оператор.

word — слово

Последовательность символов, трактуемая как слово. Слова не могут включать мета-символы без кавычек.

3. Базовые свойства

Bash — это сокращение Bourne-Again SHell. Bourne shell — традиционная оболочка Unix, написанная изначально Stephen Bourne. Все внутренние функции Bourne shell доступны в bash, правила преобразования и работы с кавычками взяты из спецификации POSIX для «стандартной» оболочки Unix.

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

3.1. Синтаксис

При чтении входных данных выполняется последовательность операций. Если входные данные указывают начало комментария, командный процессор игнорирует символ # и оставшуюся часть строки.

В иных случаях, упрощенно говоря, оболочка считывает ввод и делит его на слова и операторы, используя правила преобразования кавычек для выбора трактовки слов и символов.

Затем процессор разбирает полученные маркеры на команды и другие конструкции, удаляя специальную трактовку некоторых слов и символов и преобразуя иные, перенаправляет ввод и вывод, выполняет специальные команды, ждет результата завершения команды и делает код завершения доступным для дальнейшей проверки или обработки.

3.1.1. Операции

Ниже приведен краткий список операций командного процессора при чтении и выполнении команд

  1. Чтение ввода из файла (3.8. Сценарии оболочки), из строки, представленной в качестве аргумента опции -c при вызове (6.1. Вызов Bash), или с пользовательского терминала.

  2. Разбиение входных данных на слова и операторы в соответствии с правилами обработки кавычек из параграфа 3.1.2. Кавычки. Эти маркеры разделяются мета-символами. Здесь же выполняется преобразование псевдонимов (6.6. Псевдонимы).

  3. Разбор маркеров на простые и составные команды (3.2. Команды).

  4. Выполнение различных преобразований (3.5. Преобразования) с разбиением преобразованных маркеров на имена файлов (3.5.8. Преобразование имен файлов), команды и аргументы.

  5. Выполнение требуемых перенаправлений (3.6. Перенаправление) с удалением опреаторов и операндов перенаправления из списка аргументов.

  6. Выполнение команды (3.7. Выполнение команд).

  7. Необязательное ожидание завершения команды и получения статуса выхода (3.7.5. Статус выхода).

3.1.2. Кавычки

Кавычки служат для обхода специальной трактовки некоторых символов и слов командным процессором. Это может использоваться для отключения специальной трактовки особых символов и зарезервированных слов, а также для отключения преобразований параметров.

Каждый из мета-символов (2. Определения) имеет для командного процессора особый смысл и должен помещаться в кавычки для обычной трактовки. При использовании средств преобразования истории команд (9.3. Преобразование истории) символ преобразования истории (обычно !) должен заключаться в кавычки, чтобы предотвратить преобразование. Более подробно преобразование истории рассмотрено в параграфе 9.1. Средства Bash History.

Имеется три механизма «кавычек» — escape-символы, одинарные и двойные кавычки.

3.1.2.1. Экранирование символов

Символ обратной дробной черты (\) без кавычек является в Bash символом экранирования (escape). Он сохраняет буквальное значение следующего за ним символа, за исключением перевода строки. При получении последовательности \newline без кавычек она трактуется как продолжение текста на следующей строке (т. е. просто удаляется из входного потока).

3.1.2.2. Одинарные кавычки

Заключение символов в одинарные кавычки (’) обеспечивает буквальную трактовку каждого символа внутри кавычек. Одинарные кавычки не могут помещаться внутри другой пары одинарных кавычек даже с символом экранирования.

3.1.2.3. Двойные кавычки

Заключение символов в двойные кавычки («) обеспечивает буквальную трактовку каждого символа внутри кавычек, за исключением символов $, ‘, \, а при преобразовании истории еще и символа !. При работе оболочки в режиме POSIX (6.11. Режим POSIX) символ ! не имеет особого значения внутри двойных кавычек даже при включенном преобразовании истории. Символы $ и ‘ сохраняют особое значение даже в двойных кавычках (3.5. Преобразования). Символ \ сохраняет особое значение лишь в тех случаях, когда за ним следует символ $, ‘, «, \ или newline (в таких случаях символ просто удаляется). Символ \ перед символами, не имеющими особого значения, сохраняется. Двойные кавычки могут применяться внутри двойных кавычек при использовании с символом экранирования \. При включенном преобразовании истории оно будет выполняться, пока символ ! в двойных кавычках не экранирован символом \ (не удаляется перед !). Специальные символы * и @ имеют особую трактовку в двойных кавычках (3.5.3. Преобразование параметров оболочки).

3.1.2.4. Кавычки ANSI-C

Слова в форме $’string’ обрабатываются особо. Слово преобразуется в строку с заменой экранированных \ символов в соответствии со стандартом ANSI C. Escape-последовательности декодируются, как описано ниже.

\a

Сигнал (звонок).

\b

«Забой» (backspace).

\e
\E

Символ экранирования (не ANSI C).

\f

Перевод страницы (form feed).

\n

Новая строка.

\r

Возврат каретки.

\t

Горизонтальная табуляция.

\v

Вертикальная табуляция.

\\

Обратная дробная черта (\).

\’

Одинарная кавычка.

Двойная кавычка.

\?

Знак вопроса.

\nnn

Восьмибитовый символ с восьмеричным кодом nnn (1-3 восьмеричных цифры).

\xHH

Восьмибитовый символ с шестнадцатеричным кодом HH (1-2 шестнадцатеричных цифры).

\uHHHH

Символ Unicode (ISO/IEC 10646) с шестнадцатеричным кодом HHHH (1-4 шестнадцатеричных цифры)

\UHHHHHHHH

Символ Unicode (ISO/IEC 10646) с шестнадцатеричным кодом HHHHHHHH (1-8 шестнадцатеричных цифр)

\cx

Символ control-x.

Преобразованный результат помещается в одинарные кавычки как при отсутствии символа $.

3.1.2.5. Зависимая от языка трансляция

Строка в двойных кавычках с предшествующим символом $ будет преобразовываться в соответствии с текущим языком (locale). Если в качестве locale задан C или POSIX, символ $ игнорируется. Если строка транслируется и заменяется, результат помещается в двойные кавычки. Некоторый системы используют каталог сообщений, определяемый переменной LC_MESSAGES, другие создают имя каталога сообщений из значения переменной окружения TEXTDOMAIN, возможно с добавлением суффикса .mo. При использовании переменной TEXTDOMAIN можетпотребоваться установка в TEXTDOMAINDIR местоположения файлов каталога сообщений. Иногда используются обе переменные в стиле TEXTDOMAINDIR/LC_MESSAGES/LC MESSAGES/TEXTDOMAIN.mo.

3.1.3. Комментарии

В неинтерактивной оболочке или в интерактивной со включенной опцией interactive_comments внутренней функции shopt (4.3.2. Внутренняя команда shopt) слово, начинающееся с # и последующие символы до конца строки игнорируются. Интерактивная оболочка без включенной опции interactive_comments не поддерживает комментарии. Опция interactive_comments включена по умолчанию в интерактивных оболочках, описание которых приведено в разделе 6.3. Интерактивные оболочки.

3.2. Команды

Простые команды, такие как echo a b c, состоят из слова команды и разделенных пробелами аргументов. Более сложные команды состоят из простых команд, сгруппированных тем или иным способом — в конвейер, где вывод одной команды служит вводом для другой, цикл или конструкцию с условием.

3.2.1. Простые команды

Простые команды применяются наиболее часто и представляют собой последовательность слов, разделенных пробелами, завершающуюся одним из операторов управления (2. Определения). Первое слово обычно задает команду для выполнения, а последующие служат аргументами команды.

Статус возврата (3.7.5. Статус выхода) для простой команды является статусом выхода, возвращенным функцией POSIX 1003.1 waitpid, или 128+n, если команда была прервана сигналом n.

3.2.2. Конвейеры

Конвейер — это одна или несколько команд, разделенных оператором | или |&. Формат конвейера имет вид

[time [-p]] [!] command1 [ | or |& command2 ] ...

Вывод каждой команды в конвейере соединяется через канал (pipe) со входом следующей команды, т. е. каждая команда читает результат предыдущей команды. Соединение организуется до перенаправлений, заданных командой.

При использовании оператора |& стандартный вывод ошибок command1 вместе со стандартным выводом соединяется со стандартным вводом command2 через канал. Это сокращенно задается в форме 2>&1 |. Неявное перенаправление стандартного вывода ошибок на стандартный вывод выполняется после перенаправлений, заданных командой.

Зарезервированное слово time активизирует вывод статистики для конвейера по завершении. Статистика включает прошедшее время, а также время выполнения команды в пользовательском и системном пространстве. Опция -p устанавливает формат вывода POSIX. При работе оболочки в режиме POSIX (6.11. Режим POSIX) слово time не считается зарезервированным, если за ним следует маркер, начинающийся с символа -. В переменной TIMEFORMAT может быть задана строка, управляющая выводом значений времени (5.2. Переменные Bash). Использование time в качестве зарезервированного слова разрешено во внутренних функциях, функциях оболочки и конвейерах.

При работе оболочки в режиме POSIX (6.11. Режим POSIX) слово time следовать за newline. В этом случае оболочка выводит время в пользовательском и системном пространстве, затраченное оболочкой и ее потомками. Для задания формата вывода времени может применяться переменная TIMEFORMAT.

Если конвейер не выполняется асинхронно (3.2.3. Списки ), оболочка ждет завершения всех команд контвейера.

Каждая команд конвейера выполняется в своей субоболочке, которая является отдельным процессом (3.7.3. Среда выполнения команды). Если включена опция lastpipe при использовании внутренней команды shopt (4.3.2. Внутренняя команда shopt), последний элемент конвейера может запускаться процессом оболочки.

Статусом выход из конвейера служит статус завершения последней команды, пока не включена опция pipefail (4.3.1. Внутренняя команда set). При включенной опции pipefail статусом завершения конвейера будет последний отличный от нуля код завершения команды, или 0, если все команды конвейера завершились успешно. Если перед конвейером указан символ !, статусом завершения будет логическое обращение описанного выше статуса. Оболочка ждет завершения всех команд конвейера перед возвратом значения.

3.2.3. Списки

Список включает один или несколько конвейеров, разделенных операторами ;, &, && или ||, которые могут завершаться символом ;, &, или newline. Операторы списка && и || имеют одинаковый приоритет, за ними следуют ; и &, также имеющие одинаковый приориет. В списке может присутствовать один или несколько символов newlines для разделения команд (эквивалент ;).

Если команда завершается оператором управления &, она выполняется асинхронно в субоболочке. Это называется выполнением команды в фоновом режиме (background), а здесь такие команды называются асинхронными. Оболочка не ждет завершения команды и возвращает статус 0 (true). При активном управлении заданиями (7. Управление заданиями) стандартным вводом асинхронных команд при отсутствии явного перенаправления служит /dev/null.

Команды, разделенные символом ;, выполняются последовательно и оболочка дожидается выполнения каждой команды по очереди. Статусом возврата служит код завершения последней выполненной команды. Списки && и || являются последовательностями из одного или нескольких конвейеров, разделенных символами && или || и выполняемых слева направо.

В списке

command1 && command2

command2 выполняется тогда и только тогда, когда команда command1 вернула статус 0 (успех). А в списке

command1 || command2

command2 выполняется тогда и только тогда, когда команда command1 вернула отличный от 0 статус. Статусом возврата этих списков является статус выхода последней выполненной команды.

3.2.4. Составные команды

Составные команды являются конструкциями языка программирования оболочки. Каждая конструкция начинается зарезервированным словом или оператором и заканчивается соответствующим зарезервированным словом или оператором. Все перенаправления (3.6. Перенаправление) связанные с составной командой, применяются к каждой команде внутри конструкции, если явно не задано иное.

В большинстве случаев список команд в описании составной команды может быть отделен от остальной команды одним или несколькими символами новой строки и может сопровождаться в конце символом newline вместо ;.

Bash поддерживает конструкции с циклами, условиями и группировкой для выполнения команд как единого блока.

3.2.4.1. Конструкции с циклами

Ниже описаны конструкции с циклами, поддерживаемые bash. Отметим, что символ ; в циклах можно заменить одним или несколькими символами новой строки.

until

Синтаксис цикла until имеет вид

until test-commands; do consequent-commands; done

Выполнение consequent-commands продолжается до тех пор, пока test-commands не возвратит отличный от 0 статус выхода. Статусом выхода из цикла является статус выхода последней выполненной команды из consequent-commands или 0, если ничего не выполнялось.

while

Синтаксис цикла while имеет вид

while test-commands; do consequent-commands; done

Выполнение consequent-commands продолжается до тех пор, пока test-commands не возвратит статус выхода 0. Статусом выхода из цикла является статус выхода последней выполненной команды из consequent-commands или 0, если ничего не выполнялось.

for

Синтаксис цикла for имеет вид

for name [ [in [words ...] ] ; ] do commands; done

Происходит преобразование words (3.5. Преобразования) и выполняются команды один раз для каждого элемента в полученном списке с именем, привязанным к текущему элементу. При отсутствии in words цикл for выполняет команды один раз для каждого позиционного параметра, который установлен, как при указании in «$@» (3.4.2. Специальные параметры). Статусом возврата цикла является статус выхода последней выполненной команды. Если нет элементов при преобразовании words, никакие команды не выполняются и возвращается статус 0.

Поддерживается также другая форма цикла for в виде

for (( expr1 ; expr2 ; expr3 )) ; do commands ; done

Сначала вычисляется арифметическое выражение expr1 в соответствии с правилами, описанными ниже (6.5. Арифметика командного процессора). Затем в цикле вычисляется арифметическое выражение expr2, пока оно не даст результат 0 и в каждом цикле с отличным от 0 значением выполняются команды commands и вычисляется арифметическое выражение expr3. Если любое из выражений опущено, оно считается имеющим значение 1. Статусом возврата служит статус выхода последней выполненной команды или false, если какое-либо из выражений недействительно.

Внутренние операторы break и continue (4.1. Внутренние элементы Bourne Shell) могут служить для управления циклом.

3.2.4.2. Конструкции с условием

if

Синтаксис конструкции if показан ниже.

if test-commands; then
	consequent-commands;
[elif more-test-commands; then
	more-consequents;]
[else alternate-consequents;]
fi

Выполняется список test-commands и, если он возвращает 0, выполняется список consequent-commands. Если test-commands возвращает ненулевой статус, выполняется список elif и при нулевом статусе возврата выполняется список more-consequents. При наличии else alternate-consequents и ненулевом статусе возврата в финальном операторе if или elif, выполняется список команд alternate-consequents. Статусом возврата будет статус выхода последней выполненной команды или 0, если ни одно из условий не было выполнено.

case

Синтаксис конструкции case показан ниже.

case word in
	[ [(] pattern [| pattern]...) command-list ;;]...
esac

В конструкции case будет селективно выполняться список command-list, соответствующий первому совпадению. Сопоставление выполняется в соответствии с правилами параграфа 3.5.8.1. Сопоставление с шаблоном. Если включена опция nocasematch (4.3.2. Внутренняя команда shopt), при сопоставлении регистр символов не принимается во внимание. Символ | служит для разделения шаблонов сопоставления, а ) завершает список шаблонов, который вместе со связанным command-list называют clause (условие).

Каждое условие должно завершаться последовательностью ;;, ;& или ;;&. Для word до сравнения выполняется преобразование тильды и параметров, подстановка команд, арифметическое преобразование и удаление кавычек (3.5.3. Преобразование параметров оболочки). Для каждого шаблона pattern выполняется преобразование тильды и параметров, подстановка команд и арифметическое преобразование

В конструкции может использоваться произвольной число условий (clause), каждое из которых завершается последовательностью ;;, ;& или ;;&. Первый соответствующий шаблон pattern определяет выполняемый список command-list. Часто в качестве последнего варианта применяется шаблон *, которому соответствует все.

Ниже приведен пример использования case в сценарии для описания одной интересной особенности животных.

echo -n "Enter the name of an animal: "
read ANIMAL
echo -n "The $ANIMAL has "
case $ANIMAL in
	horse | dog | cat) echo -n "four";;
	man | kangaroo ) echo -n "two";;
	*) echo -n "an unknown number of";;
esac
echo " legs."

При использовании в конце условия оператора ;; после первого совпадения дополнительных сопоставлений не проводится. При использовании ;& вместо ;; продолжается выполнение списка command-list, связанного со следующим условием. Использование ;;& вместо ;; заставляет оболочку проверять шаблоны следующего условия и выполнять связанный с ним список command-list при совпадении.

Если ни один шаблон не подошел, возвращается статус 0, в остальных случаях возвращается статус выхода последнего command-list.

select

С помощью конструкции select легко создавать меню. Синтаксис конструкции похож на синтаксис for.

select name [in words ...]; do commands; done

Список words после in преобразуется, создавая список элементов. Набор преобразованных слов выводится в стандартный выходной поток ошибок с указанием номера каждого слова. При отсутствии in words выводятся позиционные параметры, как будто указано in «$@». Затем выводится приглашение PS3 и считывается строка со стандартного ввода. Если эта строка содержит число, соответствующее одному из выведенных слов, для переменной name устанавливается значение этого слова. Если строка пуста, слова и приглашения выводятся вновь. Если прочитан символ EOF, выполнение select завершается. При всех прочих значениях ввода для name устанавливается пустое значение. Считанная строка сохраняется в переменной REPLY.

Команды commands выполняются после каждого выбора, пока не будет выполнена команда break, после чего работа select завершается.

Ниже приведен пример, позволяющий выбрать имя файла в текущем каталоге и вывести имя и индекс файла.

select fname in *;
do
echo you picked $fname \($REPLY\)
break;
done

((…))

(( expression ))

Арифметическое выражение, вычисляемое в соответствии с правилами параграфа 6.5. Арифметика командного процессора. Если значение отлично от нуля, возвращается статус 0, в противном случае — 1. Это полный эквивалент выражения let «expression» (см. раздел 4.2. Внутренние команды bash).

[[…]]

[[ expression ]]

Возвращает 0 или 1 в зависимости от вычисления условного выражения expression. Выражения состоят из примитивов, описанных в разделе 6.4. Условные выражения bash. Расщепление слов и преобразование имен файлов не выполняется между скобками [[ ]], но выполняется преобразование тильды, параметров и переменных, преобразование арифметических выражений, подстановка команд и процессов, а также удаление кавычек. Условные операторы, такие как -f должны указываться без кавычек.

При использовании с [[ операторы < и > сортируются лексикографически в соответствии с языковыми настройками.

При использовании операторов == и != строка справа от оператора считается шаблоном и сопоставление выполняется по правилам, описанным в параграфе 3.5.8.1. Сопоставление с шаблоном, как при включенной опции extglob. Оператор = идентичен ==. При включенной опции nocasematch (4.3.2. Внутренняя команда shopt) сопоставление выполняется без учета регистра символов. Возвращается значение 0 при соответствии строк для == и несоответствии для !=, в остальных случаях возвращается значение 1. Любая часть шаблона может быть заключена в кавычки для ее сопоставления как строки.

При доступности дополнительного бинарного оператора =~ он имеет такой же порядок применения как == и !=. При его использовании строка справа считается регулярным выражением POSIX и сопоставляется соответствующим образом (как в regex 3). Возвращается 0 при соответствии строки шаблону и 1 в противном случае. Если регулярное выражение синтаксически некорректно, условное выражение возвращает 2. При включенной опции nocasematch (4.3.2. Внутренняя команда shopt) сопоставление выполняется без учета регистра символов. Любая часть шаблона может быть заключена в кавычки для ее сопоставления как строки. Заключенные в скобки части регулярных выражений должны обрабатываться осторожно, поскольку обычные символы кавычек утрачивают свой смысл между скобками. Если шаблон хранится в переменной оболочки, преобразование переменной в кавычках ведет к сопоставлению всего шаблона как строки. Подстроки, соответствующие заключенным в скобки субвыражениям в регулярном выражении сохраняются в массиве переменной BASH_REMATCH. Элемент BASH_REMATCH с индексом 0 является частью строки, соответствующей всему регулярному выражению. Элемент с индексом n является частью строки, соответствующей n-му субвыражению в скобках.

Например, приведенное ниже выражение будет соответствовать строке line (сохраненной в переменной оболочки line), если в значении есть последовательность символов, содержащая любое число (включая 0) пробелов или экземпляров символа a, за которым следует b.

[[ $line =~ [[:space:]]*?(a)b ]]

В результате такие значения, как ‘aab’ и ‘ aaaaaab’ дадут совпадение, как и строки, содержащие лишь символ b.

Сохранение регулярного выражения в переменной оболочки зачастую полезно для предотвращения проблем с кавычками для символов, имеющих в оболочке особое значение. Иногда сложно задать регулярное выражение буквально без использования кавычек или сохранить след применения кавычек регулярным выражением с учетом удаления кавычек оболочкой. Использование переменной для сохранения шаблона снижает вероятность таких проблем. Ниже приведен аналог предыдущего примера с использованием такой переменной.

pattern=’[[:space:]]*?(a)b’
[[ $line =~ $pattern ]]

Если нужно сопоставление с символом, имеющим особое значение в регулярных выражениях, шаблон следует поместить в кавычки. Например в шаблоне xxx.txt точка (.) соответствует любому символу в строке (обычная трактовка в регулярном выражении), а шаблон «xxx.txt» будет требовать точного совпадения. Программистам следует внимательно относиться к символам \, поскольку в оболочке и регулярных выражениях они задают специальную трактовку следующего символа. Например,

pattern=’\.’
[[ . =~ $pattern ]]
[[ . =~ \. ]]
[[ . =~ "$pattern" ]]
[[ . =~ ’\.’ ]]

Первые два сопоставления дадут совпадение, остальные — нет, поскольку в них символ \ является частью шаблона (кавычки). В двух первых примерах символ \ отменяет специальную трактовку точки, поэтому символ точки будет давать совпадение. Если бы строка в двух первых примерах отличалась от ‘.’ (например, ‘a’), совпадения бы не было, поскольку специальная трактовка точки отменена символом \.

Выражения можно комбинировать с помощью приведенных ниже операторов, указанных в порядке применения.

( expression )

Возвращает значение expression и может применяться для изменения порядка применения операторов.

! expression

Возвращает true, если expression имеет значение false.

expression1 && expression2

Возвращает true, если expression1 и expression2 имеют значение true.

expression1 || expression2

Возвращает true, expression1 или expression2 имеет значение true.

С операторами && и || выражение expression2 не будет вычисляться, если expression1 уже определяет результат.

3.2.4.3 Команды группировки

Bash обеспечивает два способа группировки команд с целью выполнения единым блоком. При группировке команд перенаправление может применяться ко всему набору команд. Например, вывод команд может перенаправляться в один поток.

()

( list )

Указание списка команд в круглых скобках вызывает создание среды субоболочки (3.7.3. Среда выполнения команды) и выполнение каждой команды из списка. Выполнение команд в субоболочке ведет к тому, что назначения переменных, выполненные командами, не сохраняются по завершении работы.

{}

{ list; }

Указание списка команд в фигурных скобках вызывает выполнение этих команд в контексте текущей оболочки без создания субоболочек. Список должен завершаться символом ; или newline.

Кроме создания субоболочки эти варианты имеют различие, обусловленное историческими причинами. Символы фигурных скобок являются зарезервированными, поэтому между скобками и списком команд должен присутствовать пробел или другой мета-символ. Круглые скобки являются оператором и воспринимаются как отдельные маркеры даже при отсутствии пробелов между ними и списком. Для обоих вариантов статусом завершения является статус выхода списка команд.

3.2.5. Копроцессы

Копроцесс (coprocess) — это команда оболочки, которой предшествует зарезервированное слово coproc. Копроцесс выполняется асинхронно в субоболочке, как будто команда содержала в конце управляющий оператор &, с двунаправленным каналом между оболочкой и копроцессом. Формат запуска копроцесса показан ниже.

coproc [NAME] command [redirections]

Эта команда создает копроцесс с именем NAME. Если параметр NAME не задан, применяется имя COPROC. Параметр NAME недопустимо применять с простой командой command (3.2.1. Простые команды), поскольку он будет считаться первым словом простой команды.

При выполнении копроцесса оболочка создает переменную массива (6.7. Массивы) с именем NAME в контексте выполняемой оболочки. Стандартный вывод команды соединяется через канал с дескриптором файла в исполняющей оболочке и этот дескриптор назначается переменной NAME[0]. Стандартный ввод команды соединен каналом с дескриптором файла в исполняющей оболочке и этот дескриптор назначен переменной NAME[1]. Этот канал организуется до перенаправлений, заданных командой (3.6. Перенаправление). Дескрипторы файлов могут служить аргументами команд оболочки и перенаправлений с использованием стандартного преобразования слов. Кроме дескрипторов, созданных специально для выполнения подстановок команд и процессов, в субоболочке нет доступных дескрипторов файлов.

Идентификатор процесса вызванной для выполнения копроцесса оболочки доступен как значение переменной NAME_PID. Можно использовать внутреннюю команду wait для ожидания завершения копроцесса.

Поскольку копроцесс создается как асинхронная команда, coproc всегда возвращает успешный результат. Статусом возврата копроцесса является статус выхода команды command.

3.2.6. GNU Parallel

Имеются способы параллельного выполнения команд, не встроенные в Bash и одним из них является GNU Parallel. Как ясно из имени, GNU Parallel может использоваться для сборки и запуска команд в параллель. Можно запустить одну команду с разными аргументами, будь то имена файлов, пользователей и хостов или строки, прочитанные из файлов. GNU Parallel обеспечивает сокращения для большинства базовых операций (строки ввода и их части, способы задания источника ввода и т. п.). Parallel может заменять команды xargs или feed из различных входов в нескольких разных экземплярах Bash. Полное описание пакета можно найти в документации GNU Parallel, а ниже приведено несколько кратких примеров использования.

Легко заменить xargs для упаковки gzip всех файлов html в текущем каталоге и его подкаталогах, как показано ниже.

find . -type f -name ’*.html’ -print | parallel gzip

Если нужно «защитить» в именах специальные символы, такие как newline, можно использовать опцию find -print0 и опцию parallel -0.

Можно применить Parallel для переноса файлов из текущего каталога, когда число файлов слишком велико для обработки командой mv.

ls | parallel mv {} destdir

В этом случае {} заменяется каждой строкой со стандартного ввода. Хотя команда ls будет работать в большинстве случаев, ее недостаточно для работы со всеми возможными именами. Если нужно обрабатывать файлы со специальными символами в именах, можно применить команду вида

find . -depth 1 \! -name ’.*’ -print0 | parallel -0 mv {} destdir

Эта команда запустит столько команд mv, сколько имеется файлов в текущем каталоге. Можно эмулировать параллельное использование xargs с помощью опции -X, как показано ниже.

find . -depth 1 \! -name ’.*’ -print0 | parallel -0 -X mv {} destdir

GNU Parallel может заменить некоторые распространенные выражения для работы со строками, считываемыми из файла. В приведенном ниже примере это имена файлов, указанные по одному в строке. Обычный вариант имеет вид

while IFS= read -r x; do
do-something1 "$x" "config-$x"
do-something2 < "$x"
done < file | process-output

Но это можно выразить более компактно в форме

cat list | parallel "do-something1 {} config-{} ; do-something2 < {}" |
           process-output

Parallel обеспечивает встроенный механизм удаления расширений в именах файлов, пригодный для массового преобразования или переименования файлов. Например,

ls *.gz | parallel -j+0 "zcat {} | bzip2 >{.}.bz2 && rm {}"

Эта команда будет распаковывать все файлы в текущем каталоге, имеющие расширение .gz, используя программу bzip2 с запуском одного задания на процессор (-j+0) в параллель. В примере для краткости использована команда ls, но можно использовать find для обработки файлов со специальными символами в именах. Parallel может принимать аргументы из командной строки и предыдущий пример можно выразить в форме

parallel "zcat {} | bzip2 >{.}.bz2 && rm {}" ::: *.gz

Если команда создает вывод, может оказаться желанным связать порядок ввода с порядком вывода. Например,

{
	echo foss.org.my ;
	echo debian.org ;
	echo freenetproject.org ;
} | parallel traceroute

будет выводить сначала результат traceroute для закончившейся первой трассировки. Если добавить опцию -k

{
	echo foss.org.my ;
	echo debian.org ;
	echo freenetproject.org ;
} | parallel -k traceroute

первым будет выведен результат трассировки foss.org.my.

Кроме того, parallel можно применять для запуска последовательности команд оболочки в параллель, подобно cat file | bash. Нет ничего необычного в том, чтобы взять список имен файлов, создать серию команд для работы с ними и передать этот список команд в оболочку. Parallel позволяет ускорить обработку. В предположении, что file содержит нужный список команд (по одной в строке) это может иметь вид

parallel -j 10 < file

Команды будут выполняться параллельно после их преобразования (поскольку команды не заданы явно) блоками по 10 одновременных заданий.

3.3. Функции оболочки

Shell-функции обеспечивают способ группировки команд для последующего выполнения с использованием одного имени для группы. Функции выполняются подобно «обычным» командам. Когда имя функции применяется как имя простой команды, выполняется список команд, связанных с именем функции. Shell-функции выполняются в контексте текущей оболочки без создания нового процесса.

Синтаксис объявления функции имеет форму

name () compound-command [ redirections ]

или

function name [()] compound-command [ redirections ]

Это определяет функцию с именем name. Зарезервированное слово function является необязательным, а при его указании круглые скобки становятся необязательными. Тело функции составляет набор команд compound-command (3.2.4. Составные команды). Обычно составная команда представляет собой список команд заключенный в фигурные скобки { }, но это может быть любая составная команда с одним исключением — при использовании зарезервированного слова function без круглых скобок фигурные скобки являются обязательными. В режиме POSIX (6.11. Режим POSIX), имя name не может совпадать с именем какой-либо из специальных внутренних функций (4.4. Специальные внутренние команды). Все перенаправления (3.6. Перенаправление), связанные с функцией, применяются при выполнении функции.

Определение функции можно удалить с помощью опции -f внутренней функции unset (4.1. Внутренние элементы Bourne Shell).

Статус выхода при определении функции имеет значение 0, если не возникло синтаксической ошибки и нет уже функции с таким именем, доступной лишь для чтения. При выполнении функции статус определяется статусом выхода последней выполненной в теле функции команды.

Отметим, что в силу исторических причин фигурные скобки вокруг тела функции в большинстве случаев отделены от тела пробелом или символом новой строки. Это связано с тем, что фигурные скобки являются зарезервированными словами и для распознания в таком качестве должны быть отделены пробелом или иным мета-символом. Кроме того, при использовании фигурных скобок список команд должна завершаться символом ;, & или newline.

При выполнении функции ее аргументы становятся позиционными параметрами (3.4.1. Позиционные параметры). Специальный параметр #, который преобразуется в число позиционных параметров, обновляется с учетом изменений. Специальный параметр 0 не меняется. Первому элементу переменной FUNCNAME присваивается имя функции при ее выполнении.

Все остальные аспекты среды выполнения оболочки идентичны для функции и вызвавшего ее процесса, за исключением того, что прерывания DEBUG и RETURN не наследуются, если для функции не задан атрибут трассировки trace с помощью внутренней функции declare или опции -o внутренней функции set, а прерывание ERR не наследуется, пока не задана опция -o errtrace. Внутренняя функция trap описана в разделе 4.1. Внутренние элементы Bourne Shell.

При установке в переменной FUNCNEST численного значения больше 0 она определяет максимальный уровень вложенности функций. Превышение этого уровня ведет к прерыванию команды.

Если в функции выполняется внутренняя команда return, работа функции завершается и выполняется команда, следующая за вызовом функции. Любые команды, связанные с прерыванием RETURN выполняются перед возвратом управления. Когда функция завершается, позиционные параметры и специальный параметр # восстанавливают значения, которые были перед вызовом функции. Если функции return передано числовое значение, оно будет служить статусом возврата. В остальных случаях функция возвращает статус выхода последней выполненной команды.

Локальные переменные функции можно объявить с помощью встроенного оператора local. Эти переменные будут видны только функции и вызываемым ею командам.

Локальные переменные «затеняют» одноименные переменные, объявленные до вызова функции (вне ее). Например, локальная переменная, определенная внутри функции, будет скрывать одноименную глобальную переменную. Ссылки и назначения будут относиться к локальной переменной, не затрагивая глобальную. При возврате из функции глобальная переменная вновь станет видимой.

Оболочка применяет динамическую область действия для управления видимостью переменных и их значения являются результатом последовательности вызовов функций, которые приведи к текущей функции. Значение переменной, которое видит функция, зависит от ее значения у вызывающей стороны.Например, если переменная var объявлена как локальная в func1 и func1 вызывает другую функцию func2, ссылки на var внутри func2 будет относиться к локальной переменной var из func1, затеняя любую глобальную переменную var, если она имеется. Например,

In func2, var = func1 local
func1()
{
	local var=’func1 local’
	func2
}
func2()
{
	echo "In func2, var = $var"
}
var=global
func1

Внутренняя функция unset также имеет динамическую область действия. Если переменная определена локально, unset будет сбрасывать ее, а в противном случае искать эту переменную ы вызывающей области. Если переменная в локальной области действия сброшена, это будет сохраняться до ее установки в этой области или возврата из функции. После возврата из функции все экземпляры переменных вызвавшей функцию области становятся доступными. Если команда unset была применена к переменной вызывающей области, становится доступным экземпляр, затененный этой переменной (если он есть).

Имена функций и определения могут быть перечислены с помощью опции -f внутренней команды declare (typeset) (4.2. Внутренние команды bash). Опция -F в команде declare или typeset будет выводить только имена функций (может также выводить имя файла и номер строки, если включена опция extdebug). Функции можно экспортировать, чтобы субоболочки автоматически получали их определения при указании опции -f в команде export (4.1. Внутренние элементы Bourne Shell).

Функции могут быть рекурсивными, для ограничения уровня рекурсии может применяться переменная FUNCNEST. По умолчанию глубина рекурсии не ограничена.

3.4. Параметры оболочки

Параметр — это элемент, сохраняющий значения. Параметр может быть именем, номером или обним из специальных символов, указанных ниже. Переменные являются именованными параметрами. Переменная имеет значение и может иметь атрибуты, присваиваемые с помощью внутренней команды declare (4.2. Внутренние команды bash).

Параметр установлен, если ему присвоено значение (включая null). Установленная переменная может быть сброшена внутренней командой unset и установлена выражением вида

name=[value]

Если аргумент value не задан, переменной назначается пустая строка (null). Все значения подвергаются преобразованию тильды, параметров и переменных, подстановке команд, арифметическим преобразованиям и удалению кавычек. Если переменная имеет атрибут integer, ее значение определяется арифметическим преобразованием (3.5.5. Арифметическое преобразование) даже при отсутствии выражения $((…)). Расщепление слов не применяется, за исключением описанного ниже случая $@, преобразование имен файлов также не выполняется. Операторы назначения могут присутствовать как аргументы внутренних команд alias, declare, typeset, export, readonly и local. В режиме POSIX (6.11. Режим POSIX) эти встроенные переменные могут присутствовать в команде после одного или нескольких экземпляров внутренней команды command и сохранять свойства операторов присваивания.

В контексте, где оператор присваивание задает значение переменной оболочки или индексу массива (6.7. Массивы), оператор += может служить для добавления в конец или сложения с прежним значением переменной. Это включает аргументы внутренних команд, таких как declare, которые принимают операторы присваивания. При использовании += с переменной, для которой установлен атрибут integer, значение вычисляется путем арифметического преобразования и складывается с текущим значением, которое тоже преобразуется. Когда += применяется к переменной массива с помощью композитного присваивания (6.7. Массивы), переменная не сбрасывается, как при использовании = и новое значение добавляется в конец массива с индексом на 1 больше текущего максимального индекса (массив с индексом) или добавляется новая пара ключ-значение в ассоциативный массив. Для строковой переменной этот оператор просто добавляет строку в конец имеющейся.

Переменной может быть назначен атрибут nameref с помощью опции -n внутренней команды declare или local (4.2. Внутренние команды bash) для создания nameref или ссылки на иную переменную. Это позволяет манипулировать переменными опосредованно. Всякий раз, когда переменная nameref указывается, назначается, отменяется или изменяются ее атрибуты (иные, нежели nameref), реальная операция выполняется над переменной, заданной значением nameref. Обычно nameref применяется в функциях оболочки для ссылки на переменную, имя которой передается как аргумент функции. Например, если имя переменной передается shell-функции как первый аргумент, выполнение declare -n ref=$1 внутри функции создает nameref-переменную ref, значением которой является имя переменной, переданное первым аргументом. Ссылки и назначение переменной ref, а также изменение ее атрибутов будут трактоваться как ссылки, назначение и изменение атрибутов переменной, имя которой передано как $1.

Если переменная управления циклом for имеет атрибут nameref, список слов может содержать переменные оболочки и ссылка на имя будет создаваться для каждого слова списка при выполнении цикла. Для переменных-массивов атрибут nameref не поддерживается, однако переменные nameref могут указывать переменные массива и индексы. Nameref можно отменить с помощью опции -n внутренней команды (4.1. Внутренние элементы Bourne Shell). Если же unset выполняется с именем переменной nameref в качестве аргумента, сброшена будет переменная, указанная nameref.

3.4.1. Позиционные параметры

Позиционные параметры обозначаются одной или несколькими цифрами, обозначение 0 не используется. Позиционные параметры присваиваются из значений аргументов оболочки при вызове и могут переназначаться с помощью внутренней команды set. Параметр N можно указывать как ${N} или $N (если N содержит одну цифру). Позиционные параметры не могут назначаться операторами присваивания. Для установки и сброса позиционных параметров используются внутренние команды set и unset (4. Внутренние команды оболочки). Позиционные параметры временно заменяются при выполнении shell-функций (3.3. Функции оболочки).

Если номер позиционного параметра содержит более одной цифры, параметр должен заключаться в фигурные скобки.

3.4.2. Специальные параметры

Некоторые параметры оболочки имеют особое значение и их можно лишь указывать без возможности назначения.

*

($*)

Преобразуется в позиционные параметры начиная с первого. Если преобразуемый параметр не заключен в двойные кавычки, каждый позиционный параметр становится отдельным словом. В контексте преобразования эти слова подвергаются расщеплению и преобразованию путей. Если преобразуемый параметр заключен в двойные кавычки, он преобразуется в одно слово, где значения параметров разделены первым символом специальной переменной IFS. Таким образом, «$*» преобразуется в «$1c$2c…», где c — первый символ значения переменной IFS. Если IFS не задана, разделителем служит пробел, а при IFS = null параметры не разделяются.

@

($@)

Преобразуется в позиционные параметры начиная с первого. В контексте, где выполняется расщепление слов, каждый позиционный параметр преобразуется в отдельное слово, которое при отсутствии двойных кавычек подвергается расщеплению слов. В контексте без расщепления слов параметр преобразуется в одно слово с разделением позиционных параметров пробелами. Параметр, заключенный в двойные кавычки, преобразуется с ращеплением слов и выделением каждого параметра в отдельное слово. Таким образом, «$@» является эквивалентом «$1» «$2» … Если раскрытие двойных кавычек выполняется внутри слова преобразованное первое слово объединяется с начальной частью исходного слова, а преобразование последнего — с последней частью исходного слова. При отсутствии позиционных параметров преобразования «$@» и $@ не происходит (т. е. параметр удаляется).

#

($#)

Преобразуется в число позиционных параметров в десятичное значение.

?

($?)

Преобразуется в статус выполненного последним не фонового (foreground) конвейера.

($-)

Преобразуется в текущие флаги опций, заданные при вызове внутренней командой set или установленные самой оболочкой (например, опция -i).

$

($$)

Преобразуется в идентификатор процесса оболочки. В субоболочке () указывается идентификатор процесса вызвавшей оболочки, а не субоболочки.

!

($!)

Преобразуется в идентификатор процесса для задания, помещенного последним в фоновый режим и выполняемого как асинхронная команда или с помощью внутренней команды bg (7.2. Внутренние средства управления заданиями).

0

($0)

Преобразуется в имя оболочки или сценария оболочки. Значение устанавливается при инициализации оболочки. Если Bash вызывается с файлом команд (3.8. Сценарии оболочки), в $0 задается имя этого файла. При запуске Bash с опцией -c (6.1. Вызов Bash), в $0 помещается первый аргумент после выполняемой строки, если он имеется. В остальных случаях параметр получает имя файла, использованного для вызова Bash, указанное аргументом 0.

_

($_)

При запуске оболочки для параметра устанавливается абсолютный путь, заданный при вызове оболочки или сценария и переданный в окружении или списке аргументов. Затем параметр преобразуется в последний предыдущей простой команды, выполняемой в режиме foreground, после преобразования. Устанавливается также полный путь, используемый для вызова каждой выполняемой команды, и помещается в окружение экспортируемое этой команде. При проверке почты в этом параметре содержится имя почтового файла.

3.5. Преобразования

Преобразование командной строки выполняется после ее разбиения на маркеры (компоненты). Имеется несколько типов преобразований, указанных в порядке их применения:

  1. преобразование скобок;

  2. преобразование тильды;

  3. преобразование параметров и переменных;

  4. арифметическое преобразование и подстановка команд (слева направо);

  5. расщепление слов;

  6. преобразование имен файлов.

На системах, которые это поддерживают, возможна также подстановка процессов. Она выполняется одновременно с преобразованием тильды, параметров, переменных, арифметическими преобразованиями и подстановкой команд.

Преобразование скобок, расщепление слов и имен файлов могут увеличивать число слов, а в остальных преобразованиях число слов сохраняется. Единственным исключением является преобразование «$@» и $* (3.4.2. Специальные параметры), а также «${name[@]}» и ${name[*]} (6.7. Массивы).

По завершении этих преобразований выполняется удаление кавычек (3.5.9. Удаление кавычек), если сами они на находятся в других кавычках.

3.5.1. Раскрытие скобок

Раскрытие скобок может генерировать произвольные строки символов. Этот механизм похож на преобразование имен файлов (3.5.8. Преобразование имен файлов), но создаваемые имена могут не существовать. Преобразуемая структура может включать преамбулу, за которой следует цепочка разделенных запятыми строк или выражение между парой скобок, затем может следовать дополнение (постскриптум). Преамбула добавляется перед каждой строкой, содержащейся внутри скобок, а постскриптум добавляется в конец ее. Преобразование выполняется слева направо.

Выражения в скобках могут быть вложенными. Полученные в результате преобразования строки не сортируются. Например,

bash$ echo a{d,c,b}e
ade ace abe

Последовательность имеет форму {x..y[..incr]}, где x и y — целые числа и одиночные символы, а необязательный инкремент incr — целое число. При указании целых числе выражение преобразуется в числа всего диапазона x — y, включая эти значения. Представленные значения целых чисел могут использовать префикс 0 для выравнивания числа цифр каждого элемента. Если x или y начинается с 0, оболочка пытается генерировать элементы с одинаковым числом цефр, добавляя при необходимости 0. При указании символов выражение преобразуется в последовательность символов, лексикографически входящих в диапазон x — y (включительно) в соответствии с принятой по умолчанию языковой настройкой C (locale). Отметим, что оба значения x и y должны быть одного типа. При указании инкремента он задает разницу (интервал) между элементами. По умолчанию используется инкремент 1 или -1 (что подходит).

Раскрытие скобок выполняется до всех других преобразований и поэтому все символы, имеющие особое значение в других преобразованиях, сохраняются. Преобразование является строго текстовым и Bash не пытается синтаксически интерпретировать содержимое выражения или текста между скобками.

Для корректного раскрытия скобок выражение должно содержать открывающую и закрывающую скобку без кавычек, а также хотя бы одну запятую без кавычек или корректное выражение последовательности. Некорректное выражение в скобках остается не преобразованным. Символу { или , может предшествовать экранирующий символ \. Для предотвращения конфликтов при преобразовании параметров строка ${ не считается допустимой при раскрытии скобок и блокирует преобразование до закрывающей скобки.

Приведенная ниже конструкция обычно применяется как сокращение в случаях, когда генерируемый общий префикс строки длиннеее, чем в приведенном выше примере

mkdir /usr/local/src/bash/{old,new,dist,bugs}

или

chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}

3.5.2. Преобразование тильды

Если слово начинается с символа ~ (тильда) без кавычек, все символы до первого символа / без кавычек (или просто все, если / без кавычек нет) считаются символами с тильда-префиксом. Если ни один из символов последовательности с тильдой не заключен в кавычки, символы после тильды трактуются как возможное имя пользователя (login name). Если это имя является пустой строкой, символ тильды заменяется значением переменной оболочки HOME. Если эта переменная не установлена, используется имя домашнего каталога пользователя, запустившего оболочку. В остальных случаях строка с тильда-префиксом заменяется домашним каталогом, связанным с указанным именем пользователя.

Если строка с префиксом имеет значение ~+, оно заменяется значением переменной оболочки PWD, а строка ~- заменяется значением переменной OLDPWD, если она задана.

Если после тильды следует число N (возможно с префиксом + или -), строка заменяется соответствующим элементом из стека каталогов, который будет выводится внутренней командой dirs при вызове с символами, следующими за тильдой (6.8. Стек каталогов). При отсутствии префикса между тильдой и числом предполагается префикс +.

Если имя пользователя (login) не действительно или преобразование тильды привело к отказу, строка остается прежней.

В каждом назначении переменной проверяется наличие тильда-префиксов без кавычек сразу за : или первым =. В таких случаях также выполняется преобразование тильды. Это позволяет применять имена файлов с тильдой в переменных PATH, MAILPATH, CDPATH и оболочка будет назначать перобразованные значения.

Ниже приведены трактовки в Bash тлильда-префиксов без кавычек.

~

Значение переменной $HOME

~/foo

$HOME/foo

~fred/foo

Каталог foo в домешнем каталоге пользователя fred

~+/foo

$PWD/foo

~-/foo

${OLDPWD-’~-’}/foo

~N

Строка, которая будет выведена командой dirs +N

~+N

Строка, которая будет выведена командой dirs +N

~-N

Строка, которая будет выведена командой dirs -N

Bash также выполняет преобразование тильды в словах, удовлетворяющих условиям назначения переменных (3.4. Параметры оболочки), когда они указываются в качестве аргументов простых команд. Bash не делает этого, за исключением перечисленных выше команд объявления при работе в режиме POSIX.

3.5.3. Преобразование параметров оболочки

Символ $ вводит преобразование параметров, подстановку команд или арифметическое преобразование. Преобразуемое имя параметра или символ могут быть заключены в фигурные скобки, которые не обязательны, но позволяют отделить преобразуемую переменную от следующих непосредственно за ней символов, которые могут быть сочтены частью имени. При использовании скобок закрывающей скобкой служит первый символ }, не экранированный с помощью \, не заключенный в кавычки и не входящий во вложенное арифметическое преобразование, подстановку команд или преобразование параметров.

Базовая форма для преобразования параметров имеет вид ${parameter} и выполняется подстановка значения parameter, который является параметром оболочки (3.4. Параметры оболочки) или ссылкой на массив (6.7. Массивы). Скобки требуются для позиционных параметров с несколькими цифрами, а также параметров, за которыми следуют символы, не являющиеся частью имени.

Если первым символом параметра является !, а параметр не является nameref, это задает уровень косвенности (indirection). Bash использует значение, полученное преобразованием остальной части параметра, в качестве нового параметра. Затем этот параметр преобразуется и значение используется в дальнейшем преобразовании вместо преобразования исходного параметра. Для значения выполняется преобразование тильды и параметров, подстановка команд и арифметическое преобразование. Если параметр является nameref, он преобразуется в имя переменной, указанной параметром, вместо полного косвенного преобразования. Исключением являются преобразования ${!prefix*} и ${!name[@]}, описанные ниже. Для введения косвенности восклицательный знак должен быть указан сразу после левой скобки.

В каждом из описанных ниже случаев слово подвергается преобразованию ильды и параметров, подстановке команд и арифметическому преобразованию.

Когда не выполняется преобразование подстрок с использованием описанных ниже форм (например, ‘:-’), Bash проверяет параметры, которые не сброшены (unset) или имеют занчение null. Пропуск двоеточия ведет к проверке лишь сброшенных (unset) параметров. Т. е. при наличии двоеточия оператор проверяет наличие параметра и его «непустоту» (not null), а без двоеточия провеляется лишь наличие параметра.

${parameter:−word}

Если parameter не установлен или имеет значение null, подставляется преобразование word. В остальных случаях подставляется значение parameter.

${parameter:=word}

Если parameter не установлен или имеет значение null, ему назначается преобразование word, после чего выполняется подстановка параметра. Такое назначение не применяется для позиционных и специальных параметров.

${parameter:?word}

Если parameter не установлен или имеет значение null, преобразование word (или об отсутствии word) записывается на стандартное устройство вывода ошибок и оболочка, если она не является интерактивной, завершает работу. В остальных случаях подставляется значение parameter.

${parameter:+word}

Если parameter не установлен или имеет значение null, не подставляется ничего. П остальных случаях подставляется преобразование word.

${parameter:offset}

${parameter:offset:length}

Это называется преобразованием подстроки (Substring Expansion). Преобразуется до length символов parameter, начиная с символа, заданного значением offset. Если parameter имеет значение @, для массива применяется индекс @, * или имя ассоциативного массива (результаты будут разными, как описано ниже). Если параметр length не задан, преобразуется подстрока значения parameter, начиная с offset и до конца значения. Параметры length и offset являются арифметическими выражениями (6.5. Арифметика командного процессора).

Если offset преобразуется в значение меньше 0, это значение используется для отсчета от конца значения parameter. Если length преобразуется в значение меньше 0, это значение считается смещением от конца значения parameter, а не числом символов и преобразование выполняется для символов между offset и result. Отметим, что отрицательное значение offset должно отделяться от двоеточия хотя бы одним пробелом, для предотвращения путаницы с преобразованием :-.

Ниже приведено несколько примеров, демонстрирующих преобразование подстрок для параметров и индексированных массивов.

$ string=01234567890abcdefgh
$ echo ${string:7}
7890abcdefgh
$ echo ${string:7:0}
$ echo ${string:7:2}
78
$ echo ${string:7:-2}
7890abcdef
$ echo ${string: -7}
bcdefgh
$ echo ${string: -7:0}
$ echo ${string: -7:2}
bc
$ echo ${string: -7:-2}
bcdef
$ set -- 01234567890abcdefgh
$ echo ${1:7}
7890abcdefgh
$ echo ${1:7:0}
$ echo ${1:7:2}
78
$ echo ${1:7:-2}
7890abcdef
$ echo ${1: -7}
bcdefgh
$ echo ${1: -7:0}
$ echo ${1: -7:2}
bc
$ echo ${1: -7:-2}
bcdef
$ array[0]=01234567890abcdefgh
$ echo ${array[0]:7}
7890abcdefgh
$ echo ${array[0]:7:0}
$ echo ${array[0]:7:2}
78
$ echo ${array[0]:7:-2}
7890abcdef
$ echo ${array[0]: -7}
bcdefgh
$ echo ${array[0]: -7:0}
$ echo ${array[0]: -7:2}
bc
$ echo ${array[0]: -7:-2}
bcdef

Если parameter имеет значение @, результатом будут length позиционных параметров, начиная с offset. Отрицательное значение offset задает отсчет от последнего позиционного параметра (-1). Если length преобразуется в отрицательное значение, это вызывает ошибку. Ниже приведены примеры преобразования подстрок с использованием позиционных параметров.

$ set -- 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${@:7}
7 8 9 0 a b c d e f g h
$ echo ${@:7:0}
$ echo ${@:7:2}
7 8
$ echo ${@:7:-2}
bash: -2: substring expression < 0
$ echo ${@: -7:2}
b c
$ echo ${@:0}
./bash 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${@:0:2}
./bash 1
$ echo ${@: -7:0}

Если parameter является индексированным массивом с индексом @ или *, результатом будет length элементов массива, начиная с ${parameter[offset]}. Отрицательное значение offset задает отсчет от максимального индекса указанного массива назад. Если length преобразуется в отрицательное значение, это вызывает ошибку. Ниже приведены примеры преобразования подстрок с индексированным массивом.

$ array=(0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h)
$ echo ${array[@]:7}
7 8 9 0 a b c d e f g h
$ echo ${array[@]:7:2}
7 8
$ echo ${array[@]: -7:2}
b c
$ echo ${array[@]: -7:-2}
bash: -2: substring expression < 0
$ echo ${array[@]:0}
0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${array[@]:0:2}
0 1
$ echo ${array[@]: -7:0}

Преобразование подстрок в ассоциативных массивах дает неопределенный результат.

Индексирование подстрок начинается с 0, если не используются позиционные параметры, для которых отсчет по умолчанию начинается с 1. Если для позиционных параметров задано offset = 0, в начале списка выводится $@.

${!prefix*}

${!prefix@}

Преобразуются в имена переменных, начинающиеся с prefix, разделенные первым символом специальной переменной IFS. При использовании @ и наличии двойных кавычек имя каждой переменной преобразуется в отдельное слово.

${!name[@]}

${!name[*]}

Если name является переменной массива, преобразуется в список индексов (ключей), назначенных в name. Если name не является массивом, преобразуется в 0 при установленной переменной name и в null для остальных случаев. При использовании @ и наличии двойных кавычек каждый ключ преобразуется в отдельное слово.

${#parameter}

Подставляется число символов преобразованного значения parameter. Если parameter имеет значение * или @, подставляется число позиционных параметров. Если parameter является именем массива с индексом * или @, подставляется число элементов массива. Если parameter является именем массива с отрицательным индексом, отсчет начинается с конца массива (-1 указывает последний элемент).

${parameter#word}

${parameter##word}

Аргумент word преобразуется для создания шаблона и сопоставления по описанным ниже правилам (3.5.8.1. Сопоставление с шаблоном). Если шаблон соответствует началу преобразованного значения parameter, результатом преобразования будет преобразованное значение с удалением самого короткого (вариант #) или самого длинного (вариант ##) совпадения. Если parameter имеет значение * или @, операция удаления шаблона применяется к каждому позиционному параметру по очереди и результатом преобразования является полученный список. Если parameter является именем массива с индексом * или @, операция удаления шаблона применяется к каждому элементу массива поочередно и результатом преобразования является полученный список.

${parameter%word}

${parameter%%word}

Аргумент word преобразуется для создания шаблона и сопоставления по описанным ниже правилам (3.5.8.1. Сопоставление с шаблоном). Если шаблон соответствует концу преобразованного значения parameter, результатом преобразования будет преобразованное значение с удалением самого короткого (вариант 😉 или самого длинного (вариант %%) совпадения. Если parameter имеет значение * или @, операция удаления шаблона применяется к каждому позиционному параметру по очереди и результатом преобразования является полученный список. Если parameter является именем массива с индексом * или @, операция удаления шаблона применяется к каждому элементу массива поочередно и результатом преобразования является полученный список.

${parameter/pattern/string}

Аргумент pattern преобразуется для создания шаблона как при преобразовании имен, parameter преобразуется и наибольшее совпадение с шаблоном заменяется значением string. Сопоставление выполняется по правилам параграфа (3.5.8.1. Сопоставление с шаблоном). Если pattern начинается с /, все совпадения заменяются на string (обычно замена выполняется лишь для первого совпадения). Если pattern начинается с #, ему соответствует начало преобразованного значения parameter, если pattern начинается с %’, ему соответствует конец преобразованного значения parameter. Если string = null, совпадение с шаблоном удаляется и символ / после pattern может не указываться. При включенной опции оболочки nocasematch (4.3.2. Внутренняя команда shopt) сопоставление выполняется без учета регистра символов. Если parameter имеет значение * или @, подстановка выполняется поочередно для каждого позиционного параметра и результатом преобразования является полученный список. Если parameter является именем массива с индексом * или @, подстановка применяется к каждому элементу массива поочередно и результатом преобразования является полученный список.

${parameter^pattern}

${parameter^^pattern}

${parameter,pattern}

${parameter,,pattern}

Преобразование меняет регистр символов parameter. Аргумент pattern преобразуется для создания шаблона как в преобразовании имен файлов. Каждый символ преобразованного значения parameter сравнивается с шаблоном и при совпадении регистр символа меняется. Не следует сопоставлять шаблон с несколькими символами сразу. Оператор ^ задает преобразование нижнего регистра в верхний, а ‘,’ — обратное преобразование. Преобразования ^^ и ,, конвертируют каждый соответствующий символ в преобразованном значении, ^ и ‘,’ сопоставляют и преобразуют только первый символ преобразованного значения. Если pattern отсутствует, это трактуется как шаблон ?, которому соответствует каждый символ. Если parameter имеет значение * или @, преобразование регистра выполняется поочередно для всех позиционных параметров и результатом преобразования является полученный список. Если parameter является именем массива с индексом * или @, преобразование регистра применяется к каждому элементу массива поочередно и результатом преобразования является полученный список.

${parameter@operator}

Преобразование является изменением значения parameter или информации о parameter в зависимости от оператора operator, задаваемого одной буквой.

Q

Преобразование является строкой заключенного в кавычки значения parameter в пригодном для ввода формате.

E

Преобразование является строкой значения parameter с \-экранированием как в механизме $’…’.

P

Строка, полученная в результате преобразования parameter как будто это строка приглашения (6.9. Управление формой приглашения).

A

Преобразование строки в форме оператора присваивания или объявления, которое при вычислении воссоздает parameter с его атрибутами и значением.

a

Строка значений флагов, представляющих атрибуты parameter.

Если parameter имеет значение * или @, операция поочередно применяется к каждому позиционному параметру и результатом служит полученный список. Если parameter является именем массива с индексом * или @, операция применяется к каждому элементу массива поочередно и результатом является полученный список.

Результат подвергается дальнейшему преобразованию в форме расщепления слов и преобразования путей.

3.5.4. Подстановка команд

Подстановка позволяет заменить команду ее выводом и указывается в форме $(command) или ‘command‘. Bash выполняет преобразование путем выполнения команды command в субоболочке и подстановки ее стандартного вывода в основную оболочку с удалением завершающих символов newline. Символы newline внутри вывода не удаляются, но могут быть исключены при расщеплении слов. Подстановку $(cat file) можно заменить более быстрым эквивалентом $(< file).

При использовании старой формы подстановки с обратными кавычками символ \ сохраняет свое буквальное значение, кроме тех случаев, когда за ним следует $, ‘, или \. Первая обратная кавычка без предшествующего символа \ завершает выражение для подстановки команды. При использовании формы $(command) все символы между скобками являются частью команды без особой трактовки.

Подстановки команд могут быть вложенными. В случае использования формы с обратными кавычками внутренние кавычки экранируются символом \. Если подстановка указана в двойных кавычках, для результата не выполняется расщепление слов и преобразование имен файлов.

3.5.5. Арифметическое преобразование

Арифметическое преобразование позволяет вычислить результат арифметического выражения и подставить вместо него результат. Формат арифметического выражения имеет вид $(( expression )). Здесь expression трактуется как при указании в двойных кавычках, но такие кавычки внутри круглых скобок не имеют специального значения. Все маркеры в expression подвергаются преобразованию параметров и переменных, подстановке команд и удалению кавычек. Результат считается арифметическим выражением для расчета значения. Арифметические выражения могут быть вложенными.

Расчет выполняется в соответствии с правилами раздела 6.5. Арифметика командного процессора. Если выражение не действительно, Bash печатает сообщение об ошибке на стандартном устройстве вывода и не делает подстановки.

3.5.6. Подстановка процессов

Подстановка процессов позволяет указывать ввод или вывод процесса по имени файла. Подстановка имеет вид <(list) или >(list). Список процессов запускается асинхронного и его вход или выход отображается как имя файла. Это имя передается в качестве аргумента текущей команде как результат преобразования. При использовании формы >(list) запись в файл будет служить вводом списка. Если применяется форма <(list), переданный в качестве аргумента файл должен считываться для получения списка. Отметим, что между символом < или > и левой скобкой не может быть пробела, поскольку в этом случае выражение будет задавать перенаправление. Подстановка процессов доступна в системах, поддерживающих именованные каналы (fifo) и метод именования открытых файлов /dev/fd.

При доступности подстановки процессов она выполняется одновременно с преобразованием параметров и переменных, подстановкой команд и арифметическим преобразованием.

3.5.7. Расщепление слов

Оболочка сканирует результат преобразования параметров, подстановки команд и арифметического преобразования, которые выполнялись вне двойных кавычек, на предмет расщепления слов. Оболочка трактует каждый символ переменной $IFS как разделитель слов в результатах предшествующих преобразований. Если переменная IFS не задана или имеет принятое по умолчанию значение <space><tab><newline>, последовательности <space>, <tab>, <newline> в начале и в конце результата игнорируются, а последующие символы IFS считаются разделителями слов. Если значение IFS отличается от принятого по умолчанию, последовательности пробельных символов (<space><tab><newline>), а также пробельные символы IFS в начале и в конце игнорируются. Любой непробельный символ IFS вместе со смежными пробельными символами IFS считается разделителем слов, равно как и последовательность пробельных символов IFS, Если переменная IFS имеет пустое значение (null), слова не разделяются.

Явно пустые аргументы («» или ’’) сохраняются и передаются командам в виде пустых строк. Неявные null-аргументы без кавычек, полученные в результате преобразования параметров, не имеющих значений, удаляются. Если преобразуемый параметр в двойных кавычках имеет пустое значение, полученный в результате null-аргумент сохраняется и передается команде как пустая строка. Когда заключенный в кавычки null-аргумент является частью слова, которое преобразуется в непустое значение, null-аргумент удаляется. Например, слово -d’’ преобразуется в -d.

При отсутствии преобразований расщепления слов не производится.

3.5.8. Преобразование имен файлов

После расщепления слов, если не задана опция -f внутренней команды set (4.3.1. Внутренняя команда set), Bash сканирует каждое слово в поиске символов *, ? и [. При наличии любого из этих символов слово считается шаблоном и заменяется отсортированным по алфавиту списком имен файлов, соответствующих шаблону (3.5.8.1. Сопоставление с шаблоном). Если соответствующих шаблону имен не найдено, а опция оболочки nullglob отключена, слово сохраняется без изменений. При включенной опции nullglob и отсутствии совпадений слово удаляется, выводится сообщение об ошибке и команда не выполняется. Если включена опция оболочки nocaseglob, сопоставление выполняется без учета регистра символов.

При выполнении преобразования, символ ‘.’ в начале имени или сразу после / должен сопоставляться буквально, если не задана опция оболочки dotglob. Имена ‘.’ и ‘..’ всегда должны сопоставляться буквально, даже если включена опция dotglob. В остальных случаях символ ‘.’ не имеет специального значения.

При сопоставлении имен файлов символ / всегда должен точно соответствовать такому же символу в шаблоне, но в ином контексте сопоставления он может соответствовать иным символам, как описано в параграфе 3.5.8.1. Сопоставление с шаблоном.

Опции nocaseglob, nullglob, failglob и dotglob описаны в параграфе 4.3.2. Внутренняя команда shopt.

Переменную оболочки GLOBIGNORE можно применять для ограничения набора имен, соответствующих шаблону. Если эта переменная установлена, каждое совпадающее имя файла сопоставляется также с одним из шаблонов в GLOBIGNORE и удаляется из списка при совпадении. Если установлена опция nocaseglob, сопоставление с GLOBIGNORE выполняется без учета регистра. Имена . и .. игнорируются при установке непустой переменной GLOBIGNORE. Однако установка непустого значения GLOBIGNORE будет включать опцию dotglob, поэтому все имена, начинающиеся с ‘.’, будут совпадать с шаблоном. Для поддержки прежнего поведения с игнорированием имен, начинающихся с точки, следует добавить шаблон ‘.*’ в переменную GLOBIGNORE. Опция dotglob отключена, если переменная GLOBIGNORE не установлена.

3.5.8.1. Сопоставление с шаблоном

Все символы шаблона, за исключением описанных ниже специальных символов, должны совпадать при сопоставлении. Символ nul не может включаться в шаблоны, символ \ экранирует следующий символ, а сам при сопоставлении не учитывается. Специальные символы для буквальной трактовки в шаблоне должны заключаться в кавычки.

Специальные символы шаблонов и их трактовка описаны ниже.

*

Соответствует любой строке, включая пустую. При включенной опции globstar и использовании символа * в контексте преобразования имен файлов, два смежных символа * в одном шаблоне будут соответствовать всем файлам и имеющимся каталогам и подкаталогам. Если перед парой символов * имеется /, соответствовать шаблону будут лишь каталоги и подкаталоги.

?

Соответствует одному (любому) символу.

[…]

Соответствует одному из указанных в скобках символов. Пара символов, разделенных дефисом указывает диапазон, включающий граничные символы, с использованием порядка и набора символов текущего языка. Если после открывающей скобки [указан символ ! или ^, соответствовать шаблону будет любой символ, не входящий в диапазон. Символ − может указываться в качестве первого или последнего в диапазоне, ] — в качестве первого. Порядок сортировки симвлов в диапазоне определяется текущим значением locale и переменными LC_COLLATE и LC_ALL, если они установлены.

Например, с используемым по умолчанию C диапазон [a-dx-z] будет эквивалентен набору [abcdxyz]. Многие языки (locale) сортируют символы по словарю и для них [a-dx-z] обычно не является эквивалентом [abcdxyz] и может быть, например, эквивалентом [aBbCcDdxXyYz]. Для получения традиционной интерпретации диапазонов в квадратных скобках можно использовать C locale путем установки в переменной LC_COLLATE или LC_ALL значения C или включения опции globasciiranges.

Внутри скобок [] можно указать класс символов в форме [:class:], где class — одно из значений, определенных стандартом POSIX: alnum, alpha, ascii, blank, cntrl, digit, graph, lower, print, punct, space, upper, word, xdigit.

Классу соответствует любой символ указанного класса, например, классу word соответствуют буквы, цифры и _.

Внутри скобок [] можно указать класс эквивалентности с использованием синтаксиса [=c=], которому будут соответствовать все символы с таким весом сравнения (collation) в соответствии с настройкой, как у символа c.

Внутри скобок [] синтаксис [.symbol.] соответствует символу symbol.

Если опция оболочки extglob включена с использованием внутренней команды shopt, применяется несколько расширенных сопоставлений с шаблоном. В последующих описаниях pattern-list — это список, включающий по меньшей мере один шаблон с разделением шаблонов символом |. Могут создаваться композитные шаблоны с использованием одного или нескольких субшаблонов, описанных ниже.

?(pattern-list)

Соответствует не более, чем одному вхождению указанных шаблонов.

*(pattern-list)

Соответствует любому числу вхождений указанных шаблонов.

+(pattern-list)

Соответствует не менее, чем одному вхождению указанных шаблонов.

@(pattern-list)

Соответствует одному вхождению указанных шаблонов.

!(pattern-list)

Соответствует всему, за исключением любого из указанных шаблонов.

Сопоставление расширенных шаблонов с длинными строками является медленным, особенно при наличии в шаблонах чередований а в строках — многочисленных совпадений. Использование отдельных сопоставлений для более коротких строк или применение массива строк вместо одной длинной строки может ускорить процесс.

3.5.9. Удаление кавычек

После выполнения описанных выше преобразований удаляются все не заключенные в кавычки символы \, ’ и «, не являющиеся результатом предшествующих преобразований.

3.6. Перенаправление

Перед выполнением команды ее ввод и вывод могут быть перенаправлены с использованием специальной нотации командного процессора. Перенаправление позволяет дублировать, открывать, закрывать, ссылаться на другие файлы и менять файлы, которые команда читает или записывает. Описанные ниже перенаправления могут предшествовать команде, а также указываться внутри или после команды. Перенаправления обрабатываются в порядке их указания, слева направо.

Для каждого перенаправления, которому может номер дескриптора файла, вместо такого номера может быть указано слово вида {varname}. В этом случае для каждого оператора перенаправления, кроме >&- и <&-, командный процессор может назначить дескриптор файла больше 10 и присвоить его {varname }. Если слову {varname } предшествует >&- или <&-, значение varname определяет дескриптор файла для закрытия. Если указано слово {varname}, перенаправление остается за рамками команды, что позволяет программировать управление дескриптором.

В последующих описаниях при опущенном номере дескриптора файла первый символ перенаправления < задает стандартный ввод (дескриптор 0), а первый символ > — стандартный вывод (дескриптор 1). Для слова за оператором перенаправления в последующих описаниях (если явно не указано иное) выполняется преобразование фигурных скобок, тильды и параметров, подстановка команд, арифметические преобразования, удаление кавычек, преобразование имени файла и расщепление слов. Если в результате получается более одного слова, bash возвращает ошибку.

Порядок перенаправления имеет значение. Например, команда ls > dirlist 2>&1 направляет стандартный вывод (дескриптор 1) и стандартный вывод ошибок (дескриптор 2) в dirlist, а команда ls 2>&1 > dirlist направляет в файл dirlist лишь стандартный вывод, поскольку стандартный вывод ошибок выполняет копирование стандартного вывода до его перенаправления в dirlist.

Bash обрабатывает некоторые имена файлов при перенаправлениях в соответствии с приведенным ниже описанием. Если операционная система, где работает bash, использует такие файлы, bash будет применять их. В остальных случаях будет выполняться внутренняя эмуляция, описанная ниже.

/dev/fd/fd

Если fd является пригодным целым числом, файловый дескриптор fd дублируется.

/dev/stdin

Файловый дескриптор 0 дублируется.

/dev/stdout

Файловый дескриптор 1 дублируется.

/dev/stderr

Файловый дескриптор 2 дублируется.

/dev/tcp/host/port

Если host является действительным именем хоста или адресом Internet, а port — целочисленным номером порта или именем службы bash пытается открыть соответствующий сокет TCP.

/dev/udp/host/port

Если host является действительным именем хоста или адресом Internet, а port — целочисленным номером порта или именем службы bash пытается открыть соответствующий сокет UDP.

Отказ при открытии или создании файла ведет к отказу перенаправления.

Перенаправление с файловыми дескрипторами больше 9 следует применять с осторожностью, поскольку это может вызывать конфликты с дескрипторами, используемыми внутри командного процессора.

3.6.1. Перенаправление ввода

Перенаправление ввода ведет к тому, что открывается для чтения файл, имя которого получено из слова команды, для дескриптора n или стандартного ввода (дескриптор 0), если n отсутствует. Базовый формат перенаправления ввода имеет вид

[n]<word

3.6.2. Перенаправление вывода

Перенаправление ввода ведет к тому, что открывается для записи файл, имя которого получено из слова команды, для дескриптора n или стандартного вывода (дескриптор 1), если n отсутствует. Файл при открытии усекается до нулевого размера. Базовый формат перенаправления вывода имеет вид

[n]>[|]word

Если используется оператор перенаправления > и включена опция noclobber для внутренней команды set, перенаплавление будет приводить к отказу, если полученное после преобразования имя указывает реально существующий обычный файл. Если указан оператор перенаправления >| или оператор > с выключенной опцией noclobber, будет выполнена попытка перенаправления даже при наличии указанного словом файла.

3.6.3. Добавление перенаправленного вывода

Перенаправление вывода таким способом ведет к открытию файла, имя которого получено из преобразования word, в режиме добавления в конец для файлового дескриптора n или стандартного вывода (дескриптор 1), если n отсутствует. Если нужного файла нет, он создается. Базовый формат перенаправления в конец файла имеет вид

[n]>>word

3.6.4. Перенаправление стандартного вывода и стандартного вывода ошибок

Эта конструкция позволяет перенаправить стандартный вывод (дескриптор 1) и стандартный вывод ошибок (дескриптор 2) в файл, имя которого определяется преобразованием параметра word. Применяются 2 варианта — &>word и >&word. Первая форма семантически эквивалентна >word 2>&1. При использовании второй формы параметр word может быть преобразован не в число или -. В таких случаях применяются другие операторы перенаправления (3.6.8. Дублирование файловых дескрипторов) для обеспечения совместимости.

3.6.5. Добавление стандартного вывода и стандартного вывода ошибок

Эта конструкция позволяет перенаправить стандартный вывод (дескриптор 1) и стандартный вывод ошибок (дескриптор 2) в конец имеющегося файла, имя которого указывается преобразованием word. Формат добавления вывода в файл иммет вид &>>word, что семантически эквивалентно выражению >>word 2>&1 (см. 3.6.8. Дублирование файловых дескрипторов).

3.6.6. Перенаправление из документа

Этот тип перенаправления задает оболочке чтение файла до строки, содержащей лишь word (без пробелов в конце). Все прочитанные из файла строки затем служат стандартным вводом (или файлом с дескриптором n, если он задан) для команды.

Формат here-document имеет вид

[n]<<[−]word
	here-document
delimiter

Для word не выполняется преобразования параметров и переменных, подстановки команд, арифметического преобразования и преобразования имен файлов. Если какая-либо часть word заключена в кавычки, разделитель delimiter является результатом удаления кавычек из word, а строки here-document не раскрываются. Если word не содержит кавычек, все строки here-document подвергаются преобразованию параметров, подстановке команд и арифметическому преобразованию. Последовательность \newline игнорируется, а символ \ должен применяться для экранирования \, $ и ‘.

Если задан оператор перенаправления <<-, все предшествующие символы табуляции игнорируются во входных строках и строке, содержащей delimiter. Это позволяет работать с shell-сценариями, использующими табуляцию.

3.6.7. Перенаправление из строки

Вариант here-document, имеющий формат [n]<<< word. Параметр word подвергается преобразованию тильды, параметров и переменных, подстановке команд, арифметическому преобразованию и удалению кавычек. Преобразование путей и расщепление слов не применяются. Результат представляется как одна строка с символом newline в конце на стандартный ввод (или файл с дескриптором n, если он задан.

3.6.8. Дублирование файловых дескрипторов

Оператор перенаправления [n]<&word служит для дублирования дескрипторов входных файлов. Если word преобразуется в одну или несколько цифр, дескриптор файла, обозначенный n, становится соответствующим преобразованному числу. Если word преобразуется в -, файл с дескриптором n закрывается. Если n не задано, используется стандартный ввод (дескриптор 0).

Оператор [n]>&word используется аналогичным способом для дублирования дескрипторов выходных файлов. Если n не задано, используется стандартный вывод (дескриптор 1). Если цифры word не задают дейкриптора файла, открытого для вывода, возникает ошибка перенаправления. Если word преобразуется в -, файл с дескриптором n закрывается. Особым случаем является отсутствие n и преобразование word, отличное от цифр и -. В этом случае выполняется перенаправление стандартного вывода и стандартного вывода ошибок, описанное выше.

3.6.9. Перемещение файловых дескрипторов

Оператор перенаправления [n]<&digit- перемещает файловый дескриптор digit в файловый дескриптор n или стандартный ввод (дескриптор 0), если параметр n не задан. Файл с дескриптором digit закрывается после дублирования.

Оператор [n]>&digit- перемещает файловый дескриптор digit в файловый дескриптор n или стандартный вывод (дескриптор 1), если параметр n не задан.

3.6.10. Дескрипторы открытия файлов для чтения и записи

Оператор перенаправления [n]<>word вызывает открытие файла, имя которого задано преобразованием word, для чтения и записи с файловым дескриптором n (или 0, n не задано). Если такого файла нет, он создается.

3.7. Выполнение команд

3.7.1. Преобразование простых команд

При вводе простой команды оболочка выполняет перечисленные ниже преобразования, назначения и перенаправления.

  1. Слова, которые анализатор отметил как назначения переменных (до команды), и перенаправления сохраняются для последующей обработки.

  2. Слова, не относящиеся к назначению переменных и перенаправлению преобразуются (3.5. Преобразования). Если после преобразования остаются какие-либо слова, первое из них считается именем команды, а остальные — ее аргументами.

  3. Выполняется перенаправление (3.6. Перенаправление).

  4. Текст после символа = в каждом назначении переменной подвергается преобразованию тильды и параметров, подстановке команд, арифметическому преобразованию и удалению кавычек до назначения его переменной.

Если результат не содержит имени команды, назначения применяются к переменным текущей оболочки. В остальных случаях переменные назначаются в среде выполняемой команды и не влияют на окружение текущей оболочки. При попытке задать значение переменной, доступной лишь для чтения, возникает ошибка и команда возвращает отличных от 0 статус.

Если результат не содержит имени команды, перенаправления выполняются, но не оказывают влияния на текущую среду оболочки. Ошибка перенаправления вызывает завершение с отличным от 0 статусом возврата.

Если после преобразований осталось имя команды, выполнение продолжается, как описано ниже. В противном случае команда завершается. Если какое-либо преобразование включает подстановку команд, статусом возврата команды будет статус выхода последней подстановки команды. Если подстановки команд не было, возвращается статус 0.

3.7.2. Поиск и выполнение команд

Если результатом расщепления команды на слова является простая команда с необязательным списком аргументов, выполняются перечисленные ниже действия.

  1. Если имя команды не содержит символов /, оболочка пытается найти нужную команду. При наличии функции оболочки с нужным именем, эта функция вызывается, как описано в разделе 3.3. Функции оболочки.

  2. Если имя не соответствует функции, оболочка просматривает список внутренних команд и при нахождении нужной команды выполняет ее.

  3. Если имени нет в числе функций и внутренних команд и оно не включает символов /, Bash выполняет поиск исполняемого файла в каталогах переменной $PATH. Bash использует хэш-таблицу для запоминания полных путей к исполняемым файлам для снижения числа обращений к переменной PATH (см. описание hash в параграфе 4.1. Внутренние элементы Bourne Shell). Полный поиск в переменной $PATH выполняется лишь при отсутствии команды в хэш-таблице. Если поиск не дал результата, оболочка пытается найти функцию с именем command_not_found_handle. При наличии такой функции она вызывается в отдельной среде выполнения с использованием исходной команды и ее параметров в качестве аргументов, а статус выхода этой функции служит статусом завершения субоболчки. Если функция не найдена, оболочка выводит сообщение об ошибке и возвращает статус 127.

  4. Если поиск дал результат или имя команды содержит один или несколько символов /, оболочка выполняет указанную именем команду в отдельной среде. Аргументу 0 присваивается имя команды, а остальные аргументы служат аргументами выполняемой команды.

  5. Если при выполнении команды возникает отказ по причине того, что файл не является исполняемым и этот файл не является каталогом, предполагается, что это сценарий оболочки и выполняется процедура, описанная в параграфе 3.8. Сценарии оболочки.

  6. Если команда не была запущена асинхронно, оболочка ждет завершения команды и определяет его статус.

3.7.3. Среда выполнения команды

Среда выполнения оболочки включает ряд элементов, перечисленных ниже.

  • Открытые файлы, наследуемые оболочкой при вызове и измененные путем перенаправления, предоставляемых внутренней функции exec.

  • Текущий рабочий каталог, установленный командой cd, pushd, popd или унаследованный при вызове.

  • Режим создания файлов, установленный umask или унаследованный от родителя оболочки.

  • Текущие прерывания (trap) установленные функцией trap.

  • Параметры оболочки, заданные путем назначения переменных, с помощью команды set или унаследованные от родителя оболочки.

  • Функции оболочки, определенные в процессе работы или унаследованные от родителя.

  • Опции, включенные при вызове (принятые по умолчанию или заданные в команде) или установленные с помощью set.

  • Опции, включенные shopt (4.3.2. Внутренняя команда shopt).

  • Псевдонимы, определенные с помощью alias (6.6. Псевдонимы).

  • Идентификаторы процессов, включая идентификаторы фоновых заданий (3.2.3. Списки ), значения $$ и $PPID.

При выполнении простой команды, не являющейся внутренней, или shell-функции она вызывается в отдельной среде исполнения, включающей указанные ниже элементы (если не указано иное, значения наследуются из оболочки).

  • Открытые файлы оболочки с учетом изменений и дополнений, заданных перенаправлениями команды.

  • Текущий рабочий каталог.

  • Маска режима создания файлов.

  • Переменные и функции оболочки, указанные для экспорта, вместе с переменными экспортированными для команды, которые были переданы в окружении (3.7.4. Окружение)

  • Прерывания, захваченные оболочкой, сбрасываются к значениям, унаследованным от родителя оболочки, а игнорируемые оболочкой прерывания не учитываются.

Команда, вызываемая в этой отдельной среде, не может оказывать влияния на среду оболочки.

Подстановки команд, команды, объединенные круглыми скобками, и асинхронные команды вызываются в среде субоболочки, которая дублирует окружение основной оболочки за исключением того, что установленные оболочкой прерывания сбрасываются к значениям, унаследованным оболочкой при вызове от родитеоя. Изменения в среде субоболочки не могут влиять на окружение оболочки.

Субоболочки, порожденные для выполнения подстановки команд, наследуют значение опции -e от родительской оболочки. При работе не в режиме POSIX оболочка Bash сбрасывает опцию -e в таких субоболочках.

Если за командой следует символ &, а управление заданиями не активизировано, принятым по умолчанию стандартным вводом для команды служит /dev/null. В остальных случаях вызываемая команда наследует дескрипторы файлов от вызывающей оболочки с учетом перенаправлений.

3.7.4. Окружение

При вызове программы она получает массив строк, называемый окружением или средой. Этот список включает пары «имя-значение» в формате name=value.

Bash обеспечивает несколько способов управления средой. При вызове оболочка сканирует свое окружение и создает параметр для каждого найденного имени, автоматически помечая его для экспорта в дочерние процессы. Выполняемые команды наследуют окружение. Команды export и declare -x позволяют добавлять параметры и функции в среду или удалять их. При изменении параметра в окружении новое значение становится частью среды взамен прежнего. Среда, наследуемая каждой выполняемой командой, состоит из начального окружения оболочки, значения которого можно изменять, за исключением пар, удаляемых командой unset или export -n, а также дополнений, вносимых командами export и declare -x.

Среду для простой команды или функции можно временно дополнить с помощью префиксов с назначением параметров, как описано в параграфе 3.4. Параметры оболочки. Эти назначения влияют лишь на среду, видимую данной командой. Если установлена опция -k (4.3.1. Внутренняя команда set), все назначения параметров помещаются в среду для команды в дополнение к предшествующим имени команды.

Когда Bash вызывает внешнюю команду, в переменной $_ устанавливается полный путь к этой команде и он передается в среду данной команды.

3.7.5. Статус выхода

Статусом завершения выполняемой команды является число, возвращаемое системным вызовом waitpid или эквивалентной функцией. Статус может принимать значения от 0 до 255, а значения более 125 могут иметь особый смысл. Статус вывода внутренних функций и составных команд также ограничен значением 125. Специальные значения используются оболочкой при некоторых обстоятельствах для указания особых вариантов отказа.

В оболочке возврат командой статуса 0 означает успешное выполнение, а отличное от 0 значение говорит об отказе. Эта, на первый взгляд нелогичная, схема обеспечивает однозначную индикацию успеха и различные способы указания отказов. При завершении команды со статусом N оболочка Bash возвращает в качестве статуса значение 128+N.

Если команда не найдена, дочерний процесс, созданный для ее выполнения, возвращает статус 127. Если найденная команда не является исполняемой, статус возврата будет иметь значение 126. При отказе команды в результате ошибки при преобразовании или перенаправлении возвращается статус больше 0.

Статус выхода используется условными командами Bash (3.2.4.2. Конструкции с условием) и некоторыми списками (3.2.3. Списки ).

Все внутренние команды Bash возвращают статус выхода 0 при успешном выполнении и отличных от 0 статус при отказе, что может применяться в условных выражениях и списках. Все внутренние команды возвращают статус 2 для индикации некорректного использования, что обычно связано с непригодными опциями или отсутствием аргументов.

3.7.6. Сигналы

При работе Bash в интерактивном режиме в отсутствие каких-либо прерываний оболочка игнорирует сигнал SIGTERM (поэтому kill 0 не прерывает активную оболочку), а SIGINT перехватывается и обрабатывается (с прерыванием функции ожидания). Когда Bash получает SIGINT, выполнение всех имеющихся циклов прерывается. Сигнал SIGQUIT игнорируется во всех случаях. При включенном управлении заданиями (7. Управление заданиями) Bash игнорирует SIGTTIN, SIGTTOU и SIGTSTP.

Для внешних команд, запускаемых Bash, значения обработчиков сигналов наследуются оболочкой от родителя. Когда управления заданиями нет, асинхронные команды игнорируют сигналы SIGINT и SIGQUIT в дополнение к унаследованным обработчикам. Команды, выполняемые в результате подстановки, игнорируют полученные от клавиатуры сигналы управления заданиями SIGTTIN, SIGTTOU, SIGTSTP.

По умолчанию оболочка завершает работу по сигналу SIGHUP. Перед выходом интерактивная оболочка повторяет SIGHUP для всех заданий (работающих и остановленных). Остановленные задания передают SIGCONT, подтверждающий получение SIGHUP. Чтобы оболочка не передавала SIGHUP конкретному заданию, следует удалить его из таблицы заданий с помощью внутренней команды disown (7.2. Внутренние средства управления заданиями) или пометить его как не получающее сигнал SIGHUP с помощью disown -h.

Если была установлена опция huponexit с помощью внутренней команды shopt (4.3.2. Внутренняя команда shopt), Bash передает SIGHUP всем заданиям при завершении интерактивной оболочки (login shell).

Если Bash ожидает завершения команды и получает сигнал, для которого установлена ловушка, прерывание не будет выполняться до завершения команды. Когда Bash ждет завершения асинхронной команды с помощью внутренней команды wait, получение сигнала, для которого установлена ловушка, будет приводить к незамедлительному возврату из внутренней команды wait со статусом 128, после чего сразу выполняется прерывание.

3.8. Сценарии оболочки

Сценарий оболочки (shell script) представляет собой текстовый файл с командами оболочки. При использовании такого файла в качестве первого аргумента, не являющегося опцией в вызове Bash и отсутствии опций -c и -s (6.1. Вызов Bash) Bash считывает и выполняет команды из этого файла, затем возвращает управление. Такой режим работы называется неинтерактивным. Файл ищется сначала в текущем каталоге, затем в каталогах $PATH.

При выполнении сценария Bash устанавливает в специальном параметре 0 имя файла вместо имени оболочки, а позиционными параметрами становятся оставшиеся аргументы. Если их нет, позиционные параметры не устанавливаются.

Сценарий можно сделать исполняемым с помощью команды chmod. Когда Bash такой файл в $PATH, порождается субоболочка для его выполнения. Т. е. команда filename arguments эквивалентна bash filename arguments, если filename является исполняемым файлом сценария. Эта субоболочка инициализирует себя, как будто для сценария вызвана новая оболочка, за исключением того, что расположение команд, запомненных родителем (см. описание hash в параграфе 4.1. Внутренние элементы Bourne Shell), сохраняется потомком.

Большинство версий Unix делают это частью механизма выполнения команд. Если первая строка сценария начинается символами #!, остальная часть этой строки задает интерпретатор команд для сценария. Это позволяет выбрать интерпретатор Bash, awk, Perl и т. п., а оставшуюся часть сценария написать на соответствующем языке.

Аргументы интерпретатора состоят из одного необязательного аргумента в первой строке файла сценария, следующего за именем интерпретатора, за которым может следовать имя файла сценария и остальные аргументы. Bash выполнит нужные действия в операционной систем, которая сама не справляется с этим. Отметим, что некоторые старые версии Unix ограничивают размер строки с именем интерпретатора и аргументами 32 символами.

Сценарии Bash часто насинаются строкой #! /bin/bash (в предположении установки Bash в каталоге /bin), поскольку это обеспечивает выполнение команд интерпретатором Bash даже при запуске сценария из иной оболочки.

4. Внутренние команды оболочки

Встроенные команды реализованы в самой оболочке. При использовании внутренней команды в качестве первого слова простой команды (3.2.1. Простые команды) оболочка напрямую выполняет команду без вызова других программ. Внутренние команды нужны для реализации функций, которые невозможно или неудобно выполнять внешними утилитами. В этой главе кратко описаны встроенные функции Bash, унаследованные от Bourne Shell, а также внутренние команды, присущие Bash или расширенные в этой оболочке.

Некоторые внутренние команды описаны в других параграфах — команды интерфейса Bash для управления заданиями (7.2. Внутренние средства управления заданиями), стек каталогов (6.8.1. Внутренние команды стека каталогов), команды истории (9.2. Внутренние команды истории Bash) и программируемые инструменты завершения команд (8.7. Внутренние функции программируемого дополнения). Многие из этих команд были расширены в POSIX или Bash.

Если явно не указано иное, каждая из внутренних команд, описанная как воспринимающая опции с префиксом -, принимает — для обозначения конца опций. Внутренние элементы :, true, false и test/[ не принимают опций и не применяют специальной трактовки —. Внутренние функции exit, logout, return, break, continue, let и shift воспринимают и обрабатывают аргументы с префиксом -, не требуя —. Остальные встроенные функции, которые принимают аргументы, но не указаны как принимающие опции, трактуют аргументы с префиксом — как ошибки и требуют — для предотвращения такой интерпретации.

4.1. Внутренние элементы Bourne Shell

Приведенные ниже внутренние операторы и команды унаследованы от Bourne Shell и реализованы в соответствии со стандартом POSIX.

: (двоеточие)

: [arguments]

Не делает ничего, кроме преобразования аргументов и выполнения перенаправлений. Статус возврата 0.

. (точка)

. filename [arguments]

Считывает и выполняет команды из файла filename в контексте текущей оболочки. Если filename не начинается с символа /, для поиска файла применяется переменная PATH. Когда bash работает не в режиме POSIX, просматривается также текущий каталог, если файл не найден в $PATH. Если представлены какие-либо аргументы, они становятся позиционными параметрами при выполнении filename. В остальных случаях позиционные параметры остаются неизменными. При включенной опции -T source наследует все ловушки (прерывания) DEBUG, а если это не так, любая строка DEBUG trap сохраняется перед вызовом source и восстанавливается после него, а source отменяет DEBUG trap при выполнении. Если опция -T не задана и выполняемый файл меняет DEBUG, по завершении source сохраняется новое значение. Статусом возврата является статус выхода последней выполненной команды или 0, если команды не выполнялись. Если файл filename не найден или его не удалось причитать, статус возврата будет отличен от 0. Этот оператор эквивалентен команде source.

break

break [n]

Выход из цикла for, while, until или select loop. При наличии параметра n выполняется выход из n-го вложенного цикла. Значение n должно быть не меньше 1. Возвращает статус 0, пока n не меньше 1.

cd

cd [-L|[-P [-e]] [-@] [directory]

Меняет текущий рабочий каталог на directory. Если параметр directory не указан, применяется значение переменной HOME. Все аргументы после directory игнорируются. При наличии переменной оболочки CDPATH она используется как путь поиска — каждое имя в CDPATH просматривается на предмет directory. Имена каталогов в CDPATH разделяются символом :. Если параметр directory начинается с символа /, CDPATH не используется.

Опция -P отключает следование по символьным ссылкам. Символьные ссылки преобразуются, когда cd проходит directory и до обработки экземпляра .. в directory. По умолчанию или при задании опции -L символьные ссылки в directory преобразуются после того, как cd обработает экземпляр .. в directory. Если .. присутствует в directory, это значение обрабатывается путем удаления непосредственно предшествующего элемента пути в направлении / или начала directory.

При наличии опций -e и -P и невозможности определения текущего каталога после смены cd будет возвращать статус отказа.

В системах, поддерживающих опцию -@, она задает расширенные атрибуты, связанные с файлом в качестве directory.

Если directory имеет значение -, оно преобразуется в $OLDPWD до попытки смены каталога.

При использовании непустого имени каталога из CDPATH или первом аргументе — и успешной смене каталога абсолютное имя нового рабочего каталога передается на стандартный вывод.

При смене каталога возвращается статус 0, при неудаче — отличное от нуля значение.

continue

continue [n]

Возобновляет следующую итерацию цикла for, while, until или select. Если указан параметр n, возобновляется n-й цикл. Значение n должно быть не меньше 1. Возвращает статус 0, если не было задано значение n меньше 1.

eval

eval [arguments]

Аргументы (arguments) объединяются в одну команду, которая считывается и выполняется, Статус завершения команды будет статусом выхода eval. При отсутствии arguments или пустых аргументах возвращается статус 0.

exec

exec [-cl] [-a name] [command [arguments]]

При наличии параметра command команда заменяет оболочку без создания нового процесса. Если задана опция -l, оболочка помещает тире в начале нулевого аргумента, передаваемого команде (это то, что делает программа login). Опция -c задает выполнение команды с пустым окружением. При наличии опции -a оболочка передает name в качестве нулевого аргумента для command. Если команда не может быть выполнена по какой-либо причине, неинтерактивная оболочка завершается, пока не включена опция execfail и возвращается статус отказа. Интерактивная оболочка возвращает отказ при невозможности выполнить файл (команду). Субоболочка завершается безусловно при отказе exec. Если команда не задана, могут использоваться перенаправления для воздействия на реду текущей оболочки. Если перенаправления не приводят к ошибке, возвращается статус 0, в случае ошибки статус будет ненулевым.

exit

exit [n]

Выход из оболочки с возвратом родителю статуса n. Если параметр n не задан, возвращается статус завершения последней команды. Все прерывания EXIT выполняются до завершения оболочки.

export

export [-fn] [-p] [name[=value]]

Помечает каждое имя name для передачи дочерним процессам в среде. Наличие опции -f указывает, что имена относятся к функциям оболочки, без этой опции они указывают переменные оболочки. Опция -n отменяет пометки для экспорта name. Если имена не указаны или задана опция -p, выводится список всех экспортируемых переменных в форме, пригодной для ввода. Если после имени переменной следует значение (=value), это значение устанавливается для переменной.

Возвращается статус 0, если не было задано непригодных опций или имен переменных (name), а также опция -f не была указана с недействительным именем функции оболочки.

getopts

getopts optstring name [args]

Команда getopts используется сценариями оболочки для разбора позиционных параметров. Аргумент optstring содержит символы опции для распознавания. Если за символом следует двоеточие, предполагается наличие у опции аргумента, который должен быть отделен пробелом. Двоеточие и знак вопроса не могут использоваться как символы опций. При каждом вызове getopts помещает следующую опцию в переменную оболочки name, инициализируя переменную при ее отсутствии, а индекс следующего обрабатываемого элемента — в переменную OPTIND. Переменная OPTIND инициализируется значением 1 при каждом вызове оболочки или shell-сценария. Когда опции нужен аргумент, getopts помещает его в переменную OPTARG. Оболочка не сбрасывает OPTIND автоматически и переменную нужно сбрасывать вручную между вызовами getopts в рамках одного вызова оболочки, если будет применяться новый набор параметров.

При достижении конца опций getopts завершает работу с кодом возврата, отличным от 0. В OPTIND указывается индекс первого аргумента, не являющегося опцией, а для name устанавливается значение ‘?’.

Команда getopts обычно анализирует позиционные параметры, но при наличии дополнительных аргументов в args разбираются эти аргументы.

Ошибки getopts могут возвращаться двумя способами. Если первым символом optstring является двоеточие, используется «тихое» уведомление об ошибках, а при обычной работе выводится диагностическое сообщение с указанием непригодных или пропущенных опций. Если OPTERR = 0, сообщания об ошибках не выводятся даже при отсутствии двоеточия в первом символе optstring.

При обнаружении недействительной опции getopts помещает ? в name и в обычном (не «тихом») режиме выводит сообщение об ошибке и сбрасывает OPTARG. В «тихом» режиме символ опции помещается в OPTARG без вывода диагностического сообщения.

Если нужный аргумент не найден и для getopts не задан «тихий» режим, в name помещается ?, OPTARG сбрасывается и выводится диагностическое сообщение. Если getopts работает в «тихом» режиме, в name помещается :, а в OPTARG — найденный символ опции.

hash

hash [-r] [-p filename] [-dt] [name]

При каждом вызове hash запоминаются полные пути к командам, указанным в качестве аргументов, поэтому их уже не нужно искать при последующих вызовах. Поиск команд выполняется путем просмотра каталогов, указанных в переменной $PATH. Все ранее запомненные пути отбрасываются. Опция -p отключает поиск пути а filename служит для указания местоположения name. Опция -r заставляет оболочку забыть все запомненные местоположения, опция -d заставляет забыть запомненное местоположение каждого значения name. При наличии опции -t выводится полный путь, которому соответствует каждое значение name. При указании множества аргументов name с опцией -t, значения name выводятся перед хэшированными путями. Опция -l обеспечивает вывод в формате, пригодном для ввода. Если опция -l задана без каких-либо других аргументов команды, выводится информация о запомненных командах.

Статус возврата имеет значение 0, если команда не содержит недействительной опции и name найдено.

pwd

pwd [-LP]

Выводит абсолютный (полный) путь к текущему каталогу. Опция -P исключает вывод символьных ссылок в пути, опция -L включает. Статусом возврата будет 0, если не возникло ошибок при определении пути к текущему каталогу или не была задана недействительная опция.

readonly

readonly [-aAf] [-p] [name[=value]] ...

Помечает каждую переменную name как доступную лишь для чтения. Значения этой переменной невозможно будет изменить путем назначения. При наличии опции -f параметр name относится к функциям оболочки. Опция -a связывает name с переменными индексированных массивов, -A — с переменными ассоциативных массивов. При наличии обеих опций будет применяться -A. Если аргументов name не задано или указана опция -p, выводится список переменных, доступных только для чтения, в формате пригодном для ввода. Могут применяться другие опции для ограничения выводимого множества имен readonly. Если имя задано в форме name=value, для переменной устанавливается значение value. Команда возвращает статус 0, если не указано недействительных опций, параметр name не задает недействительную переменную или функцию оболочки и опция -f не указана с параметром name, не соответствующим функции оболочки.

return

return [n]

Вызывает остановку функции оболочки с возвратом статуса n. Если параметр n не указан, статусом возврата будет статус выхода последней команды, выполненной в функции. Если команда return вызывается обработчикм прерываний (trap), для определения статуса используется последняя команда, вызванная перед обработчиком прерывания. При вызове return в процессе обработки прерывания DEBUG статус возврата определяется последней командой, выполненной обработчиком прерывания перед вызовом return. Команду return можно применять для прерывания сценариев, выполняемых с помощью внутренней команды . (source), возвращая n или статус выхода последней выполненной команды сценария. При указанном значении n возвращаются 8 младших битов этого значения. Любая команда, связанная с прерыванием RETURN, выполняется до возобновления исполнения после функции или сценария. Статус возврата отличается от 0, если команда return вызвана с аргументом, не являющимся числом, использована за пределами функции или не в процессе выполнения сценария с помощью внутренней команды . или source.

shift

shift [n]

Сдвигает позиционные параметры влево на n позиций, в результате чего параметры $n+1 — $# становятся $1 — $#-n, а параметры $# — $#-n+1 сбрасываются. Значение n должно быть неотрицательным целым числом или $#. Если n=0 или больше $#, позиционные параметры не меняются. По умолчанию предполагается n=1. Возвращается статус 0, если n не превышает $# и не является отрицательным.

test

[

test expr

Вычисляется условное выражение expr и возвращается статус 0 (true) или 1 (false). Каждый оператор и операнд должен быть отдельным аргументом. Выражения состоят из примитивов, описанных в разделе 6.4. Условные выражения bash. Команда test не принимает опций, а также не воспринимает (игнорирует) аргумент —, указывающий завершение опций.

При использовании формы [ последним аргументом команды должна быть закрывающая скобка ].

Выражения могут комбинироваться с использованием перечисленных ниже операторов (в порядке снижения предпочтения). Результат зависит от числа аргументов, как описано ниже. При 5 и более аргументах используется порядок применения операторов.

! expr

True, если expr дает false.

( expr )

Возвращает значение expr и может использоваться для переопределения порядка применения операторов.

expr1 -a expr2

True, если оба выражения expr1 и expr2 дают true.

expr1 -o expr2

True, если любое их выражений expr1 и expr2 дает true.

Внутренние функции test и [ оценивают условные выражения на основе правил, учитывающих число аргументов.

0

Выражение дает false.

1

Выражение дает true тогда и только тогда, когда аргумент отличен от null.

2

Если первым аргументом является !, выражение дает true тогда и только тогда, когда второй аргумент имеет значение null. Если первым аргументом является один из унарных условных операторов (6.4. Условные выражения bash), выражение дает true, если унарная проверка дает true. Если первый аргумент не является действительным унарным оператором, выражение дает false.

3

Применяются приведенные ниже правила в указанном порядке.

  1. Если вторым аргументом является один из бинарных условных операторов (6.4. Условные выражения bash), результатом выражения является результат применения бинарного оператора к первому и третьему аргументам. При наличии у команды 3 аргументов операторы -a и -o считаются бинарными.

  2. Если первым оператором является !, значение является отрицанием теста с использованием второго и третьего аргументов.

  3. Если первым аргументом является (, а третьим — ), результатом будет тест для второго аргумента (внутри скобок).

  4. В остальных случаях выражение дает false.

4

Если первым оператором является !, результатом будет отрицание трехаргументного выражения, образуемого оставшимися аргументами. В остальных случаях выражение анализируется и оценивается с использованием порядка применения операторов и приведенных выше правил.

5 и более

Выражение анализируется и оценивается с использованием порядка применения операторов и приведенных выше правил.

При использовании с test или [ операторы < и > работают с лексикографической сортировкой на базе ASCII.

times

times

Выводит пользовательское и системное время, применяемое оболочкой и ее потомками. Статус возврата 0.

trap

trap [-lp] [arg] [sigspec ...]

Команды, указанные параметром arg, будут считываться и выполняться при получении оболочкой сигнала sigspec. Если параметр arg не задан (и есть один сигнал sigspec) или имеет значение -, каждое заданное размещение сигнала сбрасывается к значению перед запуском оболочки. Если arg является пустой строкой (null), сигнал, заданный каждым параметром sigspec, игнорируется оболочкой и вызываемыми ею командами. Если arg отсутствует и задана опция -p, оболочка выводит команды прерывания, связанные с каждым sigspec. Если аргументы не заданы или указана лишь опция -p, команда trap выводит список команд, связанных с каждым номером сигнала в форме, которая может служить вводом для оболочки. Опция -l заставляет оболочку выводить список имен сигналов с их номерами. Каждый параметр sigspec является именем или номером сигнала. Регистр символов в именах сигналов не принимается во внимание, а префикс SIG не обязателен.

Если sigspec имеет значение 0 или EXIT, команда arg выполняется при выходе из оболочки. Если sigspec = DEBUG, команда arg выполняется перед каждой простой командой, for, case, select, каждым арифметическим преобразованием для команды и перед выполнением первой команды в функции оболочки. В описании опции extdebug внутренней команды shopt (4.3.2. Внутренняя команда shopt) рассмотрено влияние на прерывание DEBUG. Если sigspec = RETURN, команда arg выполняется каждый раз, когда завершается shell-функция или сценарий, выполняемые с использованием внутренних функций . или source.

Если sigspec = ERR, команда arg выполняется всякий раз, когда конвейер (может состоять из одной простой команды), список или составная команда возвращает отличный от нуля статус завершения при соблюдении перечисленных далее условий. Прерывание ERR не выполняется, если отказавшая команда является частью списка, следующего сразу за ключевым словом until или while, частью проверки, следующей сразу за ключевым словом if или elif, частью команды, выполняемой в списке && или ||, кроме команды, следующей за последним && или ||, не последней командой конвейера или командой, статус возврата которой инвертируется символом !. Этим же условия действуют для опции errexit (-e).

Сигналы, игнорируемые на входе в оболочку, не могут быть перехвачены или сброшены. Перехваченные сигналы, которые не игнорируются, возвращаются к исходным значениям субоболочки или среды, где они были созданы.

Статус возврата равен 0, пока sigspec не задает действительный сигнал.

umask

umask [-p] [-S] [mode]

Задает для процессов создания файлов маску mode. Если значение mode начинается с цифры, оно считается восьмеричным числом, в противном случае — символьной маской, аналогичной используемой в команде chmod. Если параметр mode не указан, выводится текущее значение маски. Если задана опция -S без аргумента, маска выводится в символьном формате. Если задана опция -p, а параметр mode не указан, маска выводится в форме, пригодной для ввода. При изменении маски или отсутствии параметра mode команда возвращает 0.

Отметим, что при задании маски восьмеричным числом каждая цифра маски вычитается из 7, т. е. маска 022 задает режим доступа к файлу 755.

unset

unset [-fnv] [name]

Удаляет каждую переменную или функцию с именем name. При наличии опции -v удаляются переменные оболочки с соответствующим именем, опция -f задает удаление определений функций оболочки. Если задана опция -n, а name является переменной с атрибутом nameref, будет сбрасываться name, а не переменная, которую указывает name. Опция -n не работает вместе с -f. Если опций не задано, каждое значение name указывает переменную, а если такой переменной нет, сбрасывается функция с именем name. Доступные лишь для чтения переменные и функции не могут быть сброшены командой unset. Команда возвращает 0, если не было попытки сбросить достуный лишь для чтения элемент.

4.2. Внутренние команды bash

В этом разделе описаны внутренние команды, которые уникальны для Bash или были расширены в этой оболочке. Некоторые из этих команд относятся к стандарту POSIX.

alias

alias [-p] [name[=value] ...]

Без аргументов или с опцией -p команда alias печатает список псевдонимов на стандартном устройстве вывода в форме, подходящей для ввода в другие команды. При наличии аргументов определяется псевдоним для каждого параметра name, значение которого указано. Если значение не задано, выводится name и value имеющегося псевдонима. Псевдонимы описаны в разделе 6.6. Псевдонимы

bind

bind [-m keymap] [-lpsvPSVX]
bind [-m keymap] [-q function] [-u function] [-r keyseq]
bind [-m keymap] -f filename
bind [-m keymap] -x keyseq:shell-command
bind [-m keymap] keyseq:function-name
bind [-m keymap] keyseq:readline-command

Выводит текущие привязки ключей и функций Readline (8. Редактирование командной строки), привязывает последовательность-ключ к функции или макросу Readline или устанавливает переменную Readline. Каждый аргумент, не являющийся опцией, служит командой в том виде, как она указана в файле инициализации Readline (8.3. Файл инициализации Readline), но каждая привязка или команда должна передаваться как отдельный аргумент, например, ‘»\C-x\C-r»:re-read-init-file’. Значение опций описано ниже.

-m keymap

Задает использование keymap в качестве раскладки, на которую будут влиять последующие привязки. Пригодными именами привязок являются emacs, emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, vi-command, vi-insert. Привязка vi эквивалентна vi-command (vi-move также является синонимом), emacs эквивалентна emacs-standard.

-l

Список имен всех функций Readline.

-p

Выводит имена функций Readline и привязки в форме, пригодной для ввода или файла инициализации Readline.

-P

Выводит имена функций Readline и привязки.

-v

Выводит имена и значения переменных Readline в форме, пригодной для ввода или файла инициализации Readline.

-V

Выводит имена и значения переменных Readline.

-s

Выводит последовательности нажатия клавиш Readline, привязанные к макросам и строкам вывода в форме, пригодной для ввода или файла инициализации Readline.

-S

Выводит последовательности нажатия клавиш Readline, привязанные к макросам и строкам вывода.

-f filename

Считывает привязки клавиш из файла.

-q function

Запрос клавиш вызова указанной функции.

-u function

Отвязка всех клавиш для указанной функции.

-r keyseq

Удаление всех текущих привязок для keyseq.

-x keyseq:shell-command

Вызывает выполнение shell-command при вводе keyseq. При выполнении команды оболочка устанавливает в переменной READLINE_LINE текущее содержимое буфера строк Readline, а в READLINE_POINT — текущую точку вставки. Если выполненная команда изменила значение READLINE_LINE или READLINE_POINT, новые значения будут отражены в состоянии редактирования.

-X

Выводит все последовательности клавиш, привязанные к командам оболочки в пригодном для ввода формате.

Команда возвращает статус 0, если не было ошибок или непригодных опций.

builtin

builtin [shell-builtin [args]]

Запускает внутреннюю команду оболочки, передавая ей аргументы и возвращая статус завершения. Это полезно при определении функции оболочки, имя которой совпадает со внутренней командой, для сохранения функциональности команды внутри функции. Статус возврата будет ненулевым, если параметр shell-builtin не задает внутреннюю команду оболочки.

caller

caller [expr]

Возвращает контекст любого активного вызова подпрограммы (функции оболочки или сценария, выполняемого со внутренней командой . или source).

При запуске без параметра expr вызывающая сторона выводит номер строки и имя файла для текущего вызова подпрограммы. Если expr содержит неотрицательное целое число, выводится номер строки, имя подпрограммы и файл, соответствующие данной позиции в стеке вызовов. Эта информация может применяться, например, для вывода трассировки стека. Текущим является кадр 0.

Команда возвращает статус отличный от 0, если оболочка не выполняет вызов подпрограммы или expr не соответствует действительной позиции в стеке вызовов.

command

command [-pVv] command [arguments ...]

Запускает команду command с аргументами arguments, игнорируя функцию оболочки с именем command. Выполняются лишь внутренние команды и команды, найденные по пути PATH. Т. е. при наличии функции ls команда command ls внутри этой функции будет выполнять внешнюю команду ls, а не вызывать функцию рекурсивно. Опция -p задает использование принятого по умолчанию значения PATH, обеспечивающего нахождение всех стандартных утилит. Статус возврата в этом случае будет 127, если command не удается найти или возникает ошибка. В остальных случаях возвращается статус выхода command.

При наличии опции -V или -v выводится описание command. Опция -v обеспечивает вывод одного слова, указывающего команду, а -V дает более подробный вывод. В этом случае статус возврата будет 0, если команда найдена.

declare

declare [-aAfFgilnrtux] [-p] [name[=value] ...]

Объявляет переменные и задает их атрибуты. Если параметров name не задано, команда выводит значения переменных.

Опция -p задает вывод значений и атрибутов для каждого параметра name. При использовании -p с аргументами name все другие опции, за исключением -f и -F, игнорируются. При указании опции -p без name будут выводиться значения и атрибуты переменных, имеющих атрибуты, заданные другими опциями. Если других опций нет, -p обеспечивает вывод значений и атрибутов всех переменных оболочки. Опция -f ограничивает вывод shell-функциями.

Опция -F предотвращает вывод определений функций и печатаются лишь имена и атрибуты. Если включена опция extdebug с помощью внутренней команды shopt (4.3.2. Внутренняя команда shopt), будут также выводиться имена файлов и номера строк, где определена каждая переменная name. Опция -F подразумевает наличие -f. Опция -g задает создание и изменение переменных в глобальном масштабе даже при выполнении declare из функции оболочки. В других случаях опция игнорируется.

Ниже приведен список опций, которые могут служить для ограничения числа выводимых переменных.

-a

Каждое имя, являющееся переменной индексированного массива (6.7. Массивы).

-A

Каждое имя, являющееся переменной ассоциативного массива (6.7. Массивы).

-f

Только имена функций.

-i

Переменная трактуется как целое число, при установке значения выполняются арифметические преобразования (6.5. Арифметика командного процессора).

-l

При установке значения символы верхнего регистра переводятся в нижний. Атрибут upper-case отключен.

-n

Задает для каждой переменной name атрибут nameref, делая ее ссылкой на другую переменную. Эта переменная указывается значение value для name. Все ссылки, назначения и изменения атрибутов name, кроме использующих или меняющих сам атрибут -n, выполняются для переменной, указанной value. Атрибут nameref не применим к переменным массивов.

-r

Делает переменные name доступными лишь для чтения. Этим переменным не могут быть присвоены или сброшены значения в последующих операторах или командах unset.

-t

Задает для каждого name атрибут trace. Трассируемые функции наследуют ловушки DEBUG и RETURN из вызывающей оболочки. Атрибут trace не имеет специального значения для переменных.

-u

При установке значения символы нижнего регистра переводятся в верхний. Атрибут lower-case отключен.

-x

Помечает каждую переменную name для экспорта в последующие команды через окружение.

Использование + вместо — отключает атрибут, за исключением того, что +a и +A не могут использоваться для уничтожения переменных массива, а +r не будет удалять атрибут readonly. При использовании в функции команда declare делает каждое имя name локальным как при использовании команды local, за исключением случаев наличия опции -g. Если за name следует =value, для переменной устанавливается значение value.

При использовании -a или -A и синтаксиса составного назначения для создания переменных массивов дополнительные атрибуты не будут работать до последующих назначений. Статусом возврата будет 0, если нет непригодных опций, попыток определить функцию с помощью -f foo=bar, попыток задать значение доступной лишь для чтения переменной, попыток назначить значения переменной массива без использования синтаксиса составного назначения (6.7. Массивы), указания в name недействительной переменной оболочки, попыток отключить статус readonly для переменной readonly, попыток отключить статус массива для переменной массива или попыток вывести несуществующую функцию с помощью опции -f.

echo

echo [-neE] [arg ...]

Выводит аргументы (arg), разделенные пробелами и завершающиеся символом новой строки. Статус возврата имеет значение 0, если не возникло ошибок. При наличии опции -n символ newline в конце строки подавляется. Опция -e включает \-экранирование последующих символов. Опция -E отключает экранирование символов даже в системах, где оно включено по умолчанию. Опция оболочки xpg_echo может служить для динамического управления преобразованием экранируемых символов в эхо-строке. Команда echo не интерпретирует последовательность — (конец опций).

Интерпретируемые командой echo escape-последовательности приведены ниже.

\a

Сигнал (звонок).

\b

«Забой» (backspace).

\c

Подавление последующего вывода.

\e
\E

Символ экранирования (не ANSI C).

\f

Перевод страницы (form feed).

\n

Новая строка.

\r

Возврат каретки.

\t

Горизонтальная табуляция.

\v

Вертикальная табуляция.

\\

Обратная дробная черта (\).

\0nnn

Восьмибитовый символ с восьмеричным кодом nnn (1-3 восьмеричных цифры).

\xHH

Восьмибитовый символ с шестнадцатеричным кодом HH (1-2 шестнадцатеричных цифры).

\uHHHH

Символ Unicode (ISO/IEC 10646) с шестнадцатеричным кодом HHHH (1-4 шестнадцатеричных цифры)

\UHHHHHHHH

Символ Unicode (ISO/IEC 10646) с шестнадцатеричным кодом HHHHHHHH (1-8 шестнадцатеричных цифр)

enable

enable [-a] [-dnps] [-f filename] [name ...]

Включает и отключает внутренние команды оболочки. Запрет внутренней команды позволяет использовать взамен одноименную внешнюю команду (файл) без указания полного пути, хотя обычно оболочка выбирает сначала внутреннюю команду. При указании опции -n заданные аргументами name команды отключаются. В противном случае команды name включаются. Например, для использования двоичного исполняемого файла test, доступного в пути $PATH, вместо внутренней функции можно использовать команду enable -n test.

Если задана опция -p или нет аргумента name, выводится список внутренних команд оболочки. При отсутствии других аргументов список будет включать все включенные внутренние команды оболочки. С опцией -a указывается включена команда или выключена.

Опция -f задает загрузку новой внутренней команды name из общего объекта filename в системе, поддерживающей динамическую загрузку. Опция -d удаляет внутреннюю команду, загруженную с -f.

Если опций не задано, выводится список внутренней команд оболочки. Опция -s ограничивает включение специальными внутренними командами POSIX. Если опции -s и -f указаны вместе, новая внутренняя команда становится специальной (4.4. Специальные внутренние команды).

Команда возвращает статус 0, пока name задает внутреннюю команду оболочки и при загрузке новой внутренней команды из общего объекта не возникает ошибки.

help

help [-dms] [pattern]

Выводит информацию о встроенных командах. Если задан аргумент pattern, будет выводиться подробная информация о всех командах , соответствующих шаблону. В остальных случаях выводится список внутренних команд. Опции команды описан ниже.

-d

Выводить краткое описание для каждого значения pattern.

-m

Выводить описание для каждого значения pattern в формате, похожем на вывод man.

-s

Выводить лишь краткий синтаксис применения для каждого значения pattern.

Команда возвращает статус 0, если хотя бы одна команда соответствует pattern.

let

let expression [expression ...]

Внутренняя команда let позволяет выполнять арифметические операции с переменными оболочки. Каждый аргумент expression преобразуется в соответствии с правилами раздела 6.5. Арифметика командного процессора. Если последнее преобразование дает 0, команда let возвращает статус 1, в остальных случаях возращается 0.

local

local [option] name[=value] ...

Для каждого аргумента создается локальная переменная с именем name и значением value. Аргумент option может задавать любые опции, пригодные для команды declare. Команда local может применяться лишь в функциях, она делает переменную name видимой только в этой функции и ее потомках. Если указано имя -, набор параметров оболочки делается локальным для функции, где вызвана команда local. Опции оболочки, измененные внутри функции, восстанавливают свои значения при возврате из функции. Команда возвращает статус 0, пока она применяется внутри функции, значение name действительно и переменная name доступна для записи.

logout

logout [n]

Выход из оболочки login с возвратом родителю статуса n.

mapfile

mapfile [-d delim] [-n count] [-O origin] [-s count]
    [-t] [-u fd] [-C callback] [-c quantum] [array]

Читает строки в переменную индексированного массива со стандартного ввода или из файла с дескриптором fd, если задана опция -u. По умолчанию массив задан переменной MAPFILE. Опции команды описаны ниже.

-d

Первый символ аргумента delim служит разграничителем строк вместо символа newline. Если delim является пустой строкой, mapfile будет завершать строку при считывании символа NUL.

-n

Максимальное число копируемых строк (count). По умолчанию число стро не ограничено (0).

-O

Начинать заполнение массива с индекса origin (по умолчанию 0).

-s

Отбрасывать первые count прочитанных строк.

-t

Удалять символ delim (по умолчанию newline) в конце каждой строки.

-u

Читать строки из файла с дескриптором fd вместо стандартного ввода.

-C

Оценивать обратный вызов (callback) при считывании каждых quantum строк. Значение задает -c quantum.

-c

Задает число строк, считываемых между вызовами callback.

Если опция -C задана без указания -c, по умолчанию применяется quantum = 5000. При оценке обратного вызова ему представляется индекс назначаемого следующим элемента массива и строка для присвоения этому элементу как добавочные аргументы. Оценка callback выполняется после чтения строки но до назначения элемента массива.

Если в команде явно не указано значение origin, команда mapfile очищает массив перед присвоением значений.

Команда mapfile возвращает 0, если не заданы непригодные опции или их аргументы, массив корректен и допускает назначение, а также является индексированным.

printf

printf [-v var] format [arguments]

Записывает форматированные аргументы на стандартный вывод в соответствии с аргументом format. Опция -v задает присваивание значений переменной var вместо печати на стандартном устройстве вывода.

Аргумент format — строка символов, содержащая 3 типа объектов: обычные символы, которые просто копируются на стандартный вывод, escape-последовательности, которые преобразуются и копируются на стандартный вывод, а также спецификации формата, каждая из которых вызывает печать следующего аргумента. В дополнение к стандартным форматам printf(1) команда printf интерпретирует описанные ниже расширения.

%b

Заставляет printf преобразовывать escape-последовательности с \ в соответствующем аргументе, как это делается в echo -e (4.2. Внутренние команды bash).

%q

Заставляет printf выводить соответствующий аргумент в формате, пригодном для ввода.

%(datefmt)T

Заставляет printf выводить строку даты и времени, полученную с использованием datefmt как строки формата для strftime(3). Соответствующий аргумент является целым числом секунд с начала эпохи. Могут применяться два специальных значения аргумента: -1 представляет текущее время, -2 — время вызова оболочки. Если аргумент не задан, предполагается -1. Это расширяет обычное поведение printf.

Аргументы для нестроковых спецификаторов формата трактуются как константы языка C, за исключением того, что допускаются начальные знаки + и -, а в случае перевого символа одинарных или двойных кавычек значением является ASCII-код следующего символа.

Аргумент format при необходимости применяется многократно для всех arguments. Если format требует больше arguments, чем представлено, дополнительные спецификации формата ведет себя как при представлении значения 0 или пустой строки. Команда возвращает статус 0 при успешном выполнении и отличное от нуля значение при отказе.

read

read [-ers] [-a aname] [-d delim] [-i text] [-n nchars]
    [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]

Считывает одну строку со стандартного ввода или из файла с дескриптором fd, указанного в опции -u, выделяет слова, как описано в параграфе 3.5.7. Расщепление слов и назначает первое слово первой переменной name, второе — следующей и т. д. Если слов больше, чем аргументов name, оставшиеся слова и разделители между ними назначаются последнему аргументу name. Если слов меньше, чем аргументов name, соответствующим переменным name присваиваются пустые значения. Для разделения слов используются символы значения переменной IFS как при расщеплении слов (3.5.7. Расщепление слов). Символ \ может служить для отмены специальной трактовки следующего символа или для продолжения строки. Если аргументы name не указаны, считанная строка назначается переменной REPLY. Команда возвращает статус 0, если не было получен символ конца файла, не исчерпано время ожидания (в этом случае возвращается статус больше 128), не было ошибок при назначении переменных (например, попытка записи в переменную, доступную лишь для чтения) и не был указан непригодный дескриптор файла в опции -u.

Опции команды описаны ниже.

-a aname

Слова присваиваются последовательным элементам массива aname, начиная с индекса 0. Все элементы aname удаляются перед назначением. Аргументы name игнорируются.

-d delim

Первый символ delim используется для завершения строки ввода вместо newline. Если delim является пустым, чтение строки будет прерываться NUL-символом.

-e

Для получения строки используется команда Readline (8. Редактирование командной строки) с текущими (или принятыми по умолчанию, если редактирование строк еще не применялось) настройками, и принятого в Readline по умолчанию дополнения имен файлов.

-i text

Если для редактирования строк будет применяться Readline, текст помещается в буфер редактирования.

-n nchars

Команда read возвращает управление после считывания nchars символов, не ожидая ввода всей строки, но учитывает разделитель, если он встретился до считывания nchars символов.

-N nchars

Команда read возвращает управление после считывания в точности nchars символов, не ожидая ввода всей строки, если раньше не был получен символ EOF или истекло время ожидания. Ограничители не трактуются в качестве таковых и не приводят к возврату управления, пока не будет прочитано nchars символов. Результат не расщепляется по символам IFS, это делается для того, чтобы переменной назначался весь набор прочитанных символов (кроме \, как указано ниже).

-p prompt

Выводит приглашение без завершающего символа newline перед попыткой чтения ввода. Приглашение отображается лишь при вводе с терминала.

-r

Эта опция отменяет действие \ в качестве символа экранирования и он считается частью строки. В частности, \newline не используется как продолжение строки.

-s

«Тихий» режим. При вводе символов с терминала они не выводятся на экране.

-t timeout

Задает считывание по времени и возвращает отказ, если строка (или заданное число символов) не была считана за timeout секунд. Аргумент timeout может быть десятичным числом с дробной частью, отделенной точкой. Эта опция действует лишь при чтении с терминала, из канала или иного специального файла, но не действует при чтении из обычного файла. При возникновении тайм-аута считанные данные сохраняются в переменной, заданной параметромname. Если timeout = 0, время команда завершает работу сразу, без попытки считывания данных. Команда возвращает статус 0, если данные доступны в указанном дескрипторе файла. При тайм-ауте возвращается значение больше 128.

-u fd

Чтение данных из файла с дескриптором fd.

readarray

readarray [-d delim] [-n count] [-O origin] [-s count]
    [-t] [-u fd] [-C callback] [-c quantum] [array]

Читает строки в переменную индексированного массива со стандартного ввода или из файла с дескриптором fd, если задана опция -u.

Синоним mapfile.

source

source filename

Синоним команды . (4.1. Внутренние элементы Bourne Shell).

type

type [-afptP] [name ...]

Для каждого аргумента name указывает способ интерпретации при использовании как имени команды.

При указании опции -t команда type выводит одно слово, которое задает псевдоним, функцию, внутреннюю команду, файл или ключевое слово, соответствующее аргументу name. Если соответствующего name элемента не найдено, ничего не выводится и возвращается статус отказа.

Опция -p option задает вывод имени дискового файла, который будет выполнен, или ничего, если -t не будет возвращать файл. Опция -P задает поиск в пути для каждого name, даже если -t не будет возвращать файл. Если команда хэширована, опции -p и -P будут выводить хэшированное имя, которое не обязательно соответствует первому файлу, найденному в $PATH.

При указании опции -a команда type возвращает все полные пути к исполняемым файлам name. При отсутствии опции -p будут выведены также псевдонимы и функции.

При указании опции -f команда type не пытается найти функции оболочки.

Статусом возврата будет 0, если найдены все name.

typeset

typeset [-afFgrxilnrtux] [-p] [name[=value] ...]

Команда typeset поддерживается для совместимости в оболочкой Korn и является синонимом внутренней команды declare.

ulimit

ulimit [-HSabcdefiklmnpqrstuvxPT] [limit]

Команда ulimit обеспечивает контроль ресурсов, доступных запускаемому оболочкой процессу, в системах, поддерживающих такой контроль. Опции команды описаны ниже.

-S

Изменение и отчет о мягком ограничении, связанном с ресурсом.

-H

Изменение и отчет о жестком ограничении, связанном с ресурсом.

-a

Вывод всех установленных ограничений.

-b

Максимальный размер буфера сокетов.

-c

Максимальный размер сойздаваемых core-файлов.

-d

Максимальный размер of a process’s data segment.

-e

Максимальный приоритет при планировании (nice).

-f

Максимальный размер файлов, записываемых оболочкой и ее потомками.

-i

Максимальное число ожидающих сигналов.

-k

Максимальное число выделяемых очередей kqueue.

-l

Максимальный размер блокируемой памяти.

-m

Максимальный размер резидентного блока (многие системы не соблюдают это ограничение).

-n

Максимальное число дескрипторов открытых файлов (большинство систем не поддерживает это ограничение).

-p

Размер буфера канала (pipe).

-q

Максимальное число байтов в очереди сообщений POSIX.

-r

Максимальный приоритет при планировании в реальном масштабе времени.

-s

Максимальный размер стека.

-t

Максимальное время процессора в секундах.

-u

Максимальное число процессов для одного пользователя.

-v

Максимальный объем виртуальной памяти, доступной оболочке (на некоторых системах также потомкам).

-x

Максимальное число файловых блокировок.

-P

Максимальное число псевдо-терминалов.

-T

Максимальное число потоков (thread).

Если аргумент limit задан и опция -a не используется, команда устанавливает новое ограничение для указанного ресурса. Специальные значения hard, soft и unlimited указывают текущие значения жестких и мягких ограничений или отсутствие ограничений. Жесткий предел не может быть увеличен пользователем (кроме root), а мягкий предел может быть увеличен до значения не более жесткого предела.

В остальных случаях выводится текущее мягкое ограничение для ресурса, если не задана опция -H. При установке новых ограничений и отсутствии опции -H или -S задается сразу мягкий и жесткий предел. Если опции не заданы, предполагается -f. Значения увеличиваются с шагом 1024 байта, за исключением -t (секунды), -p (блоки по 512 байтов), -P, -T, -b, -k, -n и -u (произвольные), а в режиме POSIX (6.11. Режим POSIX) -c и -f (блоки по 512 байтов).

Команда возвращает отличный от 0 статус, если указана непригодная опция или аргумент, а также при возникновении ошибки в случае установки ограничения.

unalias

unalias [-a] [name ... ]

Удаляет name из списка псевдонимов. Опция -a задает удаление всех псевдонимов.

4.3. Изменение поведения оболочки

4.3.1. Внутренняя команда set

Эта команда весьма сложна и заслуживает отдельного рассмотрения. Команда позволяет менять значения параметров оболочки, устанавливать позиционные параметры, выводить имена и значения переменных среды.

set [--abefhkmnptuvxBCEHPT] [-o option-name] [argument ...]
set [+abefhkmnptuvxBCEHPT] [+o option-name] [argument ...]

При отсутствии опций и аргументов команда set выводит имена и значения всех переменных оболочки и функций с сортировкой в соответствии с текущим языком (locale) в формате, пригодном в качестве ввода для установки или сброса уже установленных переменных. Переменные с доступом только для чтения не могут быть сброшены. В режиме POSIX выводятся лишь переменные оболочки.

Опции командной строки служат для установки или сброса атрибутов оболочки. Описание опций приведено ниже.

-a

Каждой переменной или функции, которая создается или изменяется, назначается атрибут экспорта и она помечается для экспорта в среду последующих команд.

-b

Задает незамедлительный возврат статуса прерванных фоновых заданий вместо вывода перед следующим основным приглашением.

-e

Немедленно завершить работу, если конвейер (3.2.2. Конвейеры), который может включать одну простую команду (3.2.1. Простые команды), список (3.2.3. Списки ) или составную команду (3.2.4. Составные команды), возвращает отличный от 0 статус. Работа оболочки не завершается, если вызвавшая отказ команда является частью списка, следующего сразу после ключевого слова while или until, частью проверочного выражения в операторе if, частью любой команды, выполняемой в списке && или || (кроме последней в списке), любой командой в конвейере (кроме последней) или статус возврата команды инвертируется оператором !. Если составная команда, не являющаяся субоболочкой, возвращает ненулевой статус в результате отказа при игнорировании опции -e, работа оболочки не завершается. Если установлено прерывание ERR, оно выполняется перед завершением работы оболочки. Эта опция применяется раздельно к среде оболочки и каждой субоболочки (3.7.3. Среда выполнения команды) и может приводить к завершению работы субоболочки до выполнения в ней всех команд.

Если составная команда или shell-функция выполняется в контексте, где опция -e не принимается во внимание, ни одна из команд, выполняемых внутри составной команды или в теле функции, не будет зависеть от опции -e даже при ее наличии и возврате командой отказа. Если составная команда или функция оболочки задает опцию -e в контексте, где эта опция игнорируется, эта установка не будет оказывать влияния, пока не завершится составная команда или команда, включающая функцию.

-f

Отключает преобразование имен файлов (globbing).

-h

Поиск и запоминание (хэш) команд, которые отыскивались для выполнения (включено по умолчанию).

-k

Все параметры в форме операторов присваивания помещаются в среду для команды в дополнение к параметрам перед именем команды.

-m

Управление заданиями включено (7. Управление заданиями). Все процессы работают в отдельной группе. По завершении фонового задания оболочка выводит строку со статусом завершения.

-n

задает чтение команд без их выполнения. Это можно применять для проверки сценариев на предмет ошибок. Опция игнорируется в интерактивной оболочке.

-o option-name

Задает опцию, соответствующую option-name.

allexport

Совпадает с -a.

braceexpand

Совпадает с -B.

emacs

Задает использование интерфейса редактирования командной строки в стиле emacs (8. Редактирование командной строки). Влияет также на интерфейс редактирования для read -e.

errexit

Совпадает с -e.

errtrace

Совпадает с -E.

functrace

Совпадает с -T.

hashall

Совпадает с -h.

histexpand

Совпадает с -H.

history

Включает историю команд, как описано в разделе 9.1. Средства Bash History. Опция включена по умолчанию в интерактивных оболочках.

ignoreeof

Интерактивная оболочка не будет завершать работу при считывании EOF.

Keyword

Совпадает с -k.

monitor

Совпадает с -m.

noclobber

Совпадает с -C.

noexec

Совпадает с -n.

noglob

Совпадает с -f.

nolog

А настоящее время игнорируется.

notify

Совпадает с -b.

nounset

Совпадает с -u.

onecmd

Совпадает с -t.

physical

Совпадает с -P.

pipefail

При установке возвращаемым значением конвейера будет значение статуса последней (самой правой) команды или 0, если все команды выполнены успешно. Опция по умолчанию отключена.

posix

Меняет поведение Bash, если принятые по умолчанию установки отличаются от стандарта POSIX, в соответствии с этим стандартом (6.11. Режим POSIX). Опция предназначена для обеспечения поведения Bash в строгом соответствии с надмножеством этого стандарта.

privileged

Совпадает с -p.

verbose

Совпадает с -v.

vi

Задает использование стиля vi при редактировании строк. Влияет также на интерфейс редактирования команды read -e.

xtrace

Совпадает с -x.

-p

Включает привилегированный режим, в котором файлы $BASH_ENV и $ENV не обрабатываются, функции оболочки не наследуются из среды, а переменные SHELLOPTS, BASHOPTS, CDPATH и GLOBIGNORE, при наличии их в окружении, игнорируются. Если оболочка запущена с действующим идентификатором пользователя (группы), отличным от идентификатора реального пользователя (группы), а опция -p не задана, эти действия выполняются и для действующего идентификатора пользователя устанавливается идентификатор реального пользователя. Если опция -p указана при запуске, идентификатор пользователя не меняется. Выключение этой опции ведет к установке действующих идентификаторов пользователя и группы в соответствии с реальными.

-t

Выход после считывания и выполнения одной команды.

-u

Задает трактовку неустановленных переменных и параметров (кроме @ и *) как ошибку при преобразовании параметров. Сообщение об ошибке отображается на стандартном устройстве вывода и работа неинтерактивной оболочки завершается.

-v

Выводит входные строки оболочки по мере их чтения.

-x

Выводит трассировку простых команд для команд, команд case и select, а также арифметики для команд и аргументов или связанных списков слов после преобразования, но до выполнения. Значение переменной PS4 преобразуется и выводится результат перед командой и ее преобразованными аргументами.

-B

Оболочка выполняет раскрытие скобок (3.5.1. Раскрытие скобок). Опция включена по умолчанию.

-C

Предотвращает переписывание имеющихся файлов при перенаправлении вывода с использованием >, >&, и <>.

-E

При установке опции все прерывания (trap) в ERR наследуются функциями оболочки, подстановками команд и командами, выполняемыми в среде субоболочки. Обычно прерывания ERR в таких случаях не наследуется.

-H

Включает стиль ! в подстановке истории (9.3. Преобразование истории). Опция включена по умолчанию для интерактивных оболочек.

-P

Установленная опция отключает преобразование символьных ссылок при выполнении команд, меняющих текущий каталог (таких как cd). Вместо этого будет использоваться реальный каталог. По умолчанию Bash следует логической цепочке каталогов при выполнении команд, меняющих текущий каталог.

Например, если /usr/sys является символьной ссылкой на /usr/local/sys

$ cd /usr/sys; echo $PWD
/usr/sys
$ cd ..; pwd
/usr

При установке опции -P

$ cd /usr/sys; echo $PWD
/usr/local/sys
$ cd ..; pwd
/usr/local

-T

При установленной опции любые прерывания в DEBUG и RETURN наследуются функциями оболочки, подстановками команд и командами, выполняемыми в среде субоболочки. Обычно прерывания DEBUG и RETURN в таких случаях не наследуется.

Если за этой опцией не следует аргумент, позиционные параметры не устанавливаются. В противном случае позиционные параметры устанавливаются в соответствии со значениями аргументов, даже если некоторые из них начинаются с символа -.

Указывает завершение опции и назначение оставшихся аргументов позиционным параметрам. Опции -x и -v выключаются. Если аргументов нет, позиционные параметры не меняются.

Использование символа + вместо — отключает соответствующую опцию. Опции могут также применяться при вызове оболочки. Текущий набор опций хранится в переменной $-.

Оставшиеся N аргментов являются позиционными параметрами $1, $2, . . . $N. Для специального параметра # устанавливается значение N.

Команда всегда возвращает статус 0, если не задана недействительная опция.

4.3.2. Внутренняя команда shopt

Эта команда позволяет изменить необязательное поведение оболочки.

shopt [-pqsu] [-o] [optname ...]

Команда меняет значения, контролирующие поведение дополнительной оболочки. Это могут быть перечисленные ниже параметры или (при использовании опции -o) параметры, доступные с опцией -o внутренней команде set (4.3.1. Внутренняя команда set). При вызове без опций или с опцией -p команда выводит список всех доступных для установки опций с индикацией уже установленных. Если при этом задан параметр optname, вывод ограничивается указанными опциями. Опция -p обеспечивает вывод в форме, которая может использоваться в качестве входных данных.

-s

Включает (set) каждую опцию из optname.

-u

Выключает (unset) каждую опцию из optname.

-q

Подавляет обычный вывод. Статус возврата указывает были опция optname установлена или сброшена. При наличии нескольких аргументов optname с опцией -q статус возврата будет 0, если установлены все optname.

-o

Ограничивает значения optname заданными для опции -o внутренней команды set (4.3.1. Внутренняя команда set).

Если опция -s или -u используется без аргумента optname, команда shopt показывает лишь установленные или сброшенные опции, соответственно.

Если явно не указано иное, опции shopt по умолчанию отключены.

Статусом возврата при просмотре опций является 0, если все опции из optname включены и отличное от 0 значение в противном случае. При установке или сбросе опций возвращается статус 0, если optname указывает действительную опцию оболочки.

assoc_expand_once

При установке опции оболочка подавляет многократное вычисление индексов ассоциативных массивов в процессе вычисления арифметических выражений при выполнении внутренних команд, которые могут назначать переменные и разыменовывать массивы.

autocd

При установке этой опции команда, являющаяся именем каталога, будет восприниматься как аргумент команды cd. Опция может применяться лишь в интерактивных оболочках.

cdable_vars

При установленной опции аргумент внутренней команды cd, не являющийся каталогом, считается именем переменной, значение которой задает каталог для перехода.

cdspell

При включенной опции незначительные ошибки при указании каталога в команде cd будут исправляться. Проверяется перестановка символов, пропуски и избыточные символы. Если исправление найдено, выводится корректный путь и команда выполняется. Опция применяется только в интерактивных оболочках.

checkhash

При установке опции Bash проверяет наличие команды, найденной в хэш-таблице, перед попыткой ее выполнения. Если хэшированной команды больше не существует, выполняется обычный поиск в заданных путях.

checkjobs

При установке опции Bash выводит состояния всех остановленных и работающих заданий, имеющихся в интерактивной оболочке. Если какие-то задания выполняются, это откладывает выход до второй попытки выхода без промежуточной команды (7. Управление заданиями). Оболочка всегда откладывает завершение при наличии остановленных заданий.

checkwinsize

При установленной опции Bash проверяет размер терминального окна после каждой внешней команды и при необходимости обновляет значения LINES и COLUMNS. По умолчанию опция включена.

cmdhist

При установленной опции Bash пытается сохранить все строки многострочной команды в одной записи истории. Это позволяет впоследствии редактировать такие команды. Опция включена по умолчанию, но работает лишь при включенной истории команд (9.1. Средства Bash History).

compat31

При установленной опции Bash меняет свое поведение в соответствии с версией 3.1 применительно к аргументам в кавычках для оператора условных команд =~ и зависимого от языка сравнения строк при использовании команды [[ с операторами < и >. Версии до bash-4.1 используют сортировку ASCII и strcmp(3), а bash-4.1 и более поздние версии используют сортировку установленного языка и strcoll(3).

compat32

При установленной опции Bash меняет свое поведение в соответствии с версией 3.2 применительно к сравнению строк на основе языка (locale) в операторах < и > условных команд [[ и прерыванию списка команд. В Bash версий 3.2 и меньше выполнялся переход к следующей команде в списке после завершения команды прерыванием.

compat40

При установленной опции Bash меняет свое поведение в соответствии с версией 4.0 применительно к сравнению строк на основе языка (locale) в операторах < и > условных команд [[ и прерыванию списка команд. В Bash версий 4.0 и выше список прерывается как при получении прерывания оболочкой, а в более ранних продолжается со следующей командой из списка.

compat41

При установленной опции Bash в режиме POSIX трактует одинарные кавычки при преобразовании параметров в двойных кавычках как специальный символ. Одинарные кавычки должны быть парными, а символы между ними считаются заключенными в кавычки. Это поведение относится к режиму POSIX до версии 4.1. По умолчанию Bash ведет себя как в предшествующих версиях.

compat42

При установленной опции Bash не обрабатывает строку замены в преобразовании слова подстановки шаблона с использованием удаления кавычек.

compat43

При установленной опции Bash не выводит предупреждения при попытке использовать в качестве аргумента заключенное в кавычки назначение составного массива, считает ошибки преобразования слов не критическими (по умолчанию они являются критическими и ведут к завершению работы оболочки) и не сбрасывает состояние цикла при выполнении функции оболочки (это позволяет прервать или продолжить цикл в функции оболочки для воздействия на цикл в контексте вызывающего элемента).

compat44

При установленной опции Bash сохраняет позиционные параметры в переменных BASH_ARGV и BASH_ARGC до их использования, независимо от включения режима расширенной отладки.

complete_fullquote

При установленной опции Bash заключает в кавычки все мета-символы в именах файлов и каталогов при дополнении. Если опция не задана, Bash удаляет мета-символы, такие как $, из числа помещаемых в кавычки в дополненных именах файлов, когда эти мета-символы появляются в ссылках на переменные оболочки в словах, которые нужно дополнить. Это означает, что символ $ в именах переменных, которые преобразуются в каталоги, не будет заключаться в кавычки, однако он не будет заключаться в кавычки и в именах файлов. Это действует лишь в тех случаях, когда bash использует символ \ для дополненных имен файлов. Опция установлена по умолчанию, что соответствует принятому по умолчанию поведению Bash до версии 4.2.

direxpand

При установленной опции Bash заменяет имена каталогов результатами преобразования слов при дополнении имен файлов. Это меняет содержимое буфера редактирования readline. Если опция не задана, Bash пытается сохранить пользовательский ввод.

dirspell

При установленной опции Bash пытается корректировать имена каталогов при дополнении, если заданного пользователем каталога не существует.

dotglob

При установленной опции Bash включает имена, начинающиеся с ., в результат преобразования имен. Имена . и .. должны совпадать явно даже при установке dotglob.

execfail

При установленной опции неинтерактивная оболочка не будет завершаться при невозможности выполнить файл, указанный как аргумент внутренней команды exec. Интерактивная оболочка не завершается при отказах exec.

expand_aliases

При установленной опции псевдонимы преобразуются в соответствии с разделом 6.6. Псевдонимы. Эта опция по умолчанию включена для интерактивной оболочки.

extdebug

Если опция установлена при вызове оболочки, организуется выполнение профиля отладчика до запуска оболочки как при указании опции —debugger. При установке опции после вызова оболочки, включается поведение, предназначенное для отладчиков, как описано ниже.

  1. Опция -F внутренней команды declare (4.2. Внутренние команды bash) выводит имя файла с исходным кодом и номер строки, соответствующие каждому имени функции, заданному в качестве аргумента.
  2. Если команда, запускаемая прерыванием DEBUG, возвращает отличный от 0 статус, следующая команда пропускается.
  3. Если команда, запускаемая прерыванием DEBUG, возвращает 2 и оболочка выполняется в подпрограмме (функция оболочки или сценарий, запущенный с помощью . или source), имитируется вызов return.
  4. Переменные BASH_ARGC и BASH_ARGV обновляются, как указано в параграфе 5.2. Переменные Bash.
  5. Трассировка функций включена, подстановка команд, функции оболочки и субоболочки, вызываемые с помощью ( command ), наследуют ловушки DEBUG и RETURN.
  6. Трассировка ошибок включена, подстановка команд, функции оболочки и субоболочки, вызываемые с помощью ( command ), наследуют ловушку ERR.

extglob

Опция включает функции расширенного сопоставления с шаблонами (3.5.8.1. Сопоставление с шаблоном).

extquote

Включает поддержку кавычек $’string’ и $»string» в преобразовании выражений ${parameter}. По умолчанию включена.

failglob

При включенной опции отсутствие совпадений с шаблоном при преобразовании имен файлов ведет к ошибке.

force_fignore

При включенной опции суффиксы, заданные переменной оболочки FIGNORE (5.2. Переменные Bash), ведут к игнорированию слов при дополнении, даже когда игнорируемое слово является единственным вариантом дополнения. Опция включена по умолчанию.

globasciiranges

При включенной опции выражения диапазонов, используемые в выражениях сопоставления с шаблоном, содержащих скобки (3.5.8.1. Сопоставление с шаблоном), ведут себя как при сравнении с традиционной языковой установкой C. Т. е. порядок символов текущей языковой установки не принимается во внимание и символы верхнего и нижнего регистра ASCII будут сравниваться вместе.

globstar

При включенной опции шаблон ** в контексте преобразования имен файлов будет соответствовать всем файлам, а также каталогам и подкаталогам. Если за шаблоном следует символ /, соответствовать будут лишь (под)каталоги.

gnu_errfmt

При включенной опции сообщения оболочки об ошибках выводятся в стандартном формает сообщений gnu.

histappend

При включенной опции список истории добавляется в конец файла, указанного значением переменной HISTFILE, вместо переписывания файла при выхое из оболочки.

histreedit

При включенной опции и использовании Readline пользователь может повторно редактировать неудачную подстановку истории.

histverify

При включенной опции и использовании Readline результат подстановки истории не передается сразу же анализатору оболочки, а полученная в результате строка загружается в буфер редактирования Readline, что обеспечивает возможность дополнительного изменения.

hostcomplete

При включенной опции и использовании Readline интерпретатор Bash будет пытаться дополнять имя хоста, когда при дополняется слово с символом @ (8.4.6. Завершение строк из Readline). Опция включена по умолчанию.

huponexit

При включенной опции Bash будет передавать сигнал SIGHUP всем заданиям при выходе из интерактивной (login) оболочки (3.7.6. Сигналы).

inherit_errexit

При включенной опции подстановка команд наследует опцию errexit вместо ее сброса в среде субоболочки. Опция включена в режиме POSIX.

interactive_comments

Позволяет интерактивной оболочке игнорировать содержимое строки, начиная с символа # и до конца строки (включена по умолчанию).

lastpipe

При включенной опции и выклюенном управлении заданиями оболочка запускает последнюю команду конвейера, которая не была выполнена в фоновом режиме в среде текущей оболочки.

lithist

Если опция включенна вместе с опцией cmdhist, многострочные команды сохраняются в списке истории с символами новой строки вместо ;.

localvar_inherit

При включенной опции локальные переменные наследуют значения и атрибуты одноименных переменных из предыдущей области действия до присвоения новых значений. Атрибут nameref не наследуется.

localvar_unset

При включенной опции вызов unset для локальных переменных в областях действия предыдущих функций маркирует их так, что последующий поиск видит их неустановленными, пока не произойдет возврат из функции. Это идентично поведению при отмене локальных переменных в области действия текущей функции.

login_shell

Оболочка устанавливает эту опцию при запуске в режиме входа в систему — login (6.1. Вызов Bash). Изменить значение невозможно.

mailwarn

При включенной опции выводится сообщение «The mail in mailfile has been read», если к файлу, который Bash проверяет на предмет почты, было обращение с момента последней проверки.

no_empty_cmd_completion

При включенной опции и использовании Readline оболочка Bash не пытается искать в PATH возможные дополнения при попытке дополнения пустой строки.

nocaseglob

При включенной опции Bash сопоставляет имена файлов без учета регистра символов для преобразования имен.

nocasematch

При включенной опции Bash сравнивает шаблон без учета регистра символов при сопоставлении во время выполнения условных команд case или [[ conditional, при подстановке шаблонов в преобразовании слов и при фильтрации возможных дополнений как части программируемого дополнения.

nullglob

При включенной опции Bash позволяет преобразование шаблонов имен, которым ничего не соответствует, в пустую строку, а не в себя.

progcomp

При включенной опции разрешены средства программируемого дополнения (8.6. Программируемое дополнение). Опция включена по умолчанию.

progcomp_alias

При включенной опции и включенном программируемом дополнении Bash трактует имя команды, не имеющее дополнения, как возможный псевдоним и пытается его преобразовать. Если это псевдоним, Bash пытается выполнить программируемое дополнение, используя слово команды из преобразованного псевдонима.

promptvars

При включенной опции строки приглашения подвергаются преобразованию параметров, подстановке команд, арифметическому преобразованию и удалению кавычек, как описано ниже (6.9. Управление формой приглашения). Опция включена по умолчанию.

restricted_shell

Оболочка устанавливает эту опцию при запуске в ограниченном режиме (6.10. Ограниченная оболочка). Изменить значение нельзя и оно не сбрасывается при выполнении стартовых файлов, что позволяет им обнаруживать ограниченный режим оболочки.

shift_verbose

При включенной опции внутренняя команда используется source использует переменную PATH для поиска каталога, содержащего файл, указанный как аргумент. Опция включена по умолчанию.

xpg_echo

При включенной опции внутренняя команда echo по умолчанию преобразует \-экранирование.

Статус возврата при перечислении параметров имеет значение 0, если все все имена опций (optname) включены и отличен от 0 в противном случае. При установке или сбросе опций статус возврата имеет значение 0, если опция действительна для оболочки.

4.4. Специальные внутренние команды

В силу исторических причин стандарт POSIX выделяет некоторые внутренние команды оболочки как специальные. При работе Bash в режиме POSIX специальные команды отличаются от прочих в 3 аспектах:

  1. при поиске специальные команды отыскиваются до функций оболочки;

  2. при возврате специальной внутренней функцией отличного от 0 статуса интерактивная оболочка завершается;

  3. предшествующие команде операторы назначения продолжают действовать в среде оболочки после выполнения команды.

При работе Bash не в режиме POSIX специальные внутренние команды ведут себя как обычные внутренние команды Bash. Режим Bash POSIX описан в разделе 6.11. Режим POSIX.

Специальные команды POSIX включают break, :, ., continue, eval, exec, exit, export, readonly, return, set, shift, trap, unset.

5. Переменные оболочки

В этом разделе описаны параметры оболочки, используемые Bash. Многим переменным Bash автоматически присваивает используемые по умолчанию значения.

5.1. Переменные Bourne Shell

Bash использует некоторые переменные оболочки так же, как это делает Bourne shell. В некоторых случаях Bash поддерживает для переменных заданные по умолчанию значения.

CDPATH

Разделенный двоеточиями список каталогов, используемых в качестве пути поиска внутренней команды cd.

HOME

Домашний каталог текущего пользователя. применяется по умолчанию внутренней командой cd без аргументов. Значение переменной также используется при преобразовании тильды (3.5.2. Преобразование тильды).

IFS

Список символов, служащих разделителями полей. Применяется при расщеплении слов в преобразованиях.

MAIL

Если этот параметр указывает файл или каталог и переменная MAILPATH не задана, Bash информирует пользователя о приходе почты в указанный файл или каталог в формате Maildir.

MAILPATH

Разделенный двоеточиями список файлов, которые оболочка периодически проверяет на предмет новых почтовых сообщений. Каждый элемент списка может задавать сообщение, выводимое при появлении новой почты в файле, которое указывается через ? после имени файла. При использовании в тексте сообщения символы $_ преобразуются в имя текущего файла почты.

OPTARG

Значение последнего аргумента опции, обработанного внутренней командой getopts.

OPTIND

Индекс последнего аргумента опции, обработанного внутренней командой getopts.

PATH

Разделенный двоеточиями список каталогов, которые оболочка просматривает в поиске команд. Пустое (null) имя в переменной PATH указывает текущий каталог и указывается двумя двоеточиями подряд или двоеточием в начале или в конце списка каталогов.

PS1

Строка основного приглашения (по умолчанию (‘\s-\v\$ ’). Полный список escape-последовательностей, преобразуемых перед выводом PS1, приведен в разделе 6.9. Управление формой приглашения.

PS2

Строка вторичного приглашения (по умолчанию ‘> ’), преобразуемого так же, как PS1 перед выводом.

5.2. Переменные Bash

Эти переменные устанавливаются и используются в Bash, но обычно не имеют значения в других оболочках. Некоторые переменные, используемые Bash описаны в разделе 7.3. Переменные управления заданиями.

BASH

Полный путь, использованный для запуска данного экземпляра Bash.

BASHOPTS

Список разделенных двоеточиями включенных опций оболочки. Каждое слово в этом списке является допустимым аргументом опции -s внутренней команды shopt (4.3.2. Внутренняя команда shopt). Опциями в BASHOPTS являются те, для которых shopt показывает значение on. Если эта переменная присутствовала в окружении при запуске Bash, каждая из опций списка будет включена до считывания каких-либо стартовых файлов. Переменная доступна лишь для чтения.

BASHPID

Выводит идентификатор текущего процесса Bash. Это отличается от $$ в некоторых случаях, таких как субоболочки, которым не требуется повторная инициализация Bash. Назначение BASHPID эффекта не дает. Если переменная сброшена, она теряет особые свойства даже в случае последующей переустановки.

BASH_ALIASES

Переменная ассоциативного массива, элементы которого соответствуют внутреннему списку псевдонимов, поддерживаемому внутренней командой alias (4.1. Внутренние элементы Bourne Shell). Добавляемые в массив элементы появляются в списке псевдонимов, однако их сброс (unset) в настоящее время не ведет к удалению из списка. Если переменная сброшена, она теряет особые свойства даже в случае последующей переустановки.

BASH_ARGC

Переменная массива, значения которого указывают число параметров в каждом кадре текущего стека вызовов при выполнении bash. На вершине стека находится число параметров текущей подпрограммы (shell-функции или сценария, выполняемого с . или source). Когда подпрограмма выполняется, число параметров передается в BASH_ARGC. Оболочка устанавливает BASH_ARGC только в режиме расширенной отладки (4.3.2. Внутренняя команда shopt). Установка extdebug после запуска оболочки для выполнения сценария или ссылка на эту переменную, когда extdebug не установлена, может давать несогласованный результат.

BASH_ARGV

Переменная массива, содержащая все параметры в текущем стеке вызовов исполнения bash. На вершине стека находится последний параметр последней подпрограммы, а первый параметр начального вызова находится на дне. При выполнении подпрограммы переданные ей параметры вталкиваются в BASH_ARGV. Оболочка устанавливает BASH_ARGV только в режиме расширенной отладки (4.3.2. Внутренняя команда shopt). Установка extdebug после запуска оболочки для выполнения сценария или ссылка на эту переменную, когда extdebug не установлена, может давать несогласованный результат.

BASH_ARGV0

При ссылке на эту переменную она преобразуется в имя оболочки или сценария оболочки (идентично $0, как описано в 3.4.2. Специальные параметры). Назначение BASH_ARGV0 вызывает присвоение этого же значения переменной $0. При сбросе BASH_ARGV0 переменная теряет свои особые свойства даже в случае переустановки.

BASH_CMDS

Переменная ассоциативного массива, элементы которого соответствуют внутренней хэш-таблице команд, поддерживаемой внутренней командой hash (4.1. Внутренние элементы Bourne Shell). Добавляемые в массив элементы появляются в хэш-таблице, однако сброс (unset) элемента массива не ведет к удалению имени команды из хэш-таблицы. При сбросе BASH_CMDS переменная теряет свои особые свойства даже в случае переустановки.

BASH_COMMAND

Команда, выполняемая или готовящаяся к выполнению в данный момент, если только оболочка не выполняет команду в результате прерывания (trap), когда это будет команда, выполнявшаяся в момент прерывания.

BASH_COMPAT

Значение, используемое для установки уровня совместимости оболочки (4.3.2. Внутренняя команда shopt). Значение может быть десятичным (например, 4.2) или целым (например, 42) числом, соответствующим желаемому уровню совместимости. Если переменная BASH_COMPAT сброшена или установлена пустая строка, для уровня совместимости устанавливается текущая версия. Если в BASH_COMPAT установлено значение, не являющееся одним из действительных уровней совместимости, оболочка выводит сообщение об ошибке и устанавливает для уровня совместимости текущую версию. Действительные уровни совместимости соответствуют опциям совместимости, воспринимаемым внутренней командой shopt (например, compat42 означает, что значения 4.2 и 42 являются действительными). Текущая версия также является пригодным значением.

BASH_ENV

Если эта переменная установдена при вызове Bash для выполнения shell-сценария, она преобразуется и используется как имя стартового файла, считываемого до выполнения сценария (6.2. Стартовые файлы Bash).

BASH_EXECUTION_STRING

Аргумент команды для опции вызова -c.

BASH_LINENO

Переменная массива, элементами которого являются номера строк в исходных файлах, где вызывается каждый соответствующий элемент FUNCNAME. ${BASH_LINENO[$i]} — номер строки в исходном файле (${BASH_SOURCE[$i+1]}), где была вызвана ${FUNCNAME[$i]} (или ${BASH_LINENO[$i-1]} при указании с другой shell-функцией). Для получения номера текущей строки используется LINENO.

BASH_LOADABLES_PATH

Список разделенных двоеточиями каталогов, которые оболочка просматривает в поиске динамически загружаемых внутренних команд, указанных командой enable.

BASH_REMATCH

Переменная массива, элементы которого назначены бинарным оператором =~ условной команды [[ (3.2.4.2. Конструкции с условием). Элемент с индексом 0 является частью строки, соответствующей всему регулярному выражению. Элемент с индексом n является частью строки, соответствующей n-му параметризованному субвыражению. Переменная доступна лишь для чтения.

BASH_SOURCE

Переменная массива, элементы которого являются именами исходных файлов, где определена соответствующая shell-функция, названная в массиве FUNCNAME. Функция оболочки ${FUNCNAME[$i]} определена в файле ${BASH_SOURCE[$i]} и вызывается из ${BASH_SOURCE[$i+1]}

BASH_SUBSHELL

Инкрементируется на 1 в каждой субоболочке или среде субоболочки, когда оболочка начинает выполняться в этой среде. Начальное значение равно 0.

BASH_VERSINFO

Доступный лишь для чтения массив (6.7. Массивы), элементы которого содержат данные о версии этого экзеппляра Bash.

BASH_VERSINFO[0]

Старший номер версии (выпуск — release).

BASH_VERSINFO[1]

Младший номер версии (версия).

BASH_VERSINFO[2]

Уровень исправлений (patch level).

BASH_VERSINFO[3]

Версия сборки.

BASH_VERSINFO[4]

Статус выпуска (например, beta1).

BASH_VERSINFO[5]

Значение MACHTYPE.

BASH_VERSION

Номер версии текущего экземпляра Bash.

BASH_XTRACEFD

При установке целого значения, соответствующего действительному дескриптору файла, Bash будет записывать трассировку вывода, генерируемую при включении set -x для этого дескриптора. Это позволяет отделить вывод трассировки от диагностики и сообщений об ошибках. Дескриптор файла закрывается при сбросе или установке нового значения BASH_XTRACEFD. Сброс или назначение пустой строки BASH_XTRACEFD вызывают передачу трассировки на стандартный вывод ощибок. Установка BASH_XTRACEFD = 2 (стандартный вывод ошибок) и последующий сброс приводят к закрытию стандартного вывода ошибок.

CHILD_MAX

Задает число выходных дочерних состояний, запоминаемых оболочкой. Bash не позволяет снижать это значение меньше описанного ниже минимума, заданного POSIX, а также задан максимум (в настоящее время 8192). Минимальное значение зависит от системы.

COLUMNS

Используется командой select для определения ширины терминала при выводе списков выбора. При включенной опции checkwinsize (4.3.2. Внутренняя команда shopt) и в интерактивной оболочке при получении сигнала SIGWINCH устанавливается автоматически.

COMP_CWORD

Индекс в ${COMP_WORDS} слова, содержащего текущую позицию курсора. Переменная доступна лишь в функциях оболочки, вызываемых средствами программируемого дополнения (8.6. Программируемое дополнение).

COMP_LINE

Текущая строка команды, доступная лишь в функциях оболочки и внешних командах, вызываемых средствами программируемого дополнения (8.6. Программируемое дополнение).

COMP_POINT

Индекс текущей позиции курсора относительно начала текущей команды. Если курсор находится в конце команды, переменная имеет значение ${#COMP_LINE}. Переменная доступна лишь в функциях оболочки, вызываемых средствами программируемого дополнения (8.6. Программируемое дополнение).

COMP_TYPE

Целое число, соответствующее типу предпринятого дополнения, которое вызвало функцию завершения, — TAB для обычного завершения, ? Для списка завершений после последовательных нажатий TAB, ! Для списка вариантов при частичном завершении слова, @ для списка завершений если слово не изменено, % для завершения меню. Переменная доступна лишь в функциях оболочки, вызываемых средствами программируемого дополнения (8.6. Программируемое дополнение).

COMP_KEY

Клавиша (финальная клавиша или комбинация), используемая для вызова текущей функции завершения.

COMP_WORDBREAKS

Набор символов, трактуемых библиотекой Readline как разделители слов при дополнении слова. При сбросе переменной она теряет свои особые свойства даже после переустановки.

COMP_WORDS

Переменная массива, состоящая из отдельных слов текущей строки команды. Строка делится на слова, как ее будет расщеплять Readline, с использованием COMP_WORDBREAKS, как описано выше. Переменная доступна лишь в функциях оболочки, вызываемых средствами программируемого дополнения (8.6. Программируемое дополнение).

COMPREPLY

Переменная массива, из которой Bash считывает возможные дополнения, созданные shell-функцией, вызванной средством программируемого дополнения (8.6. Программируемое дополнение). Каждый элемент массива содержит одно возможное дополнение.

COPROC

Переменная массива, созданная для хранения дескрипторов файлов для ввода и вывода безымянных процессов (3.2.5. Копроцессы).

DIRSTACK

Переменная массива, содержащая текущий стек каталогов в порядке их отображения внутренней функцией dirs. Назначение элементов массива может служить для изменения включенных в стек каталогов, но для добавления и удаления должны применяться внутренние команды pushd и popd. Назначение этой переменной не меняет текущего каталога. При сбросе переменной она не восстанавливает особые свойства даже после переустановки.

EMACS

Если Bash находит эту переменную в среде при запуске оболочки со значением t, предполагается работа оболочки в буфере Emacs с запретом редактирования строк.

ENV

Похожа на BASH_ENV и применяется при вызове оболочки в режиме POSIX (6.11. Режим POSIX).

EPOCHREALTIME

При каждой ссылке на параметр он преобразуется в число секунд эпохи Unix, выраженное действительным значением с микросекундной точностью (см. описание библиотеки C). Назначение EPOCHREALTIME игнорируется. При сбросе переменной ее свойства не восстанавливаются даже после переустановки.

EPOCHSECONDS

При каждой ссылке на этот параметр он преобразуется в число секунд эпохи Unix (см. описание библиотеки C). Назначение EPOCHSECONDS игнорируется. При сбросе переменной она не восстанавливает особые свойства даже после переустановки.

EUID

Эффективный числовой идентификатор текущего пользователя, доступный лишь для чтения.

EXECIGNORE

Список разделенных двоеточиями шаблонов (3.5.8.1. Сопоставление с шаблоном), определяющий имена файлов при поиске с помощью команды search в PATH. Файлы, имена путей для которых полностью соответствуют одному из шаблонов, не считаются исполняемыми для дополнения и запуска команд через поиск в PATH. Это не влияет на поведение команд [, test и [[. Полные имена в хэш-таблице команд не учитываются EXECIGNORE. Переменную следует использовать для игнорирования файлов общих библиотек, у которых установлен бит выполнения, но они не являются исполняемыми файлами. При сопоставлении учитывается опция оболочки extglob.

FCEDIT

Редактор, используемый по умолчанию внутренней командой fc с опцией -e .

FIGNORE

Разделенный двоеточиями список суффиксов, которые игнорируются при дополнении имен файлов. Имя файла, в котором суффикс совпадает с одним из элементов FIGNORE, исключается из числа совпадений (например, .o:~)

FUNCNAME

Переменная массива, содержащая имена всех shell-функций в стеке исполняемых вызовов. С индексом 0 в массиве размещается имя выполняемой в данный момент функции, нижним элементом (наибольший индекс) является main. Переменная существует только при выполнении shell-функции. Назначение FUNCNAME эффекта не дает. При сбросе переменной она не восстанавливает особые свойства даже после переустановки.

Переменная может использоваться с BASH_LINENO и BASH_SOURCE, каждый элемент FUNCNAME имеет соответствующие элементы в BASH_LINENO и BASH_SOURCE для описания стека вызовов. Например, ${FUNCNAME[$i]} была вызвана из файла ${BASH_SOURCE[$i+1]}, строка ${BASH_LINENO[$i]}. Внутренняя функция caller выводит текущий стек вызовов, используя эту информацию.

FUNCNEST

При установке положительного числа определяет максимальный уровень вложенности функций. В случае превышения заданного уровня текущая команда прерывается.

GLOBIGNORE

Список разделенных двоеточиями шаблонов, определяющий набор имен файлов, игнорируемых при преобразовании имен. Если имя, соответствующее шаблону, соответствует также одному из шаблонов GLOBIGNORE, оно удаляется из списка совпадений. При сопоставлении учитывается опция оболочки extglob.

GROUPS

Переменная массива, содержащая список групп, в которые входит текущий пользователь. Назначение переменной не дает эффекта. При сбросе переменной она не восстанавливает особые свойства даже после переустановки.

histchars

До трех символов, управляющих преобразованием истории, быстрой постановкой и маркировкой (9.3. Преобразование истории). Первым служит символ преобразования истории (обычно !), который указывает начало преобразования. Второй символ указывает «быструю подстановку», когда этот символ является первым в строке (обычно ^). Необязательный третий символ (обычно #) указывает, что остальная часть строки является комментарием и пропускается в процессе подстановки. Это не обязательно ведет к трактовке отсавшейся части строки как комментария синтаксическим анализатором оболочки.

HISTCMD

Номер в истории или индекс списка истории для текущей команды. При сбросе переменной она не восстанавливает особые свойства даже после переустановки.

HISTCONTROL

Список разделенных двоеточиями значений, которые управляют способом хранения в списке истории. Если список включает ignorespace, начинающиеся с пробела строки не включаются в список. Значение ignoredups отключает сохранение строк, совпадающих с предшествующими записями. Значение ignoreboth является сокращением для комбинации ignorespace и ignoredups. Значение erasedups задает удаление из списка записи, совпадающей с текущей строкой, перед сохранением этой строки. Все прочие значения игнорируются. Если переменная сброшена (unset) или не содержит действительных значений, все строки, прочитанные анализатором оболочки, сохраняются в списке истории в зависимости от значения HISTIGNORE. Вторая и последующие строки многострочной команды не проверяются и включаются в список истории независимо от значения HISTCONTROL.

HISTFILE

Имя файла для записи списка истории. По умолчанию ~/.bash_history.

HISTFILESIZE

Максимальное число строк в файле истории, при достижении которого наиболее старая запись удаляется. Отсечка файла по этому значению происходит также при выходе из оболочки. Значение 0 задает пустой файл. Нечисловые и отрицательные значения блокируют отсечку. Оболочка устанавливает используемое по умолчанию значение HISTSIZE после считывания стартовых файлов.

HISTIGNORE

Список разделенных двоеточиями, служащих для выбора команд, сохраняемых в списке истории. Каждый шаблон привязывается к началу строки и должен соответствовать всей строке (без добавления неявного символа *). Каждый шаблон соспоставляет со строкой после проверок, заданных HISTCONTROL. В дополнение к обычным шаблонам оболочки символу & соответствует предыдущая строка списка истории. Символ & может экранироваться символом \, который исключается перед сопоставлением. Вторая и последующие строки многострочной команды не проверяются и добавляются в список истории независимо от значения HISTIGNORE. При сопоставлении учитываются настройки опции extglob.

HISTIGNORE включает функции переменной HISTCONTROL. Шаблон & идентичен ignoredups, а [ ]* — ignorespace. Комбинация этих шаблонов, разделенных двоеточием, обеспечивает функциональность ignoreboth.

HISTSIZE

Максимальное число команд, запоминаемых в списке истории. При значении 0 команды не сохраняются в списке. Отрицательные значения задают сохранение каждой команды (нет ограничения). Оболочка устанавливает по умолчанию значение 500 после считывания всех стартовых файлов.

HISTTIMEFORMAT

Непустое значение переменной задает строку формата для strftime при выводе временных меток, связанных с записями, выводимыми по команде history. При заданной переменной метки записываются в файл истории и будут доступны в другой сессии оболочки. При записи меток применяется символ комментария для обозначения меток.

HOSTFILE

Имя файла в формате /etc/hosts, которые оболочке следует считывать при дополнении имен хостов. Список возможных дополнений имен можно менять во время работы оболочки и при следующем дополнении имени Bash добавит содержимое нового файла к имеющемуся списку. Если переменная пуста или не указывает читаемый файл, Bash пытается использовать /etc/hosts. При сброшенной переменной список имен хостов очищается.

HOSTNAME

Имя текущего хоста.

HOSTTYPE

Строка описания машины, на которой работает Bash.

IGNOREEOF

Управляет реакцией оболочки на получение символа EOF как единственного ввода. Установленное значение указывает число последовательных символов EOF, которые могут быть прочитаны в качестве первых символов строк ввода до завершения работы оболочки. Если переменная содержит нечисловое значение или не имеет значения, используется число 10. Если переменной не существует, символ EOF обозначает конец ввода в оболочку. Переменная действует только для интерактивных оболочек.

INPUTRC

Имя файла инициализации Readline, используемого вместо принятого по умолчанию ~/.inputrc.

INSIDE_EMACS

Если Bash находит эту переменную в среде при запуске оболочки, предполагается работа в shell-буфере Emacs с возможностью отключения редактирования строк в зависимости от значения TERM.

LANG

Служит для определения категории языковой установки, не заданной явно переменной, начинающейся с LC_.

LC_ALL

Переопределяет значение LANG и любой другой переменной LC_, задающей категорию языковой установки.

LC_COLLATE

Определяет порядок сортировки, используемой для результатов преобразования имен файлов, а также повередие приобразования диапазонов, классов эквивалентности и порядка сортировки при преобразовании имен файлов и сопоставлении с шаблонами (3.5.8. Преобразование имен файлов).

LC_CTYPE

Задает интерпретацию символов и поведение классов символов при преобразовании имен файлов и сопоставлении с шаблонами (3.5.8. Преобразование имен файлов).

LC_MESSAGES

Задает языковую установку, используемую для трансляции строк в двойных кавычках с префиксом $ (3.1.2.5. Зависимая от языка трансляция).

LC_NUMERIC

Задает категорию языковой установки, применяемую для форматирования чисел.

LC_TIME

Задает категорию языковой установки, применяемую для форматирования даты и времени.

LINENO

Номер строки в выполняемом сценарии или функции оболочки.

LINES

Используется командой select для определения размера строки при выводе списков для выбора. Устанавливается автоматически при включенной опции checkwinsize (4.3.2. Внутренняя команда shopt) или в интерактивной оболочке при получении SIGWINCH.

MACHTYPE

Строка, полностью описывающая тип системы, где выполняется Bash, в формате gnu cpu-company-system.

MAILCHECK

Интервал (в секундах, по умолчанию 60) проверки оболочкой новых сообщений в файлах, заданных переменными MAILPATH и MAIL. Оболочка проверяет почту перед выводом текущего основного приглашения. Если переменная не установлена или не содержит неотрицательного целого числа, проверка почты не происходит.

MAPFILE

Переменная массива, создаваемая для хранения текста, считываемого внутренней командой mapfile, когда имя переменной не задано.

OLDPWD

Предыдущий рабочий каталог, установленный командой cd.

OPTERR

При установке значения 1 Bash будет выводить сообщения об ошибках, создаваемые командой getopts.

OSTYPE

Строка, описывающая операционную систему, в которой работает Bash.

PIPESTATUS

Переменная массива (6.7. Массивы) containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command).

POSIXLY_CORRECT

Если Bash находит эту переменную в среде при запуске оболочки, оболочка переходит в режим POSIX mode (6.11. Режим POSIX) до считывания стартовых файлов, как будто была задана опция —POSIX. Если переменная установлена при работе оболочки, Bash включает режим POSIX как при выполнении команды set -o POSIX. При переходе оболочки в режим POSIX переменная устанавливается, если она еще не задана.

PPID

Идентификатор родительского процесса оболочки, доступный лишь для чтения.

PROMPT_COMMAND

Установленное значение считается командой, выполняемой перед выводом основного приглашения ($PS1).

PROMPT_DIRTRIM

Положительное значение считается числом компонент каталога, сохраняемых при преобразовании \w и \W в приглашениях (6.9. Управление формой приглашения). Удаленные символы заменяются многоточием.

PS0

Значение параметра преобразуется подобно PS1 и выводится интерактивной оболочкой после считывания команды и перед ее выполнением.

PS3

Значение переменной используется в качестве приглашения для команды select (по умолчанию ‘#? ’).

PS4

Значение параметра (по умолчанию ‘+ ’) преобразуется подобно PS1 и преобразованное значение служит приглашением, выводимым перед эхо-выводом команды, когда установлена опция -x (4.3.1. Внутренняя команда set). Первый символ преобразованного значения может повторяться для указания множества уровней косвенности.

PWD

Текущий рабочий каталог, установленный командой cd.

RANDOM

При каждой ссылке на параметр генерируется случайное число от 0 до 32767, которое служит «затравкой» (seed) для генератора случайных чисел.

READLINE_LINE

Содержимое буфера строки Readline для использования с bind -x (4.2. Внутренние команды bash).

READLINE_POINT

Положение точки вставки в буфер строки Readline для использования с bind -x (4.2. Внутренние команды bash).

REPLY

Переменная, использумая по умолчанию внутренней командой read.

SECONDS

Преобразуется в число секунд с момент запуска оболочки. Назначение переменной меняет прошлое значение на указанное и далее будет выводиться сумма заданного значения с числом секунд после установки.

SHELL

Полный путь к оболочке. Если при запуске оболочки переменная не задана, Bash назначает ей полное имя файла текущей пользовательской оболочки login.

SHELLOPTS

Список разделенных двоеточиями включенных опций оболочки. Каждое слово в списке является действительным аргументом опции -o внутренней команды set (4.3.1. Внутренняя команда set). Опции из списка SHELLOPTS выводятся с пометкой on по команде set -o. Если эта переменная была установлена в среде при запуске Bash, каждая из опций списка включается до прочтения стартовых файлов. Переменная доступна лишь для чтения.

SHLVL

Инкрементируется при запуске каждого нового экземпляра Bash для учета глубины вложенности оболочки.

TIMEFORMAT

Значение этого параметра служит строкой формата при выводе времени для конвейеров с зарезервированным словом time. Символ % указывает escape-последовательность, преобразуемую в значение времени или иную информацию, как показано ниже (в квадратных скобках указаны необязательные параметры).

%%

Литерал %.

%[p][l]R

Прошедшее время в секундах.

%[p][l]U

Затраченное процессором время в пользовательском режиме.

%[p][l]S

Затраченное процессором время в емном режиме.

%P

Процент загрузки CPU, рассчитанный как (%U + %S) / %R.

Параметр p указывает размер дробной части. Значение 0 задает вывод только целой части. Можно вывести до 3 знаков после точки и при задании большего числа будет использовано 3. Необязательный параметр l задает «длинный» формат с указанием минут в виде MM mSS.FFs. Значение p управляет дробной частью. Если переменная не задана, Bash использует значение $’\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS’. При пустой переменной данные о времени не выводятся. При выводе времени в конце строки формата добавляется символ новой строки.

TMOUT

Положительное значение трактуется как принятый по умолчанию тайм-аут внутренней команды read (4.2. Внутренние команды bash). Команда select (3.2.4.2. Конструкции с условием) прерывается, если не получен ввод в течение TMOUT секунд при ожидании данных с терминала. В интерактивной оболочке значение считается числом секунд ожидания ввода строки после вывода основного приглашения. Если полная строка не введена за это время, работа Bash прерывается.

TMPDIR

Установленное значение Bash использует как имя каталога для создания верменных файлов оболочки.

UID

Числовой идентификатор текущего реального пользователя, доступный лишь для чтения.

6. Свойства Bash

В этой главе описаны свойства, присущие только Bash.

6.1. Вызов Bash

bash [long-opt] [-ir] [-abefhkmnptuvxdBCDHP] [-o option]
	[-O shopt_option] [argument ...]
bash [long-opt] [-abefhkmnptuvxdBCDHP] [-o option]
	[-O shopt_option] -c string [argument ...]
bash [long-opt] -s [-abefhkmnptuvxdBCDHP] [-o option]
	[-O shopt_option] [argument ...]

Все односимвольные опции внутренней команды set (4.3.1. Внутренняя команда set) могут служить опциями при вызове оболочки. Кроме того, может применяться часть многосимвольных опций, которые должны указываться в командной строке до односимвольных опций.

—debugger

Задает профиль отладчика, запускаемого перед вызовом оболочки, включая режим расширенной отладки (см. описание опции extdebug внутренней команды shopt в параграфе 4.3.2. Внутренняя команда shopt).

—dump-po-strings

Выводит список всех заключенных в двойные кавычки строк с префиксом $ на стандартное устройство вывода в формате gnu gettext PO1. Эквивалент опции -D для формата вывода.

—dump-strings

Эквивалент -D.

—help

Выдает сообщение об использовании на стандартный вывод и завершает работу.

—init-file filename

—rcfile filename

Выполняет команды из filename (вместо ~/.bashrc) для интерактивной оболочки.

—login

Эквивалент -l.

—noediting

Отключает использование библиотеки gnu Readline (8. Редактирование командной строки) для чтения строк команд в интерактивной оболочке.

—noprofile

Отменяет загрузку системного стартового файла /etc/profile и всех персональных файлов инициализации (~/.bash_profile, ~/.bash_login, ~/.profile) при вызове Bash в качестве оболочки для регистрации в системе (login).

—norc

Отменяет чтение файла инициализации ~/.bashrc интерактивной оболочки. Принято по умолчанию для вызова sh.

—POSIX

Меняет поведение Bash в тех аспектах, где принятые по умолчанию операции отличаются от стандарта POSIX. Это сделано для того, чтобы оболочка вела себя как строгое надмножество стандарта (6.11. Режим POSIX).

—restricted

Делает оболочку ограниченной (6.10. Ограниченная оболочка).

—verbose

Эквивалент -v. Выводит прочитанные строки ввода оболочки.

—version

Выводит информацию о версии данного экземпляра Bash на стандартный вывод и завершает работу.

Имеются односимвольные опции, которые могут быть указаны при вызове, но не доступны внутренней команде set.

-c

Считывание и выполнение команд с первого аргумента, не являющегося опцией, и завершение работы. При наличии аргументов после строки команды первый из них назначается переменной $0, а остальные — позиционным параметрам. Назначение $0 задает имя оболочки, используемое в предупреждениях и сообщениях об ошибках.

-i

Переводит оболочку в интерактивный режим (6.3. Интерактивные оболочки).

-l

Заставляет оболочку действовать как при прямом вызове для входа в систему (login). Для интерактивной оболочки это эквивалентно запуску login-оболочки с помощью exec -l bash, в остальных случаях будут выполняться стартовые файлы login-оболочки. Команды exec bash -l и exec bash —login будут менять текущую оболочку на Bash login (см. 6.2. Стартовые файлы Bash).

-r

Делает оболочку ограниченной (6.10. Ограниченная оболочка).

-s

При наличии этой опции или отсутствии аргументов после обработки опций команда считывается со стандартного ввода, что позволяет задать позиционные параметры для интерактивной оболочки или при вводе из конвейера.

-D

Выводит список всей заключенных в двойные кавычки строк с префиксом $ на стандартное устройство вывода. К этим строкам применяются языковые преобразования, когда текущая настройка языка отличается от C и POSIX (3.1.2.5. Зависимая от языка трансляция). Подразумевается опция -n, команды не выполняются.

[-+]O [shopt_option]

Опция shopt является одной из опций оболочки, воспринимаемых командной shopt (4.3.2. Внутренняя команда shopt). При наличии такой опции -O устанавливает значение, +O отменяет. Если опция shopt не задана, выводятся имена и значения опций оболочки, воспринимаемые shopt, на стандартное устройство вывода. При использовании опции вызова +O формат вывода пригоден для использования в качестве ввода.

Символы — указывают завершение опций и отключают дальнейшую их обработку. Все аргументы после — считаются именами файлов и аргументами.

Оболочкой входа (login) является оболочка с первым символом аргумента «-» или вызванная с опцией —login.

Интерактивной является оболочка, запущенная без аргументов, не являющихся опциями (если не задана опция -s), без опции -c и соединенная с терминалами по входу и выходу (как определено isatty(3)), или запущенная с опцией -i (см. 6.3. Интерактивные оболочки).

Если после обработки опций остаются аргументы и не было задано ни одной из опций -c и -s, первый аргумент считается именем файла с командами оболочки (3.8. Сценарии оболочки). При таком вызове Bash параметру $0 назначается имя этого файла, а остальные аргументы передаются в позиционные параметры. Bash читает и выполняет команды из файла, а затем завершает работу. Статусом завершения Bash будет статус выхода последней выполненной в сценарии команды. При отсутствии команд статус выхода будет 0.

6.2. Стартовые файлы Bash

В этом разделе описано использование стартовых файлов в Bash. Если файл имеется, но не может быть прочитан, Bash сообщает об ошибке. Символ ~ преобразуется, как указано в параграфе 3.5.2. Преобразование тильды.

Интерактивные оболочки описаны в параграфе 6.3. Интерактивные оболочки.

Вызов как интерактивной входной оболочки или с опцией —login

При вызове Bash как интерактивной оболочки входа в систему (login) или неинтерактивной оболочки с опцией —login сначала считываются и выполняются команды из файла /etc/profile, если он имеется. После этого отыскиваются в указанном порядке файлы ~/.bash_profile, ~/.bash_login, ~/.profile и первый найденный и читаемый файл считывается, а команды из него выполняются. Для блокировки такого поведения можно задать при запуске опцию —noprofile.

При завершении интерактивной login-оболочки или при выполнении в неинтерактивной login-оболочке внутренней команды exit интерпретатор Bash считывает файл ~/.bash_logout (при наличии) и выполняет команды из него.

Вызов как неинтерактивной и невходной оболочки

При запуске интерактивной оболочки, не являющейся входом в систему (login) Bash считывает файл ~/.bashrc (при его наличии) и выполняет команды из него. Это поведение можно блокировать опцией —norc, а опция —rcfile заставляет Bash читать и выполнять команды из файла ~/.bashrc.

Обычно файл ~/.bash_profile содержит строку

if [ -f ~/.bashrc ]; then . ~/.bashrc; fi

после (или до) связанной со входом в систему инициализации.

Вызов как неинтерактивной оболочки

При запуске Bash в неинтерактивном режиме (например, для выполнения сценария) отыскивается переменная среды BASH_ENV, ее значение преобразуется и результат используется в качестве имени файла для считывания и выполнения. Bash ведет себя как при выполнении команды

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

При этом значение переменной PATH не применяется для поиска файла. Как отмечено выше, при вызове неинтерактивной оболочки с опцией —login интерпретатор Bash пытается читать и выполнять команды из стартовых файлов login-оболочки.

Вызов с именем sh

При вызове Bash с именем sh предпринимается попытка поведения при старте в соответствии с исторической оболочкой sh и стандартом POSIX. При запуске в качестве интерактивной оболочки входа (login) или неинтерактивной оболочки с опцией —login сначала предпринимается попытка выполнить команды из файлов /etc/profile и ~/.profile в указанном порядке. Это можно блокировать опцией —noprofile.

При вызове в качестве интерактивной оболочки с именем sh интерпретатор Bash отыскивает переменную ENV, преобразует ее (при наличии) и использует результат как имя файла для считывания и выполнения. Поскольку при вызове по имени sh оболочка не пытается считывать и выполнять команды из других стартовых файлов, опция —rcfile не будет работать. При вызове неинтерактивной оболочки по имени sh не предпринимается попыток чтения и выполнения других стартовых файлов. При вызове по имени sh интерпретатор Bash переходит в режим POSIX после чтения стартовых файлов.

Вызов в режиме POSIX

При запуске Bash в режиме POSIX (с опцией —POSIX) применяются стартовые файлы в соответствии со стандартом POSIX. В этом режиме интерактивная оболочка преобразует переменную ENV, считывая и выполняя команды из файла, имя которого получено в результате преобразования. Другие стартовые файлы не считываются.

Вызов удаленным демоном shell

Bash пытается определить запуск со стандартным вводом, подключенным к сетевому соединению, как при выполнении демоном удаленной оболочки (обычно rshd) или sshd. Если Bash идентифицирует такой режим, считываются и выполняются команды из файла ~/.bashrc при его наличии и доступности для чтения (это не будет происходить при вызове оболочки по имени sh). Можно блокировать считывание и выполнение команд опцией —norc или указать —rcfile для чтения и выполнения другого файла, но демоны rshd и sshd обычно не используют и не поддерживают эти опции.

Вызов с неэквивалентными эффективными и реальными uid/gid

При запуске Bash с эффективным идентификатором пользователя (группы), не совпадающим с реальным, и без опции -p стартовые файлы не будут использоваться, функции оболочки не наследуются из среды, переменные SHELLOPTS, BASHOPTS, CDPATH и GLOBIGNORE (при их наличии в среде) игнорируются, а эффективный идентификатор пользователя устанавливается в соответствии с реальным. При наличии опции -p эффективный идентификатор пользователя не будет меняться.

6.3. Интерактивные оболочки

6.3.1. Что такое интерактивная оболочка?

Интерактивной считается оболочка, запущенная без аргументов, не являющихся опциями (если не задана опция -s), без опции -c, со вводом и выводом (ошибок), подключенными к терминалу (в соответствии с isatty(3)), или запущенная с опцией -i. Интерактивные оболочки обычно применяют для ввода и вывода терминал пользователя. Можно использовать вызовв с опцией -s для задания позиционных параметров при старте оболочки.

6.3.2. Является ли оболочка интерактивной?

Для определения в сценарии интерактивного режима Bash можно проверять значения специального параметра ‘-’, который в интерактивном режиме содержит i. Например,

case "$-" in
*i*) echo This shell is interactive ;;
*) echo This shell is not interactive ;;
esac

Можно также проверять переменную PS1, которая устанавливается только в интерактивной оболочке. Например,

if [ -z "$PS1" ]; then
	echo This shell is not interactive
else
	echo This shell is interactive
fi

6.3.3. Поведение интерактивной оболочки

При работе оболочки в интерактивном режиме меняется ряд аспектов поведения, описанных ниже.

  1. Стартовые файлы считываются и выполняются как описано в параграфе 6.2. Стартовые файлы Bash.

  2. Управление заданиями по умолчанию включено (7. Управление заданиями) и Bash игнорирует сигналы управления заданиями с клавиатуры (SIGTTIN, SIGTTOU, SIGTSTP).

  3. Bash преобразует и выводит переменную PS1 перед считыванием первой строки команды, а также преобразует и выводит PS2 перед считыванием второй и последующих строк многострочной команды. Bash преобразует и выводит переменную PS0 после чтения команды, но до ее выполнения. Полное описание escape-последовательностей строк приглашения приведено в разделе 6.9. Управление формой приглашения.

  4. Bash использует значение переменной PROMPT_COMMAND как команду, выполняемую перед выводом основного приглашения $PS1 (5.2. Переменные Bash).

  5. Для чтения команд с пользовательского терминала служит Readline (8. Редактирование командной строки).

  6. Bash проверяет значение опции ignoreeof для установки -o вместо незамедлительного выхода при получении символа EOF со стандартного ввода во время чтения команд (4.3.1. Внутренняя команда set).

  7. История команд (9.1. Средства Bash History) и ее преобразование (9.3. Преобразование истории) включены по умолчанию. Bash сохраняет историю команд в файле, указанном $HISTFILE, при завершении работы со включенной историей.

  8. Преобразование псевдонимов (6.6. Псевдонимы) выполняется по умолчанию.

  9. При отсутствии ловушек (trap) Bash игнорирует SIGTERM (3.7.6. Сигналы).

  10. При отсутствии ловушек сигнал SIGINT считывается и обрабатывается (3.7.6. Сигналы), прерывая некоторые внутренние функции оболочки.

  11. Интерактивная оболочка входа (login) передает сигнал SIGHUP всем заданиям при выходе, если включена опция huponexit (3.7.6. Сигналы).

  12. Опция вызова -n игнорируется, а set -n не оказывает влияния (4.3.1. Внутренняя команда set).

  13. Bash периодически проверяет почту в соответствии со значениями переменных MAIL, MAILPATH и MAILCHECK (5.2. Переменные Bash).

  14. Ошибки прерывания, обусловленные ссылками на несвязанные переменные оболочки после влючения set -u не будут приводить к завершению работы (4.3.1. Внутренняя команда set).

  15. Оболочка не будет завершать работу при ошибках преобразования, вызванных отменой или пустым значением var в ${var:?word} (3.5.3. Преобразование параметров оболочки).

  16. Ошибки перенаправления для внутренних команд оболочки не будут приводить к завершению работы.

  17. В режиме POSIX специальная встроенная функция возврата статуса ошибок не будет вызывать прекращение работы (6.11. Режим POSIX).

  18. Отказ exec не будет вызывать прекращение работы (4.1. Внутренние элементы Bourne Shell).

  19. Синтаксические ошибки при анализе не будут вызывать прекращение работы.

  20. Простая корректировка ввода каталогов для внутренней команды cd включена по умолчанию (см. описание опции cdspell в параграфе 4.3.2. Внутренняя команда shopt).

  21. Оболочка проверяет значение переменной TMOUT и будет завершать работу, если команда не считана в течение заданного числа секунд после вывода $PS1 (5.2. Переменные Bash).

6.4. Условные выражения bash

Условные выражения используются составной командой [[, а также внутренними командами test и [, поведение которых зависит от числа аргументов. Выражения могут быть унарными или бинарными и состоят из примитивов. Унарные выражения часто применяются для проверки статуса файлов. Имеются операторы сравнения строк и числовых выражений. Bash применяет особую обработку для некоторых имен файлов в выражениях. Если операционаая система, где работает Bash, поддерживает такие файлы, Bash будет использовать их. В остальных случаях применяется внутренняя эмуляция — если аргумент file имеет форму /dev/fd/N, проверяется файл с дескриптором N, для /dev/stdin, /dev/stdout, /dev/stderr используются дескрипторы 0, 1, 2.

При использовании с [[ операторы < и > работают на основе лексикографической сортировки для установленного языка (locale). Команда test использует сортировку ASCII.

Если явно не указано иное, работающие с файлами примитивы следуют по символьным ссылкам и действуют на целевой файл, а не на саму ссылку.

-a file

True, если file существует.

-b file

True, если file существует и является специальным блочным файлом.

-c file

True, если file существует и является специальным символьным файлом.

-d file

True, если file существует и является каталогом.

-e file

True, если file существует.

-f file

True, если file существует и является обычным файлом.

-g file

True, если file существует и для него установлен бит set-group-id.

-h file

True, если file существует и является символьной ссылкой.

-k file

True, если file существует и для него установлен бит sticky.

-p file

True, если file существует и является именованным каналом (FIFO).

-r file

True, если file существует и доступен для чтения.

-s file

True, если file существует и его размер больше 0.

-t fd

True, если дескриптор fd открыт и указывает на терминал.

-u file

True, если file существует и для него установлен бит set-user-id.

-w file

True, если file существует и доступен для записи.

-x file

True, если file существует и является исполняемым.

-G file

True, если file существует и принадлежит действующей группе.

-L file

True, если file существует и является символьной ссылкой.

-N file

True, если file существует и был изменен с момента последнего чтения.

-O file

True, если file существует и принадлежит действующему пользователю.

-S file

True, если file существует и является сокетом.

file1 -ef file2

True, если file1 и file2 указывают одно устройство и номер inode.

file1 -nt file2

True, если file1 новее (по времени изменения) чем file2 или file1 существует, а file2 — нет.

file1 -ot file2

True, если file1 старше чем file2 или file2 существует, а file1 — нет.

-o optname

True, если включена опция оболочки optname (4.3.1. Внутренняя команда set).

-v varname

True, если переменная оболочки varname установлена (имеет значение).

-R varname

True, если переменная оболочки varname установлена и ссылается на имя.

-z string

True, если размер string равен 0.

-n string
string

True, если размер string не равен 0.

string1 == string2

string1 = string2

True, если строки совпадают. При использовании с командой [[ выполняется сопоставление с шаблоном, как описано в параграфе 3.2.4.2. Конструкции с условием.
Оператор = следует использовать с командой test для соответствия POSIX.

string1 != string2

True, если строки не совпадают.

string1 < string2

True, если string1 лексикографически предшествует строке string2.

string1 > string2

True, если string1 лексикографически следует после строки string2.

arg1 OP arg2

OP может быть -eq, -ne, -lt, -le, -gt или -ge. Операторы возвращают true, если arg1 равен, не равен, меньше, не больше, больше, не меньше arg2. Arg1 и arg2 могут быть положительными или отрицательными целыми числами. При использовании с командой [[ аргументы arg1 и arg2 считаются арифметическими выражениями (6.5. Арифметика командного процессора).

6.5. Арифметика командного процессора

Командный процессор позволяет вычислять арифметические выражения как один из видов преобразования или с использованием композитной команды ((, внутренней команды let или опции -i для внутренней команды declare.

Вычисление производится с целыми числами фиксированного размера без проверки переполнения, хотя деление на 0 отслеживается и помечается как ошибка. Операторы, порядок их применения, ассоциативность и значения совпадают с принятыми в языке C. Ниже приведен список операторов, сгруппированных по уровням предпочтения (порядку применения) в порядке снижения.

id++ id—

Пост-инкрементирование и пост-декрементирование переменной

++id —id

Предварительное инкрементирование и декрементирование переменной

+ —

Унарный + и —

! ~

Логическое и побитовое отрицание

**

Возведение в степень

*/%

Умножение, деление, остаток

+ —

Сложение, вычитание

<< >>

Побитовый сдвиг влево и вправо

<= >= < >

Сравнение

== !=

Равенство и неравенство

&

bitwise AND

^

Побитовая операция XOR (исключительное ИЛИ)

|

Побитовая операция OR (ИЛИ)

&&

Логическая операция AND (И)

||

Логическая операция OR (ИЛИ)

expr ? expr : expr

Условный оператор

= *= /= %= += -= <<= >>= &= ^= |=

Назначение

expr1 , expr2

Запятая

Переменные оболочки могут служить операндами, преобразование параметров выполняется до расчета выражения. В выражении переменные оболочки могут задаваться именами без применения синтаксиса преобразования параметров. Переменная оболочки, имеющая значение null или не установленная, преобразуется в 0 при указании именем без использования синтаксиса преобразования. Значение переменной вычисляется как арифметическое выражения, когда на нее ссылаются или присвоено значение переменной, объявленной с атрибутом integer, с помощью declare -i. Значение null трактуется как 0. Переменная не обязана иметь атрибут integer для использования в выражении.

Константы, начинающиеся с 0, считаются восьмеричными значениями, а 0x или 0X в начале указывает шестнадцатеричное значение. В остальных случаях числа имеют форму [base#]n, где необязательный элемент base является десятичным числом от 2 до 64, представляющим основание, а n указывает значение по этому основанию. Если base# отсутствует, предполагается основание 10. При указании n цифры больше 9 указываются заглавными буквами, буквами нижнего регистра, а также символами @ и _ в указанном порядке. Если основание не превышает 36, в качестве цифр 10 — 35 могут применяться буквы в верхнем и нижнем регистре без его учета.

Операторы при расчете применяются в соответствии с порядком действий, субвыражения в скобках вычисляются заранее и могут менять порядок действий.

6.6. Псевдонимы

Псевдонимы позволяют заменить строку словом для использования в качестве первого слова простой команды. Оболочка поддерживает список псевдонимов, которые можно задавать и отменять с помощью внутренних команд alias и unalias.

Первое слово простой команды, если оно не заключено в кавычки, проверяется на предмет наличия псевдонима. Если псевдоним найден, слово заменяется текстом соответствующей строки. Символы /, $, ‘, = и все мета-символы оболочки, а также символы кавычек, указанные выше, не могут включаться в имена псевдонимов. Текст, заменяющий псевдоним, может содержать любой действительный ввод оболочки, включая мета-символы. Первое слово текста проверяется на предмет наличия псевдонима, но идентичное преобразуемому псевдониму слово второй раз не преобразуется. Это значит, например, что в псевдониме ls для текста «ls -F» Bash не будет пытаться рекурсивно подставлять замену ls. Если последний символ псевдонима является пробельным (blank), следующее слово команды также проверяется на предмет наличия и преобразования псевдонима.

Псевдонимы создаются и просматриваются с помощью команды alias, а удаляются командой unalias.

Механизма использования аргументов в тексте подстановки (как в csh) не поддерживается. Если аргументы нужны, следует использовать не псевдоним, а функцию оболочки (3.3. Функции оболочки).

Псевдонимы не преобразуются в неинтерактивной оболочке, если для нее не установлена опция expand_aliases с помощью внутренней команды shopt (4.3.2. Внутренняя команда shopt).

Правила определения и использования псевдонимов несколько запутаны. Bash всегда читает по меньшей мере одну полную строку ввода и все строки, образующие композитную команду, перед выполнением любой команды в строке или составной команды. Псевдонимы преобразуются при считывании команды, а не ее выполнении. Поэтому определение псевдонима в одной строке с командой не будет работать до ввода следующей строки. Команда, следующая за определением псевдонима, в той же строке не сможет использовать псевдоним. Это также может вызывать проблемы при выполнении функций. Псевдонимы преобразуются при считывании определения функции, а не при ее выполнении, поскольку определение функции само является командой. В результате псевдонимы, определенные в функции, недоступны, пока функция не будет выполнена. В целях безопасности следует помещать определения псевдонимов в отдельную строку и не применять псевдонимы в составных командах.

Практически во всех случаях функции оболочки предпочтительней, нежели псевдонимы.

6.7. Массивы

Bash поддерживает одномерные массивы с индексом и ассоциативные массивы. Внутренний оператор declare служит для явного объявления массива. Размер массивов не ограничен и не задается требований к непрерывности индексов. Индексированные массивы указываются с использованием целочисленных индексов, которые могут быть арифметическими выражениями (6.5. Арифметика командного процессора). Отсчет индексов начинается с 0. Если явно не указано иное, индексы массива должны быть неотрицательными целыми числами. Ассоциативные массивы используют произвольные строки ключей.

Индексированный масив создается автоматически, если любая переменная задана с использованием синтаксиса

name[subscript]=value

Элемент subscript считается арифметическим выражением, которое должно преобразовываться в число. Для явного объявления массива служит форма, приведенная ниже.

declare -a name

Приемлем также синтаксис

declare -a name[subscript]

где значение subscript игнорируется.

Ассоциативные массивы создаются в форме

declare -A name.

Атрибуты могут быть заданы для переменной массива с использованием внутренней команды declare или readonly. Каждый атрибут применяется ко всем элементам массива.

Значения массивов указываются с помощью компонентного оператора присваивания в форме

name=(value1 value2 ... )

где каждый аргумент value имеет форму [subscript]=string. Индексированные массивы не требуют ничего, кроме строки. При задании значений таких массивов с указанием необязательного индекса значение присваивается с этим индексом, иначе назначается элемент, следующий за последним с увеличением индекса на 1. Индексы начинаются с 0.

При задании значения в ассоциативном массиве требуется указание индекса. Такой синтаксис принимается также внутренней командой declare. Отдельные элементы массива могут задаваться в форме name[subscript]=value.

Если при назначении в индексированный массив имя задано отрицательным индексом, значение интерпретируется относительно максимального индекса (вычитается), т. е. отрицательные индексы отсчитываются от конца массива и -1 указывает последний элемент.

Любой элемент массива можно указать в форме ${name[subscript]}. Скобки нужны для предотвращения конфликтов с операторами преобразования имен файлов. Если индекс subscript имеет значение @ или *, слово преобразуется во все элементы массива name. Эти индексы различаются лишь для слов в двойных кавычках. В этом случае ${name[*]} преобразуется в одно слово с разделением элементов массива первым символом переменной IFS, а ${name[@]} преобразуется в отдельные слова для каждого элемента массива. Если в массиве нет элементов, ${name[@]} преобразуется в пустое значение. Если происходит преобразование двойных кавычек внутри слова, первый преобразованный символ объединяется с началом исходного слова, а последний — с концом этого слова. Это аналогично преобразованию специальных символов @ и *. ${#name[subscript]} преобразуется в размер ${name[subscript]}. Если subscript имеет значение @ или *, результатом преобразования будет число элементов массива. Если индекс массива преобразуется в число меньше 0, он интерпретируется относительно максимального индекса в массиве (т. е. -1 указывает последний элемент массива).

Ссылка на переменную массива без указания индекса эквивалентна ссылке с индексом 0. Любая ссылка на переменную с действительным индексом корректна и bash при необходимости будет создавать массив. Переменная массива считается установленной, если назначено значение индекса. Пустая строка является допустимым значением.

Можно получить ключи (индексы) массива, а также значения. ${!name[@]} и ${!name[*]} преобразуются в индексы, назначенные в переменной массива name. Трактовка значений в двойных кавычках похожа на преобразование специальных символов @ и * внутри двойных кавычек.

Для уничтожения массивов служит внутренняя команда unset. Для уничтожения элемента в индексном массив