<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=OWeRQ</id>
		<title>Linuxformat - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=OWeRQ"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:Contributions/OWeRQ"/>
		<updated>2026-05-15T10:29:43Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Python</id>
		<title>LXF97:Python</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Python"/>
				<updated>2008-03-19T23:45:51Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Python: Управляемся ==&lt;br /&gt;
''Надоело мириться с дезориентирующими тэгами и нелепыми именами файлов?&lt;br /&gt;
Укодируйте их до полного исчезновения с помощью '''Ника Вейча''' и магии Python!''&lt;br /&gt;
&lt;br /&gt;
Правда-правда, я ужасно люблю порядок: все вещи на своем&lt;br /&gt;
месте, все под рукой, и вы можете мигом определить, что&lt;br /&gt;
есть, чего нет; и всякое такое. Впрочем, люди, видевшие фото&lt;br /&gt;
моего рабочего стола или совавшие нос в мой бельевой ящик, пожалуй, оторопеют от явной лживости этого высказывания. Но, пожалуйста, внимательно прочтите его еще раз: я сказал, что люблю порядок, а&lt;br /&gt;
вовсе не что я люблю его наводить. Моя мечта – чтобы во всех комнатах моего дома стояло по хитроумной мусорной корзине, связанной с&lt;br /&gt;
этаким интеллектуальным сканером объектов: каждый раз, покончив с&lt;br /&gt;
использованием/чтением/изучением чего-либо, я бы просто скидывал&lt;br /&gt;
эту штуку в мусоросборник, а она волшебным образом перемещалась&lt;br /&gt;
куда-нибудь и дожидалась там своего часа. Увы, похоже, подобные&lt;br /&gt;
технологии не скоро до меня доберутся. Сейчас самая моя больная&lt;br /&gt;
тема – музыкальная коллекция. Я, конечно, целиком за свободу творчества, но то, что все мои сборники CD имеют разные шрифты, цвета и&lt;br /&gt;
формат хранения данных, действует на нервы. Впрочем, виртуальный&lt;br /&gt;
мир вашей Linux-системы способен удовлетворить любые ваши прихоти, включая страсть к педантизму и скрупулезной правильности!&lt;br /&gt;
&lt;br /&gt;
Python – превосходный язык для выполнения стандартных операций с файлами. Он позволяет обрабатывать имена файлов и использовать функциональные возможности ОС с помощью ряда встроенных&lt;br /&gt;
функций, всегда готов при необходимости вызвать внешние утилиты,&lt;br /&gt;
имеет огромную коллекцию готовых модулей, способных выполнить&lt;br /&gt;
практически любые действия, и к тому же очень прост для понимания.&lt;br /&gt;
Он хорош не только для прототипирования, но и для создания самостоятельных приложений – или как минимум удобных небольших сценариев для выполнения частных задач.&lt;br /&gt;
&lt;br /&gt;
Итак, наша цель – разобраться с коллекцией музыкальных файлов&lt;br /&gt;
на моем Linux-компьютере (отдельным счастливчикам это тоже при-&lt;br /&gt;
годится). У меня есть один большой каталог под названием ‘Music’,&lt;br /&gt;
который, как полагается, делится на подкаталоги по исполнителям,&lt;br /&gt;
альбомам и отдельным трекам. Однако, несмотря на столь стройную&lt;br /&gt;
систему, у меня имеются проблемы непосредственно с музыкальными&lt;br /&gt;
файлами. Вот примерный список вещей, мешающих мне насладиться&lt;br /&gt;
моей коллекцией:&lt;br /&gt;
&lt;br /&gt;
* Некоторые файлы имеют слишком длинные имена, затрудняющие работу с ними. Такое бывает с покупной музыкой: в название&lt;br /&gt;
включается сразу и альбом, и имя исполнителя, и номер дорожки, и&lt;br /&gt;
т.д. Я же хочу единый для всех названий вид, желательно без дурацких символов.&lt;br /&gt;
* Некоторые файлы содержат тэги формата ID3v1, а не ID3v2. Беда&lt;br /&gt;
небольшая, но по возможности я бы предпочел наслаждаться и преимуществами ID3v2.&lt;br /&gt;
* Некоторые файлы снабжены тэгами формата ID3v2, но не ID3v1.&lt;br /&gt;
Из-за этого они не читаются на стареньком MP3-плейере в моем&lt;br /&gt;
автомобиле.&lt;br /&gt;
* Некоторые из файлов неработоспособны. Неплохо было бы&lt;br /&gt;
иметь список дефектных файлов, чтобы удалить их из коллекции&lt;br /&gt;
или заменить.&lt;br /&gt;
* Некоторые из файлов сохранены в нетипичных форматах, которые распознаются не всеми доступными устройствами. Список этих&lt;br /&gt;
файлов тоже пригодился бы.&lt;br /&gt;
&lt;br /&gt;
Но как же достичь хотя бы части этих целей? Хоть я и не вполне уверен, что все перечисленные мной желания легко выполнимы, но попытаться стоит; по крайней мере, я знаю, с чего начать. В Python’е имеется&lt;br /&gt;
модуль под названием os. Он реализует все стандартные функции ОС,&lt;br /&gt;
в частности, связанные с файловой системой. Python – кросс-платформенная разработка, поэтому, несмотря на различия реализации в разных операционных системах, задача у данного модуля одна: предоставление функциональности уровня ОС с единым интерфейсом. Одной из&lt;br /&gt;
самых полезных из известных мне функций, представленных в данном&lt;br /&gt;
модуле, является walk(). Если задать ей имя родительского каталога,&lt;br /&gt;
эта функция вернет список кортежей (см. врезку слева), включающих&lt;br /&gt;
имя родительского каталога, список подкаталогов (если они есть) и&lt;br /&gt;
список имен файлов. Таким образом, чтобы получить список всех файлов, включая полный путь к ним, нужно выполнить функцию walk() с&lt;br /&gt;
заданным нами каталогом и по шагам обработать результат.&lt;br /&gt;
&lt;br /&gt;
==== Что такое «кортеж»? (врезка) ====&lt;br /&gt;
Кортеж – это объект, состоящий из нескольких значений. Он часто&lt;br /&gt;
используется в Python. Хороший пример использования кортежа –&lt;br /&gt;
цвет. Вместо того, чтобы хранить три значения в трех разных переменных для красного, зеленого и синего цветов, вы назначаете одну переменную, содержащую три значения! Кортеж в Python записывается&lt;br /&gt;
примерно так: (123,255,17). Вы можете получить доступ к любому элементу кортежа с помощью индексов – значений в квадратных скобках,&lt;br /&gt;
указываемых после имени переменной. Например, команда print&lt;br /&gt;
Colour[1] вернет значение «255» в случае с предыдущим примером –&lt;br /&gt;
только не забывайте, что значения индексов начинаются с 0!&lt;br /&gt;
&lt;br /&gt;
=== Python и музон ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 import os&lt;br /&gt;
 topdir=”/usr/share/music/”&lt;br /&gt;
 walklist = os.walk(topdir)&lt;br /&gt;
 for dirs in walklist:&lt;br /&gt;
   if(dirs[2]):&lt;br /&gt;
     for file in dirs[2]:&lt;br /&gt;
     // Выполнить какое-нибудь действие&lt;br /&gt;
     print os.path.join(dirs[0],file)&lt;br /&gt;
   else:&lt;br /&gt;
     for entry in dirs[1]:&lt;br /&gt;
       print dirs[1]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В данном примере мы сначала импортируем модуль os, затем&lt;br /&gt;
назначаем каталог, который хотим использовать. В результате выполнения функции walk() генерируется объект в переменной walklist. С&lt;br /&gt;
помощью конструктора for мы можем затем использовать имеющийся в Python способ пошагового перемещения по списку для работы с&lt;br /&gt;
каждым элементом. Чтобы вам стало понятнее, данные переменной&lt;br /&gt;
walklist должны выглядеть примерно так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 (‘/usr/share/music/Blonde_Redhead’, [‘1980 Forward’, ‘23’], [])&lt;br /&gt;
 (‘/usr/share/music/Blonde_RedHead/1980 Forward’, [], [‘18-Magic&lt;br /&gt;
 Mountain.mp3’])&lt;br /&gt;
 (‘/usr/share/music/Blonde_Redhead/23’, [], [‘10-My Impure Hair.&lt;br /&gt;
 mp3’,’1-23.mp3’, ‘7-Publisher.mp3’, ‘3-The Dress.mp3’, ‘6-Silently.&lt;br /&gt;
 mp3’])&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь пошагово проверим каждую строку. Если элемент строки&lt;br /&gt;
является файлом (одним или несколькими, в виде списка), мы хотим&lt;br /&gt;
выполнить с ним определенные действия. Оператор if проверяет, имеется ли что-нибудь в каталоге, а если имеется, мы продолжим перемещаться по списку файлов тем же способом. Что делать с файлами,&lt;br /&gt;
пока не совсем ясно, поэтому просто распечатаем список в стандартный вывод. Здесь мы воспользуемся другой полезной функцией модуля os – os.path.join(). Она соединяет вместе все компоненты пути к&lt;br /&gt;
файлу и записывает их в виде, соответствующем текущему модулю os,&lt;br /&gt;
что, несомненно, гораздо лучше, чем простое соединение вхождений с&lt;br /&gt;
помощью слэша /, как это обычно делается в Linux!&lt;br /&gt;
&lt;br /&gt;
Я также добавил здесь еще одну ветку else – на случай, если мы&lt;br /&gt;
захотим что-то проделать и с каталогами (может, переименовать?). Но&lt;br /&gt;
для начала просто выполните данный скрипт, чтобы проверить, работает ли он в вашей системе. Главное – не забудьте указать именно&lt;br /&gt;
тот каталог, где действительно имеются MP3-файлы.&lt;br /&gt;
&lt;br /&gt;
==== Проверка типов файлов ====&lt;br /&gt;
Ну вот, теперь самое время добавить новые функции в данный скрипт.&lt;br /&gt;
Но прежде чем приняться за файл, я предлагаю убедиться, что он действительно музыкальный! Думаю, мы можем смело предположить,&lt;br /&gt;
что все MP3-файлы имеют расширение mp3. Таким образом, в нашем&lt;br /&gt;
цикле мы могли бы проверить это и пометить файлы, не соответствующие данному критерию. Вероятно, мы могли бы просто включить&lt;br /&gt;
такую проверку внутри цикла, уже осуществляемого оператором if, но&lt;br /&gt;
так как проверка может потребоваться не одна, гораздо разумнее присвоить расширение переменной и затем проверять ее. Для извлечения&lt;br /&gt;
расширения воспользуемся простым и мощным способом обработки&lt;br /&gt;
строк и переменных других типов в Python (подробнее – см. врезку&lt;br /&gt;
справа вверху). Добыв расширение файла, можно проверить, не совпадает ли оно с другими форматами музыкальных файлов, вроде ‘.wma’&lt;br /&gt;
и ‘.ogg’ – на случай, если мы захотим поработать и с такими файлами.&lt;br /&gt;
В Python нет оператора case:; придется нагромоздить последовательность операторов if, elif (else if) и else. Символ # в Python указывает, что&lt;br /&gt;
оставшаяся часть строки – комментарий. В итоге наш основной цикл&lt;br /&gt;
примет такой вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 for file in dirs[2]:&lt;br /&gt;
   fullpath = os.path.join(dirs[0],file)&lt;br /&gt;
   extension = file[-4:]&lt;br /&gt;
   if (extension!=’.mp3’):&lt;br /&gt;
     # Это не MP3-файл; проверить на другие расширения?&lt;br /&gt;
     if (extension ==’.wma’):&lt;br /&gt;
       wmalist.append(fullpath)&lt;br /&gt;
     elif (extension ==’.ogg’):&lt;br /&gt;
       ogglist.append(fullpath)&lt;br /&gt;
     else:&lt;br /&gt;
       unknownlist.append(fullpath)&lt;br /&gt;
   else:&lt;br /&gt;
     # Это MP3-файл.&lt;br /&gt;
     # Что-нибудь с ним сделаем.&lt;br /&gt;
     print fullpath&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы также должны объявить три переменных типа «список» в&lt;br /&gt;
основном коде. Возможно, вы захотите добавить код, обрабатывающий файлы, или указать другие варианты расширений. Для полноты&lt;br /&gt;
картины, создадим также список неизвестных типов файлов, найденных в нашем каталоге – чисто информативный; заодно он поможет&lt;br /&gt;
обнаружить то, что мы упустили.&lt;br /&gt;
Теперь займемся MP3-файлами. Спецификация ID3v1 весьма&lt;br /&gt;
незамысловата: в конец файла просто добавляется 128 байт информации о файле, и легко создать синтаксический анализатор для сбора&lt;br /&gt;
этих данных и дальнейшей обработки. Однако ID3v2 придерживается&lt;br /&gt;
других стандартов: информация заносится в начало файла, в виде&lt;br /&gt;
сложной структуры с переменной длиной данных, и, если честно, нам&lt;br /&gt;
пришлось бы изрядно разрастить наш маленький скрипт, чтобы с ней&lt;br /&gt;
справиться. Поэтому мы поступим, как все нормальные программисты:&lt;br /&gt;
схитрим! Существует множество готовых модулей Python, способных&lt;br /&gt;
читать данные MP3-тэгов, вот и возьмем один из них. Рекомендую&lt;br /&gt;
EyeD3 – это признанный фаворит, и в нем есть все, что нам нужно. Вы&lt;br /&gt;
найдете его на DVD, прилагаемом к данному журналу, а на сайте http://&lt;br /&gt;
eyed3.nicfit.net может оказаться более свежая версия.&lt;br /&gt;
Данный модуль творит всяческие чудеса; некоторые из них нам&lt;br /&gt;
даже и трогать незачем. Вы можете почитать о нем подробнее на указанном сайте, но для наших целей достаточно импортировать модуль&lt;br /&gt;
и ознакомиться с функциями, которые нам пригодятся.&lt;br /&gt;
К счастью, модуль eyeD3 не относится к числу сложных. Опасения&lt;br /&gt;
внушает только один объект – eyeD3.Tag, содержащий структуру тэгов&lt;br /&gt;
ID3v1 и ID3v2. Чтобы заполнить его данными из вашего файла, вы&lt;br /&gt;
должны использовать метод объекта link с соответствующим именем&lt;br /&gt;
файла, и выглядит это примерно так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 mytag=eyeD3.Tag()&lt;br /&gt;
 mytag.link(‘/usr/share/music/Blonde_Redhead/23/1-23.mp3’)&lt;br /&gt;
 print mytag.getArtist()&lt;br /&gt;
 print mytag.getAlbum()&lt;br /&gt;
 print mytag.getTrackNum()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Изменив любой из тэгов, просто вызовите метод tag.update(), и&lt;br /&gt;
он запишет новый тэг в файл. Теперь разберемся, как мы поступим с&lt;br /&gt;
нашими файлами. Вместо того, чтобы сразу создавать необходимый&lt;br /&gt;
код, я обычно просто вписываю набор операций, которые нужно сделать, в виде комментариев. Потом можно легко сортировать их, разбивать на более мелкие действия, или, в конце концов, собраться с духом&lt;br /&gt;
и дописать требуемый код! Ниже представлен примерный список операций над нашими файлами, которые могли бы понадобиться:&lt;br /&gt;
&lt;br /&gt;
* Получить расширение файла&lt;br /&gt;
* Он заканчивается на .mp3?&lt;br /&gt;
* Проверить, действительно ли это MP3-файл&lt;br /&gt;
* Прочитать тэги версии 2&lt;br /&gt;
* Прочитать тэги версии 1&lt;br /&gt;
* Если имеется только один тип, копировать в другой тип&lt;br /&gt;
* Если тэгов вообще нет, установить пометку&lt;br /&gt;
* Создать нормальное имя файла из тэгов&lt;br /&gt;
* Предложить/записать новое имя файла&lt;br /&gt;
* Проверить, соответствует ли название альбома имени каталога&lt;br /&gt;
* Если это не MP3-файл, то что? Добавить в соответствующий список&lt;br /&gt;
&lt;br /&gt;
Как сказано выше, впишем это в скрипт в виде комментариев.&lt;br /&gt;
Обычно приступать к делу лучше с первого пункта, чтобы от вас не&lt;br /&gt;
ускользнули логика действий и структура скрипта. Особо хитрые участки – или участки, используемые многократно – можно вынести в&lt;br /&gt;
отдельную функцию. Существуют мнения и за и против этого, и программисты нередко обсуждают, что допустимо выделять в отдельную&lt;br /&gt;
функцию. Теория выглядит примерно так: чем больше вы выносите из&lt;br /&gt;
основного цикла программы, тем более очевидной становится общая&lt;br /&gt;
задача. Но есть и контрдовод: чем больше вы включаете подобных&lt;br /&gt;
обобщений, делая программу максимально простой и понятной, тем&lt;br /&gt;
сложнее потом добраться до работы отдельных функций. Резюме:&lt;br /&gt;
поскольку вы пишете программу исключительно для личного пользования, делайте так, как вам удобнее!&lt;br /&gt;
&lt;br /&gt;
==== Проверка типов файлов – 2 ====&lt;br /&gt;
Теперь пора и делом заняться. Прежде всего, получим расширения&lt;br /&gt;
файлов через слайсинг Python’а, а затем проверим, MP3 это или нет.&lt;br /&gt;
После чего употребим модуль eyeD3, чтобы распознать, действительно&lt;br /&gt;
ли файл соответствует заявленному формату.&lt;br /&gt;
&lt;br /&gt;
После операторов проверки сделаем отступы, чтобы было видно,&lt;br /&gt;
какой блок кода используется при обнаружении соответствия, и воз-&lt;br /&gt;
вратимся к оператору else. В данном случае я слегка поменил порядок&lt;br /&gt;
действий, для начала разобравшись с файлами, не соответствующими&lt;br /&gt;
формату MP3, а затем через оператор else перешел к дальнейшим&lt;br /&gt;
действиям. Почему? Да просто очень легко позабыть про файлы, не&lt;br /&gt;
интересующие вас в данный момент; если вы можете парой строк отде-&lt;br /&gt;
латься от второстепенных данных, лучше сразу с ними и покончить. В&lt;br /&gt;
конечном итоге, быть может, у нас появится специальная функция для&lt;br /&gt;
их обработки.&lt;br /&gt;
&lt;br /&gt;
В представленном ниже коде можно встретить так называемые&lt;br /&gt;
функции «санации» (sanitize). Присутствие их тела в основном коде&lt;br /&gt;
сделало бы его неудобочитаемым, кроме того, иногда их бывает нужно&lt;br /&gt;
вызывать из разных мест. Наконец, так с их реализацией можно разо-&lt;br /&gt;
браться и позже, не затрагивая основной код.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 if (extension !=’.mp3’):&lt;br /&gt;
   # Не файл MP3? Проверить на другие расширения?&lt;br /&gt;
   if (extension == ‘.wma’):&lt;br /&gt;
     wmalist.append(fullpath)&lt;br /&gt;
     # logger.warn(“silly wma file %s”,fullpath)&lt;br /&gt;
   elif (extension == ‘.ogg’):&lt;br /&gt;
     ogglist.append(fullpath)&lt;br /&gt;
   else:&lt;br /&gt;
     unknownlist.append(fullpath)&lt;br /&gt;
 else:&lt;br /&gt;
   # Это вправду MP3-файл?&lt;br /&gt;
   if eyeD3.isMp3File(fullpath):&lt;br /&gt;
     # Прочитать тэг ID3V2&lt;br /&gt;
     tag2 = eyeD3.Tag()&lt;br /&gt;
     tag1 = eyeD3.Tag()&lt;br /&gt;
     a = tag2.link(fullpath,eyeD3.ID3_V2)&lt;br /&gt;
     b = tag1.link(fullpath,eyeD3.ID3_V1)&lt;br /&gt;
     if b and not a:&lt;br /&gt;
       # Имеется только тэг ID3v1&lt;br /&gt;
       print “version1 only”&lt;br /&gt;
       # Создать информацию для tag2 по tag1&lt;br /&gt;
       print fullpath&lt;br /&gt;
       artist = tag1.getArtist()&lt;br /&gt;
       album = tag1.getAlbum()&lt;br /&gt;
       title = tag1.getTitle()&lt;br /&gt;
       print artist,album,title&lt;br /&gt;
       tag1.update(eyeD3.ID3_V2)&lt;br /&gt;
       # check tags are cool&lt;br /&gt;
     elif a and not b:&lt;br /&gt;
       # Имеется только тэг ID3v2&lt;br /&gt;
       print fullpath&lt;br /&gt;
       artist = tag2.getArtist()&lt;br /&gt;
       album = tag2.getAlbum()&lt;br /&gt;
       title = tag2.getTitle()&lt;br /&gt;
       print artist,album,title&lt;br /&gt;
       try:&lt;br /&gt;
         tag2.update(eyeD3.ID3_V1_1)&lt;br /&gt;
       except UnicodeEncodeError:&lt;br /&gt;
         logger.error(“tag invalid for v1.1 in file %s”, fullpath)&lt;br /&gt;
     elif a and b:&lt;br /&gt;
       # Имеются оба тэга&lt;br /&gt;
       logger.info( “both versions fine %s”, fullpath)&lt;br /&gt;
     else:&lt;br /&gt;
       # Тэгов нет вообще&lt;br /&gt;
       logger.warn(‘this file has no tags! %s’, fullpath)&lt;br /&gt;
       error_flag = True&lt;br /&gt;
       # М.б. удастся вытянуть что-нибудь из имени каталога, где сидит файл!&lt;br /&gt;
     if not error_flag:&lt;br /&gt;
       # Пускай имя файла будет&lt;br /&gt;
       # number-name.mp3&lt;br /&gt;
       title=tag2.getTitle()&lt;br /&gt;
       title = title.replace(‘ ‘,’_’)&lt;br /&gt;
       n=tag2.getTrackNum()&lt;br /&gt;
       # Номер (number) у нас есть&lt;br /&gt;
       ns = str(n[0])&lt;br /&gt;
       if len(ns)==1:&lt;br /&gt;
           ns= ‘0’+ns&lt;br /&gt;
     ns=ns+’-’+title+’.mp3’&lt;br /&gt;
     # Уберем нехорошие символы&lt;br /&gt;
     ns=sanitize(ns)&lt;br /&gt;
     if (file!=ns):&lt;br /&gt;
       logger.info(“change filename suggested for %s, to %s!”,filename,ns)&lt;br /&gt;
       os.rename(fullpath, os.path.join(dirs[0],ns)&lt;br /&gt;
   else:&lt;br /&gt;
     # Выдадим предупреждение&lt;br /&gt;
     logger.warn(“ file %s does not seem to be a valid mp3 file”,fullpath)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Полная распечатка этого небольшого скрипта представлена на&lt;br /&gt;
DVD данного номера Linux Format. Но будьте осторожны – скрипт не&lt;br /&gt;
завершен! Нельзя гарантировать, что он не испортит вашу музыкаль-&lt;br /&gt;
ную коллекцию! Особенно следует обратить внимание на проверку&lt;br /&gt;
символов в кодировке Unicode, нередко встречающихся в тэгах ID3v2&lt;br /&gt;
(недопустимых в тэгах первой версии). Также вы, возможно, захотите&lt;br /&gt;
обработать и файлы формата .ogg.&lt;br /&gt;
&lt;br /&gt;
Здесь не доделано также множество проверок на ошибки. В случае&lt;br /&gt;
с тэгами в кодировке Unicode поможет структура try: ... except:; она же&lt;br /&gt;
пригодится и для других случаев (например, выяснении, как поступать&lt;br /&gt;
с музыкальными файлами без прав доступа на запись). Но я надеюсь,&lt;br /&gt;
что рассмотренный в статье пример показал вам, как просто создавать&lt;br /&gt;
полезные скрипты!&lt;br /&gt;
&lt;br /&gt;
==== Будем резать! (врезка) ====&lt;br /&gt;
В Python используются индексы для «нарезания на кусочки» (иногда говорят «слайсинг»,&lt;br /&gt;
от англ. slicing) строк, списков и других типов&lt;br /&gt;
переменных. Пусть у нас имеется запись plop.&lt;br /&gt;
mp3; мы можем запросто извлечь из нее&lt;br /&gt;
любой нужный нам бит. Откройте терминал,&lt;br /&gt;
запустите Python для входа в интерактивный&lt;br /&gt;
режим и попробуйте следующие команды:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; string = ‘plop.mp3’&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string[1]&lt;br /&gt;
 l&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string[:2]&lt;br /&gt;
 pl&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string [-0]&lt;br /&gt;
 p&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string [-1]&lt;br /&gt;
 3&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string [-4:]&lt;br /&gt;
 .mp3&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В последнем операторе print из строки выхватываются четыре последних символа.&lt;br /&gt;
Отрицательные индексы отсчитываются с конца строки, но будьте внимательны: -0 означает&lt;br /&gt;
&lt;br /&gt;
==== Журналирование (врезка) ====&lt;br /&gt;
Небольшие скрипты часто нашпиговывают множеством выводов промежуточных данных на&lt;br /&gt;
печать, чтобы знать, что и как происходит. Это действительно удобно; но иногда хочется превратить строку с оператором печати в комментарий, потом снова её подключить, и т.д. Проще всего&lt;br /&gt;
в таком случае использовать встроенный в Python модуль ведения журнала! Он умеет выводить&lt;br /&gt;
сообщения и в консоль, но способен различать сообщения по значимости, и вы сможете гибко&lt;br /&gt;
регулировать количество выводов на консоль путём правки всего одной строки кода скрипта.&lt;br /&gt;
Добавьте этот модуль к списку импортируемых и впишите следующий код в начало вашего&lt;br /&gt;
скрипта:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 logger = logging.getLogger(“pymusic”)&lt;br /&gt;
 # Создать обработчик консоли&lt;br /&gt;
 handler = logging.StreamHandler()&lt;br /&gt;
 # Создать форматирование и настроить обработчик на его использование&lt;br /&gt;
 formatter = logging.Formatter(“%(asctime)s - %(name)s - %(levelname)s - %(message)s”)&lt;br /&gt;
 handler.setFormatter(formatter)&lt;br /&gt;
 # Добавить обработчик к модулю ведения журнала&lt;br /&gt;
 logger.addHandler(handler)&lt;br /&gt;
 logger.setLevel(logging.WARN)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Часть этих штук смахивает на волшебство, и кое-кто считает модуль ведения журнала непостижимым, но на самом деле все очень просто. Если вы хотите узнать больше, документация&lt;br /&gt;
находится здесь: http://docs.python.org/lib/module-logging.html. Фактически, всё, что необходимо&lt;br /&gt;
знать – это набор стандартных команд для управления выводом сообщений в консоль.&lt;br /&gt;
Например, следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 logger.warn(“ file %s does not seem to be a valid mp3 file”,fullpath)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
выведет в консоль только сообщения, относящиеся к предупреждениям типа WARN или ниже&lt;br /&gt;
(порядок такой: Critical, Error, Warning, Info, Debug). Можно установить и собственные уровни, но&lt;br /&gt;
мы займёмся этим в другой раз...&lt;br /&gt;
то же самое, что и просто 0, а именно – начало&lt;br /&gt;
строки! (Индексы в Python нумеруются с 0.)&lt;br /&gt;
&lt;br /&gt;
==== Форматирование (врезка) ====&lt;br /&gt;
Необходимость чёткого форматирования кода в Python многих ставит&lt;br /&gt;
в тупик, но это вполне простое и разумное требование. В частности,&lt;br /&gt;
отступы строк (посредством пробелов или табуляции) в блоке кода&lt;br /&gt;
должны быть одинаковыми, потому что в Python отступы являются&lt;br /&gt;
значимыми. Взглянув на код, вы не увидите фигурных скобок вокруг&lt;br /&gt;
любых операторов или блоков кода: Python распознаёт окончание блока по окончанию отступа. Это даёт сразу два преимущества: код становится гораздо удобнее для чтения, и не надо заботиться о вложенных&lt;br /&gt;
фигурных скобках!&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Python</id>
		<title>LXF97:Python</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Python"/>
				<updated>2008-03-19T23:40:47Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: == Python: Управляемся == ''Надоело мириться с дезориентирующими тэгами и нелепыми именами файлов? Укодиру...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Python: Управляемся ==&lt;br /&gt;
''Надоело мириться с дезориентирующими тэгами и нелепыми именами файлов?&lt;br /&gt;
Укодируйте их до полного исчезновения с помощью '''Ника Вейча''' и магии Python!''&lt;br /&gt;
&lt;br /&gt;
Правда-правда, я ужасно люблю порядок: все вещи на своем&lt;br /&gt;
месте, все под рукой, и вы можете мигом определить, что&lt;br /&gt;
есть, чего нет; и всякое такое. Впрочем, люди, видевшие фото&lt;br /&gt;
моего рабочего стола или совавшие нос в мой бельевой ящик, пожалуй, оторопеют от явной лживости этого высказывания. Но, пожалуйста, внимательно прочтите его еще раз: я сказал, что люблю порядок, а&lt;br /&gt;
вовсе не что я люблю его наводить. Моя мечта – чтобы во всех комнатах моего дома стояло по хитроумной мусорной корзине, связанной с&lt;br /&gt;
этаким интеллектуальным сканером объектов: каждый раз, покончив с&lt;br /&gt;
использованием/чтением/изучением чего-либо, я бы просто скидывал&lt;br /&gt;
эту штуку в мусоросборник, а она волшебным образом перемещалась&lt;br /&gt;
куда-нибудь и дожидалась там своего часа. Увы, похоже, подобные&lt;br /&gt;
технологии не скоро до меня доберутся. Сейчас самая моя больная&lt;br /&gt;
тема – музыкальная коллекция. Я, конечно, целиком за свободу творчества, но то, что все мои сборники CD имеют разные шрифты, цвета и&lt;br /&gt;
формат хранения данных, действует на нервы. Впрочем, виртуальный&lt;br /&gt;
мир вашей Linux-системы способен удовлетворить любые ваши прихоти, включая страсть к педантизму и скрупулезной правильности!&lt;br /&gt;
&lt;br /&gt;
Python – превосходный язык для выполнения стандартных операций с файлами. Он позволяет обрабатывать имена файлов и использовать функциональные возможности ОС с помощью ряда встроенных&lt;br /&gt;
функций, всегда готов при необходимости вызвать внешние утилиты,&lt;br /&gt;
имеет огромную коллекцию готовых модулей, способных выполнить&lt;br /&gt;
практически любые действия, и к тому же очень прост для понимания.&lt;br /&gt;
Он хорош не только для прототипирования, но и для создания самостоятельных приложений – или как минимум удобных небольших сценариев для выполнения частных задач.&lt;br /&gt;
&lt;br /&gt;
Итак, наша цель – разобраться с коллекцией музыкальных файлов&lt;br /&gt;
на моем Linux-компьютере (отдельным счастливчикам это тоже при-&lt;br /&gt;
годится). У меня есть один большой каталог под названием ‘Music’,&lt;br /&gt;
который, как полагается, делится на подкаталоги по исполнителям,&lt;br /&gt;
альбомам и отдельным трекам. Однако, несмотря на столь стройную&lt;br /&gt;
систему, у меня имеются проблемы непосредственно с музыкальными&lt;br /&gt;
файлами. Вот примерный список вещей, мешающих мне насладиться&lt;br /&gt;
моей коллекцией:&lt;br /&gt;
&lt;br /&gt;
* Некоторые файлы имеют слишком длинные имена, затрудняющие работу с ними. Такое бывает с покупной музыкой: в название&lt;br /&gt;
включается сразу и альбом, и имя исполнителя, и номер дорожки, и&lt;br /&gt;
т.д. Я же хочу единый для всех названий вид, желательно без дурацких символов.&lt;br /&gt;
* Некоторые файлы содержат тэги формата ID3v1, а не ID3v2. Беда&lt;br /&gt;
небольшая, но по возможности я бы предпочел наслаждаться и преимуществами ID3v2.&lt;br /&gt;
* Некоторые файлы снабжены тэгами формата ID3v2, но не ID3v1.&lt;br /&gt;
Из-за этого они не читаются на стареньком MP3-плейере в моем&lt;br /&gt;
автомобиле.&lt;br /&gt;
* Некоторые из файлов неработоспособны. Неплохо было бы&lt;br /&gt;
иметь список дефектных файлов, чтобы удалить их из коллекции&lt;br /&gt;
или заменить.&lt;br /&gt;
* Некоторые из файлов сохранены в нетипичных форматах, которые распознаются не всеми доступными устройствами. Список этих&lt;br /&gt;
файлов тоже пригодился бы.&lt;br /&gt;
&lt;br /&gt;
Но как же достичь хотя бы части этих целей? Хоть я и не вполне уверен, что все перечисленные мной желания легко выполнимы, но попытаться стоит; по крайней мере, я знаю, с чего начать. В Python’е имеется&lt;br /&gt;
модуль под названием os. Он реализует все стандартные функции ОС,&lt;br /&gt;
в частности, связанные с файловой системой. Python – кросс-платформенная разработка, поэтому, несмотря на различия реализации в разных операционных системах, задача у данного модуля одна: предоставление функциональности уровня ОС с единым интерфейсом. Одной из&lt;br /&gt;
самых полезных из известных мне функций, представленных в данном&lt;br /&gt;
модуле, является walk(). Если задать ей имя родительского каталога,&lt;br /&gt;
эта функция вернет список кортежей (см. врезку слева), включающих&lt;br /&gt;
имя родительского каталога, список подкаталогов (если они есть) и&lt;br /&gt;
список имен файлов. Таким образом, чтобы получить список всех файлов, включая полный путь к ним, нужно выполнить функцию walk() с&lt;br /&gt;
заданным нами каталогом и по шагам обработать результат.&lt;br /&gt;
&lt;br /&gt;
==== Что такое «кортеж»? (врезка) ====&lt;br /&gt;
Кортеж – это объект, состоящий из нескольких значений. Он часто&lt;br /&gt;
используется в Python. Хороший пример использования кортежа –&lt;br /&gt;
цвет. Вместо того, чтобы хранить три значения в трех разных переменных для красного, зеленого и синего цветов, вы назначаете одну переменную, содержащую три значения! Кортеж в Python записывается&lt;br /&gt;
примерно так: (123,255,17). Вы можете получить доступ к любому элементу кортежа с помощью индексов – значений в квадратных скобках,&lt;br /&gt;
указываемых после имени переменной. Например, команда print&lt;br /&gt;
Colour[1] вернет значение «255» в случае с предыдущим примером –&lt;br /&gt;
только не забывайте, что значения индексов начинаются с 0!&lt;br /&gt;
&lt;br /&gt;
=== Python и музон ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 import os&lt;br /&gt;
 topdir=”/usr/share/music/”&lt;br /&gt;
 walklist = os.walk(topdir)&lt;br /&gt;
 for dirs in walklist:&lt;br /&gt;
   if(dirs[2]):&lt;br /&gt;
     for file in dirs[2]:&lt;br /&gt;
     // Выполнить какое-нибудь действие&lt;br /&gt;
     print os.path.join(dirs[0],file)&lt;br /&gt;
   else:&lt;br /&gt;
     for entry in dirs[1]:&lt;br /&gt;
       print dirs[1]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В данном примере мы сначала импортируем модуль os, затем&lt;br /&gt;
назначаем каталог, который хотим использовать. В результате выполнения функции walk() генерируется объект в переменной walklist. С&lt;br /&gt;
помощью конструктора for мы можем затем использовать имеющийся в Python способ пошагового перемещения по списку для работы с&lt;br /&gt;
каждым элементом. Чтобы вам стало понятнее, данные переменной&lt;br /&gt;
walklist должны выглядеть примерно так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 (‘/usr/share/music/Blonde_Redhead’, [‘1980 Forward’, ‘23’], [])&lt;br /&gt;
 (‘/usr/share/music/Blonde_RedHead/1980 Forward’, [], [‘18-Magic&lt;br /&gt;
 Mountain.mp3’])&lt;br /&gt;
 (‘/usr/share/music/Blonde_Redhead/23’, [], [‘10-My Impure Hair.&lt;br /&gt;
 mp3’,’1-23.mp3’, ‘7-Publisher.mp3’, ‘3-The Dress.mp3’, ‘6-Silently.&lt;br /&gt;
 mp3’])&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь пошагово проверим каждую строку. Если элемент строки&lt;br /&gt;
является файлом (одним или несколькими, в виде списка), мы хотим&lt;br /&gt;
выполнить с ним определенные действия. Оператор if проверяет, имеется ли что-нибудь в каталоге, а если имеется, мы продолжим перемещаться по списку файлов тем же способом. Что делать с файлами,&lt;br /&gt;
пока не совсем ясно, поэтому просто распечатаем список в стандартный вывод. Здесь мы воспользуемся другой полезной функцией модуля os – os.path.join(). Она соединяет вместе все компоненты пути к&lt;br /&gt;
файлу и записывает их в виде, соответствующем текущему модулю os,&lt;br /&gt;
что, несомненно, гораздо лучше, чем простое соединение вхождений с&lt;br /&gt;
помощью слэша /, как это обычно делается в Linux!&lt;br /&gt;
&lt;br /&gt;
Я также добавил здесь еще одну ветку else – на случай, если мы&lt;br /&gt;
захотим что-то проделать и с каталогами (может, переименовать?). Но&lt;br /&gt;
для начала просто выполните данный скрипт, чтобы проверить, работает ли он в вашей системе. Главное – не забудьте указать именно&lt;br /&gt;
тот каталог, где действительно имеются MP3-файлы.&lt;br /&gt;
&lt;br /&gt;
==== Проверка типов файлов ====&lt;br /&gt;
Ну вот, теперь самое время добавить новые функции в данный скрипт.&lt;br /&gt;
Но прежде чем приняться за файл, я предлагаю убедиться, что он действительно музыкальный! Думаю, мы можем смело предположить,&lt;br /&gt;
что все MP3-файлы имеют расширение mp3. Таким образом, в нашем&lt;br /&gt;
цикле мы могли бы проверить это и пометить файлы, не соответствующие данному критерию. Вероятно, мы могли бы просто включить&lt;br /&gt;
такую проверку внутри цикла, уже осуществляемого оператором if, но&lt;br /&gt;
так как проверка может потребоваться не одна, гораздо разумнее присвоить расширение переменной и затем проверять ее. Для извлечения&lt;br /&gt;
расширения воспользуемся простым и мощным способом обработки&lt;br /&gt;
строк и переменных других типов в Python (подробнее – см. врезку&lt;br /&gt;
справа вверху). Добыв расширение файла, можно проверить, не совпадает ли оно с другими форматами музыкальных файлов, вроде ‘.wma’&lt;br /&gt;
и ‘.ogg’ – на случай, если мы захотим поработать и с такими файлами.&lt;br /&gt;
В Python нет оператора case:; придется нагромоздить последовательность операторов if, elif (else if) и else. Символ # в Python указывает, что&lt;br /&gt;
оставшаяся часть строки – комментарий. В итоге наш основной цикл&lt;br /&gt;
примет такой вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 for file in dirs[2]:&lt;br /&gt;
   fullpath = os.path.join(dirs[0],file)&lt;br /&gt;
   extension = file[-4:]&lt;br /&gt;
   if (extension!=’.mp3’):&lt;br /&gt;
     # Это не MP3-файл; проверить на другие расширения?&lt;br /&gt;
     if (extension ==’.wma’):&lt;br /&gt;
       wmalist.append(fullpath)&lt;br /&gt;
     elif (extension ==’.ogg’):&lt;br /&gt;
       ogglist.append(fullpath)&lt;br /&gt;
     else:&lt;br /&gt;
       unknownlist.append(fullpath)&lt;br /&gt;
   else:&lt;br /&gt;
     # Это MP3-файл.&lt;br /&gt;
     # Что-нибудь с ним сделаем.&lt;br /&gt;
     print fullpath&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы также должны объявить три переменных типа «список» в&lt;br /&gt;
основном коде. Возможно, вы захотите добавить код, обрабатывающий файлы, или указать другие варианты расширений. Для полноты&lt;br /&gt;
картины, создадим также список неизвестных типов файлов, найденных в нашем каталоге – чисто информативный; заодно он поможет&lt;br /&gt;
обнаружить то, что мы упустили.&lt;br /&gt;
Теперь займемся MP3-файлами. Спецификация ID3v1 весьма&lt;br /&gt;
незамысловата: в конец файла просто добавляется 128 байт информации о файле, и легко создать синтаксический анализатор для сбора&lt;br /&gt;
этих данных и дальнейшей обработки. Однако ID3v2 придерживается&lt;br /&gt;
других стандартов: информация заносится в начало файла, в виде&lt;br /&gt;
сложной структуры с переменной длиной данных, и, если честно, нам&lt;br /&gt;
пришлось бы изрядно разрастить наш маленький скрипт, чтобы с ней&lt;br /&gt;
справиться. Поэтому мы поступим, как все нормальные программисты:&lt;br /&gt;
схитрим! Существует множество готовых модулей Python, способных&lt;br /&gt;
читать данные MP3-тэгов, вот и возьмем один из них. Рекомендую&lt;br /&gt;
EyeD3 – это признанный фаворит, и в нем есть все, что нам нужно. Вы&lt;br /&gt;
найдете его на DVD, прилагаемом к данному журналу, а на сайте http://&lt;br /&gt;
eyed3.nicfit.net может оказаться более свежая версия.&lt;br /&gt;
Данный модуль творит всяческие чудеса; некоторые из них нам&lt;br /&gt;
даже и трогать незачем. Вы можете почитать о нем подробнее на указанном сайте, но для наших целей достаточно импортировать модуль&lt;br /&gt;
и ознакомиться с функциями, которые нам пригодятся.&lt;br /&gt;
К счастью, модуль eyeD3 не относится к числу сложных. Опасения&lt;br /&gt;
внушает только один объект – eyeD3.Tag, содержащий структуру тэгов&lt;br /&gt;
ID3v1 и ID3v2. Чтобы заполнить его данными из вашего файла, вы&lt;br /&gt;
должны использовать метод объекта link с соответствующим именем&lt;br /&gt;
файла, и выглядит это примерно так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 mytag=eyeD3.Tag()&lt;br /&gt;
 mytag.link(‘/usr/share/music/Blonde_Redhead/23/1-23.mp3’)&lt;br /&gt;
 print mytag.getArtist()&lt;br /&gt;
 print mytag.getAlbum()&lt;br /&gt;
 print mytag.getTrackNum()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Изменив любой из тэгов, просто вызовите метод tag.update(), и&lt;br /&gt;
он запишет новый тэг в файл. Теперь разберемся, как мы поступим с&lt;br /&gt;
нашими файлами. Вместо того, чтобы сразу создавать необходимый&lt;br /&gt;
код, я обычно просто вписываю набор операций, которые нужно сделать, в виде комментариев. Потом можно легко сортировать их, разбивать на более мелкие действия, или, в конце концов, собраться с духом&lt;br /&gt;
и дописать требуемый код! Ниже представлен примерный список операций над нашими файлами, которые могли бы понадобиться:&lt;br /&gt;
&lt;br /&gt;
* Получить расширение файла&lt;br /&gt;
* Он заканчивается на .mp3?&lt;br /&gt;
* Проверить, действительно ли это MP3-файл&lt;br /&gt;
* Прочитать тэги версии 2&lt;br /&gt;
* Прочитать тэги версии 1&lt;br /&gt;
* Если имеется только один тип, копировать в другой тип&lt;br /&gt;
* Если тэгов вообще нет, установить пометку&lt;br /&gt;
* Создать нормальное имя файла из тэгов&lt;br /&gt;
* Предложить/записать новое имя файла&lt;br /&gt;
* Проверить, соответствует ли название альбома имени каталога&lt;br /&gt;
* Если это не MP3-файл, то что? Добавить в соответствующий список&lt;br /&gt;
&lt;br /&gt;
Как сказано выше, впишем это в скрипт в виде комментариев.&lt;br /&gt;
Обычно приступать к делу лучше с первого пункта, чтобы от вас не&lt;br /&gt;
ускользнули логика действий и структура скрипта. Особо хитрые участки – или участки, используемые многократно – можно вынести в&lt;br /&gt;
отдельную функцию. Существуют мнения и за и против этого, и программисты нередко обсуждают, что допустимо выделять в отдельную&lt;br /&gt;
функцию. Теория выглядит примерно так: чем больше вы выносите из&lt;br /&gt;
основного цикла программы, тем более очевидной становится общая&lt;br /&gt;
задача. Но есть и контрдовод: чем больше вы включаете подобных&lt;br /&gt;
обобщений, делая программу максимально простой и понятной, тем&lt;br /&gt;
сложнее потом добраться до работы отдельных функций. Резюме:&lt;br /&gt;
поскольку вы пишете программу исключительно для личного пользования, делайте так, как вам удобнее!&lt;br /&gt;
&lt;br /&gt;
==== Проверка типов файлов – 2 ====&lt;br /&gt;
Теперь пора и делом заняться. Прежде всего, получим расширения&lt;br /&gt;
файлов через слайсинг Python’а, а затем проверим, MP3 это или нет.&lt;br /&gt;
После чего употребим модуль eyeD3, чтобы распознать, действительно&lt;br /&gt;
ли файл соответствует заявленному формату.&lt;br /&gt;
&lt;br /&gt;
После операторов проверки сделаем отступы, чтобы было видно,&lt;br /&gt;
какой блок кода используется при обнаружении соответствия, и воз-&lt;br /&gt;
вратимся к оператору else. В данном случае я слегка поменил порядок&lt;br /&gt;
действий, для начала разобравшись с файлами, не соответствующими&lt;br /&gt;
формату MP3, а затем через оператор else перешел к дальнейшим&lt;br /&gt;
действиям. Почему? Да просто очень легко позабыть про файлы, не&lt;br /&gt;
интересующие вас в данный момент; если вы можете парой строк отде-&lt;br /&gt;
латься от второстепенных данных, лучше сразу с ними и покончить. В&lt;br /&gt;
конечном итоге, быть может, у нас появится специальная функция для&lt;br /&gt;
их обработки.&lt;br /&gt;
&lt;br /&gt;
В представленном ниже коде можно встретить так называемые&lt;br /&gt;
функции «санации» (sanitize). Присутствие их тела в основном коде&lt;br /&gt;
сделало бы его неудобочитаемым, кроме того, иногда их бывает нужно&lt;br /&gt;
вызывать из разных мест. Наконец, так с их реализацией можно разо-&lt;br /&gt;
браться и позже, не затрагивая основной код.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 if (extension !=’.mp3’):&lt;br /&gt;
   # Не файл MP3? Проверить на другие расширения?&lt;br /&gt;
   if (extension == ‘.wma’):&lt;br /&gt;
     wmalist.append(fullpath)&lt;br /&gt;
     # logger.warn(“silly wma file %s”,fullpath)&lt;br /&gt;
   elif (extension == ‘.ogg’):&lt;br /&gt;
     ogglist.append(fullpath)&lt;br /&gt;
   else:&lt;br /&gt;
     unknownlist.append(fullpath)&lt;br /&gt;
 else:&lt;br /&gt;
   # Это вправду MP3-файл?&lt;br /&gt;
   if eyeD3.isMp3File(fullpath):&lt;br /&gt;
     # Прочитать тэг ID3V2&lt;br /&gt;
     tag2 = eyeD3.Tag()&lt;br /&gt;
     tag1 = eyeD3.Tag()&lt;br /&gt;
     a = tag2.link(fullpath,eyeD3.ID3_V2)&lt;br /&gt;
     b = tag1.link(fullpath,eyeD3.ID3_V1)&lt;br /&gt;
     if b and not a:&lt;br /&gt;
       # Имеется только тэг ID3v1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print “version1 only”&lt;br /&gt;
# Создать информацию для tag2 по tag1&lt;br /&gt;
print fullpath&lt;br /&gt;
artist = tag1.getArtist()&lt;br /&gt;
album = tag1.getAlbum()&lt;br /&gt;
title = tag1.getTitle()&lt;br /&gt;
print artist,album,title&lt;br /&gt;
tag1.update(eyeD3.ID3_V2)&lt;br /&gt;
# check tags are cool&lt;br /&gt;
elif a and not b:&lt;br /&gt;
# Имеется только тэг ID3v2&lt;br /&gt;
print fullpath&lt;br /&gt;
artist = tag2.getArtist()&lt;br /&gt;
album = tag2.getAlbum()&lt;br /&gt;
title = tag2.getTitle()&lt;br /&gt;
print artist,album,title&lt;br /&gt;
try:&lt;br /&gt;
tag2.update(eyeD3.ID3_V1_1)&lt;br /&gt;
except UnicodeEncodeError:&lt;br /&gt;
logger.error(“tag invalid for v1.1 in file %s”,&lt;br /&gt;
fullpath)&lt;br /&gt;
elif a and b:&lt;br /&gt;
# Имеются оба тэга&lt;br /&gt;
logger.info( “both versions fine %s”, fullpath)&lt;br /&gt;
else:&lt;br /&gt;
# Тэгов нет вообще&lt;br /&gt;
logger.warn(‘this file has no tags! %s’, fullpath)&lt;br /&gt;
error_flag = True&lt;br /&gt;
# М.б. удастся вытянуть что-нибудь из имени&lt;br /&gt;
каталога, где сидит файл!&lt;br /&gt;
if not error_flag:&lt;br /&gt;
# Пускай имя файла будет&lt;br /&gt;
# number-name.mp3&lt;br /&gt;
title=tag2.getTitle()&lt;br /&gt;
title = title.replace(‘ ‘,’_’)&lt;br /&gt;
n=tag2.getTrackNum()&lt;br /&gt;
# Номер (number) у нас есть&lt;br /&gt;
ns = str(n[0])&lt;br /&gt;
if len(ns)==1:&lt;br /&gt;
ns= ‘0’+ns&lt;br /&gt;
ns=ns+’-’+title+’.mp3’&lt;br /&gt;
# Уберем нехорошие символы&lt;br /&gt;
ns=sanitize(ns)&lt;br /&gt;
if (file!=ns):&lt;br /&gt;
logger.info(“change filename suggested for %s, to&lt;br /&gt;
%s!”,filename,ns)&lt;br /&gt;
os.rename(fullpath, os.path.join(dirs[0],ns)&lt;br /&gt;
else:&lt;br /&gt;
# Выдадим предупреждение&lt;br /&gt;
logger.warn(“ file %s does not seem to be a valid mp3&lt;br /&gt;
file”,fullpath)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Полная распечатка этого небольшого скрипта представлена на&lt;br /&gt;
DVD данного номера Linux Format. Но будьте осторожны – скрипт не&lt;br /&gt;
завершен! Нельзя гарантировать, что он не испортит вашу музыкаль-&lt;br /&gt;
ную коллекцию! Особенно следует обратить внимание на проверку&lt;br /&gt;
символов в кодировке Unicode, нередко встречающихся в тэгах ID3v2&lt;br /&gt;
(недопустимых в тэгах первой версии). Также вы, возможно, захотите&lt;br /&gt;
обработать и файлы формата .ogg.&lt;br /&gt;
&lt;br /&gt;
Здесь не доделано также множество проверок на ошибки. В случае&lt;br /&gt;
с тэгами в кодировке Unicode поможет структура try: ... except:; она же&lt;br /&gt;
пригодится и для других случаев (например, выяснении, как поступать&lt;br /&gt;
с музыкальными файлами без прав доступа на запись). Но я надеюсь,&lt;br /&gt;
что рассмотренный в статье пример показал вам, как просто создавать&lt;br /&gt;
полезные скрипты!&lt;br /&gt;
&lt;br /&gt;
==== Будем резать! (врезка) ====&lt;br /&gt;
В Python используются индексы для «нарезания на кусочки» (иногда говорят «слайсинг»,&lt;br /&gt;
от англ. slicing) строк, списков и других типов&lt;br /&gt;
переменных. Пусть у нас имеется запись plop.&lt;br /&gt;
mp3; мы можем запросто извлечь из нее&lt;br /&gt;
любой нужный нам бит. Откройте терминал,&lt;br /&gt;
запустите Python для входа в интерактивный&lt;br /&gt;
режим и попробуйте следующие команды:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; string = ‘plop.mp3’&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string[1]&lt;br /&gt;
 l&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string[:2]&lt;br /&gt;
 pl&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string [-0]&lt;br /&gt;
 p&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string [-1]&lt;br /&gt;
 3&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print string [-4:]&lt;br /&gt;
 .mp3&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В последнем операторе print из строки выхватываются четыре последних символа.&lt;br /&gt;
Отрицательные индексы отсчитываются с конца строки, но будьте внимательны: -0 означает&lt;br /&gt;
&lt;br /&gt;
==== Журналирование (врезка) ====&lt;br /&gt;
Небольшие скрипты часто нашпиговывают множеством выводов промежуточных данных на&lt;br /&gt;
печать, чтобы знать, что и как происходит. Это действительно удобно; но иногда хочется превратить строку с оператором печати в комментарий, потом снова её подключить, и т.д. Проще всего&lt;br /&gt;
в таком случае использовать встроенный в Python модуль ведения журнала! Он умеет выводить&lt;br /&gt;
сообщения и в консоль, но способен различать сообщения по значимости, и вы сможете гибко&lt;br /&gt;
регулировать количество выводов на консоль путём правки всего одной строки кода скрипта.&lt;br /&gt;
Добавьте этот модуль к списку импортируемых и впишите следующий код в начало вашего&lt;br /&gt;
скрипта:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 logger = logging.getLogger(“pymusic”)&lt;br /&gt;
 # Создать обработчик консоли&lt;br /&gt;
 handler = logging.StreamHandler()&lt;br /&gt;
 # Создать форматирование и настроить обработчик на его использование&lt;br /&gt;
 formatter = logging.Formatter(“%(asctime)s - %(name)s - %(levelname)s - %(message)s”)&lt;br /&gt;
 handler.setFormatter(formatter)&lt;br /&gt;
 # Добавить обработчик к модулю ведения журнала&lt;br /&gt;
 logger.addHandler(handler)&lt;br /&gt;
 logger.setLevel(logging.WARN)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Часть этих штук смахивает на волшебство, и кое-кто считает модуль ведения журнала непостижимым, но на самом деле все очень просто. Если вы хотите узнать больше, документация&lt;br /&gt;
находится здесь: http://docs.python.org/lib/module-logging.html. Фактически, всё, что необходимо&lt;br /&gt;
знать – это набор стандартных команд для управления выводом сообщений в консоль.&lt;br /&gt;
Например, следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 logger.warn(“ file %s does not seem to be a valid mp3 file”,fullpath)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
выведет в консоль только сообщения, относящиеся к предупреждениям типа WARN или ниже&lt;br /&gt;
(порядок такой: Critical, Error, Warning, Info, Debug). Можно установить и собственные уровни, но&lt;br /&gt;
мы займёмся этим в другой раз...&lt;br /&gt;
то же самое, что и просто 0, а именно – начало&lt;br /&gt;
строки! (Индексы в Python нумеруются с 0.)&lt;br /&gt;
&lt;br /&gt;
==== Форматирование (врезка) ====&lt;br /&gt;
Необходимость чёткого форматирования кода в Python многих ставит&lt;br /&gt;
в тупик, но это вполне простое и разумное требование. В частности,&lt;br /&gt;
отступы строк (посредством пробелов или табуляции) в блоке кода&lt;br /&gt;
должны быть одинаковыми, потому что в Python отступы являются&lt;br /&gt;
значимыми. Взглянув на код, вы не увидите фигурных скобок вокруг&lt;br /&gt;
любых операторов или блоков кода: Python распознаёт окончание блока по окончанию отступа. Это даёт сразу два преимущества: код становится гораздо удобнее для чтения, и не надо заботиться о вложенных&lt;br /&gt;
фигурных скобках!&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8</id>
		<title>LXF97:Первые шаги</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8"/>
				<updated>2008-03-09T13:13:31Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: == Органайзер: == ''Лекарством для недугов наших дней (кроме снижения затрат ископаемого топлива) была б...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Органайзер: ==&lt;br /&gt;
''Лекарством для недугов наших дней (кроме снижения затрат ископаемого топлива)&lt;br /&gt;
была бы лучшая организация. '''Энди Ченнел''' – хозяин своего времени...''&lt;br /&gt;
&lt;br /&gt;
Темп жизни, похоже, не собирается замедляться, и потерянное&lt;br /&gt;
искусство тянуть время становится, хм, все более потерянным.&lt;br /&gt;
Но так не обязательно должно быть. При содействии некоторых&lt;br /&gt;
стандартных программ Linux и правильного планирования все еще&lt;br /&gt;
возможно (по крайней мере, иногда) спихнуть на завтра то, что нужно&lt;br /&gt;
сделать сегодня. На самом деле, без этого не обойтись!&lt;br /&gt;
&lt;br /&gt;
Ключом к продуктивным проволочкам является умение точно&lt;br /&gt;
представить, когда дело должно быть сделано, сколько времени оно&lt;br /&gt;
займет и что важнее. А ключевые типы программ, помогающие этого&lt;br /&gt;
добиться – Календарь и Список задач [To Do]. К счастью, в Linux есть&lt;br /&gt;
прекрасные программы для обоих рабочих столов, Gnome и KDE, в&lt;br /&gt;
лице Evolution и Kontact соответственно, но существуют также и кроссплатформенные пакеты, вроде Sunbird – и его дочернего проекта&lt;br /&gt;
Lightning, интегрированного в Thunderbird – а также целый диапазон&lt;br /&gt;
онлайн-решений, идущих ноздря в ноздрю с настольными соперниками. Ради простоты мы выбрали для данного урока Sunbird/Lightning,&lt;br /&gt;
но приведенные здесь методы подходят к практически любому мыслимому приложению, управляющему расписанием. Sunbird делает все&lt;br /&gt;
необходимое для контроля за нашим временем; мы создадим календари для задач, добавляя и редактируя события, установим напоминания,&lt;br /&gt;
подписавшись на сетевые списки событий, синхронизирумся с нашим&lt;br /&gt;
сетевым календарем и расставим приоритеты работ, настроив список&lt;br /&gt;
задач. Через страницу мы также покажем, как идти в ногу со временем&lt;br /&gt;
вдали от вашего Linux-компьютера при помощи новаторского (и очень&lt;br /&gt;
дешевого) органайзера Graphite.&lt;br /&gt;
&lt;br /&gt;
Кое-что из этого основано на идее Getting Things Done (GTD) Дэвида&lt;br /&gt;
Аллена [David Allen] (www.davidco.com): как наиболее эффективно&lt;br /&gt;
управлять информацией и временем ''[в русском переводе: Д. Аллен&lt;br /&gt;
«Как привести дела в порядок. Искусство продуктивности без стресса»,&lt;br /&gt;
Вильямс, 2007 г.]''. И хотя вся GDT-«индустрия» полнится рекламной&lt;br /&gt;
шумихой и почти непознаваемым корпоративным сленгом, по сути она&lt;br /&gt;
выливается в несколько здравых идей, которые можно реализовать, не&lt;br /&gt;
прибегая к дорогому ПО, книгам или интенсивным семинарам.&lt;br /&gt;
&lt;br /&gt;
=== Получаем программы ===&lt;br /&gt;
Для начала нам необходимы две программы, первая из которых – сама&lt;br /&gt;
Sunbird. На момент написания была доступна версия 0.5, на www.&lt;br /&gt;
mozilla.org/projects/calendar/sunbird/, она имеется на DVD этого месяца. Загрузив файл, дважды щелкните на архиве и распакуйте его куданибудь, где у вас хранятся приложения или двоичные файлы (в нашем&lt;br /&gt;
случае, это /home/downloads/имя_приложения). Затем сам архив можно удалить. Теперь просмотрите каталог Sunbird и найдите элемент с&lt;br /&gt;
именем Sunbird (вообще-то это скрипт) и дважды щелкните на нем.&lt;br /&gt;
Перед вами появится окно с выбором: показать файл, запустить его в&lt;br /&gt;
терминале или просто запустить. Выберите Запустить [Run] и подождите пока приложение запускается. При первом запуске вам предоставится возможность импорта данных календаря из других источников,&lt;br /&gt;
включая Evolution, а затем перед вами предстанет само приложение, по&lt;br /&gt;
умолчанию отображающее вид День. Абсолютно понятный набор других видов, доступный в верхнем меню окна, включает Месяц [Month]&lt;br /&gt;
и Неделю [Week].&lt;br /&gt;
&lt;br /&gt;
Прежде чем двинуться дальше, сделаем на рабочем столе ярлык&lt;br /&gt;
для этого приложения и заставим его запускаться при каждой загрузке&lt;br /&gt;
системы – это удобный способ известить себя о насущных задачах на&lt;br /&gt;
день: календарь должен быть первым, что вы видите.&lt;br /&gt;
&lt;br /&gt;
== Успеть все! ==&lt;br /&gt;
Итак, в Gnome щелкните где-нибудь на рабочем столе и выберите&lt;br /&gt;
Создать кнопку запуска... Добавьте соответствующее Имя, затем щелкните по кнопке Просмотреть... рядом с областью Команда. Перейдите к&lt;br /&gt;
элементу Sunbird, на котором вы щелкали ранее, и выберите его. Теперь&lt;br /&gt;
щелкните по кнопке с текстом Нет значка, выберите Просмотреть и&lt;br /&gt;
найдите каталог /Icon внутри каталога Sunbird. Выберите большую из&lt;br /&gt;
двух иконок и нажмите кнопку OK. Можете также добавить подсказку&lt;br /&gt;
для элемента, поместив текст в строку Примечание. Если иконка получилась слегка великоватой для вашего рабочего стола, то щелкните&lt;br /&gt;
на ней правой кнопкой мыши, выберите Растянуть значок, а затем&lt;br /&gt;
измените его размер, используя один из четырех квадратиков по углам&lt;br /&gt;
иконки. Теперь нажмите Система &amp;gt; Параметры &amp;gt; Сеансы и выберите&lt;br /&gt;
вкладку Запускаемые при старте программы. Нажмите Создать, задайте имя и, уже в последний раз, Просмотреть для перемещения в соответствующее место, чтобы выбрать приложение Sunbird.&lt;br /&gt;
&lt;br /&gt;
Процедура для KDE весьма похожа, за исключением того, что&lt;br /&gt;
после правого щелчка при создании ярлыка на рабочем столе следует&lt;br /&gt;
выбрать Ссылка на приложение... (и далее то же). Чтобы приложение&lt;br /&gt;
запускалось автоматически, откройте ваш каталог в /home, выведите&lt;br /&gt;
скрытые файлы (Вид &amp;gt; Показывать скрытые файлы), перейдите в .kde/&lt;br /&gt;
Autostart и создайте в нем ссылку на приложение Sunbird.&lt;br /&gt;
&lt;br /&gt;
Теперь, когда бы вы ни включили свой ПК, Sunbird в Gnome или KDE&lt;br /&gt;
будет запускаться автоматически, и вы точно будете знать, чему посвятите свой день – конечно, если позаботитесь о вводе этих данных.&lt;br /&gt;
&lt;br /&gt;
Вторая необходимая нам программа также есть на DVD. Она назы-&lt;br /&gt;
вается Provider и позволяет Sunbird (или Lightning) осуществлять двустороннюю синхронизацию с календарем Google. Это значит, что если&lt;br /&gt;
вы обновите календарь Sunbird, то эти изменения попадут и в ваш сетевой календарь, и наоборот; а значит, открываете ли вы свои данные в&lt;br /&gt;
домашнем уюте или в интернет-кафе в Москве, вы всегда будете иметь&lt;br /&gt;
верную информацию под рукой. Последняя версия доступна на https://&lt;br /&gt;
addons.mozilla.org/en-US/sunbird/addon/4631. Однако если вы просто&lt;br /&gt;
щелкнете по кнопке Установить [Install Now], ничего не произойдет,&lt;br /&gt;
потому что расширение разработано для Sunbird, а ссылка работает&lt;br /&gt;
только в Firefox. Вместо этого щелкните на ссылке правой кнопкой&lt;br /&gt;
мыши и сохраните ее на вашем рабочем столе. Теперь откройте Sunbird,&lt;br /&gt;
выполните Инструменты &amp;gt; Дополнения и внизу слева нажмите кнопку&lt;br /&gt;
Установить... Откроется стандартный диалог открытия файла, и вы&lt;br /&gt;
сможете выбрать в нем загруженный XPI-файл. По завершении установки понадобится перезапустить Sunbird.&lt;br /&gt;
&lt;br /&gt;
=== Добавляем содержимое ===&lt;br /&gt;
Итак, мы справились с установкой, но пока данных нет, проку от этого&lt;br /&gt;
мало. Первое, что мы добавим – праздники своей страны: это легко,&lt;br /&gt;
благодаря тому, что web-сайт проекта в разделе Docs &amp;amp; Extras имеет&lt;br /&gt;
набор календарей праздников. Отыщите ссылку на вашу страну и сохраните файл на свой жесткий диск. Вернитесь в Sunbird, выполните Файл&lt;br /&gt;
&amp;gt; Открыть календарь... [File &amp;gt; Open Calendar File...] и переместитесь к&lt;br /&gt;
только что загруженному файлу. Теперь, выбрав вид Месяц, вы должны увидеть, что календарь заселен различными событиями. Можете&lt;br /&gt;
отключить эти события, перейдя на вкладку Календари [Calendars]&lt;br /&gt;
(слева от главного окна) и сняв галочку напротив RussiaHolidays.&lt;br /&gt;
Поскольку Sunbird использует распространенный формат файловкалендарей ICS, можно загружать из сети всевозможные варианты –&lt;br /&gt;
например, игры сборной Манчестера на сезон–2007/2008, и это будет&lt;br /&gt;
отдельный календарь внутри приложения.&lt;br /&gt;
&lt;br /&gt;
Собственные события можно добавить в календарь, дважды щел-&lt;br /&gt;
кнув на дате или во временной секции любого из видов и добавив&lt;br /&gt;
соответствующую информацию. Каждое событие должно иметь дату,&lt;br /&gt;
время и продолжительность (если только это не событие на весь день),&lt;br /&gt;
и выбранный Календарь (то есть частью какого календаря оно является). Среди других опций, пригодится флажок Повторять, который&lt;br /&gt;
также позволяет повторить событие согласно определенному шаблону,&lt;br /&gt;
если, например, надо учесть событие, происходящее в 10:00, но только по будням и только до 22 декабря. После определения события оно&lt;br /&gt;
тут же появится в соответствующем окошке, подкрашенное цветом,&lt;br /&gt;
выбранным для данного календаря. Вы можете изменить детали события, дважды щелкнув на нем; или, если необходимо изменить только&lt;br /&gt;
дату (или время в виде День), можете перенести выбранную секцию в&lt;br /&gt;
другое место.&lt;br /&gt;
&lt;br /&gt;
Для грамотного управления временем необходимо изучить две&lt;br /&gt;
основные концепции: разделение и приоритет. Примером первой является собрание всех российских праздников в один календарь Sunbird.&lt;br /&gt;
Эта информация может быть включена или выключена, то есть при&lt;br /&gt;
желании вы можете полностью ее игнорировать, пока она снова не&lt;br /&gt;
понадобится. Вторая связана с использованием списков задач с приоритетами – Sunbird их тоже поддерживает, но мы воспользуемся сетевым сервисом: он более гибок и прекрасно интегрируется с Sunbird.&lt;br /&gt;
&lt;br /&gt;
Предположим, в вашей жизни есть три главных приоритета: семья,&lt;br /&gt;
работа и дела общественные; последнее – в форме заведования школой. Надо также отслеживать важные даты релиз-цикла Fedora. На все&lt;br /&gt;
это требуется пять календарей, включая уже имеющийся календарь&lt;br /&gt;
российских праздников. Конечно, можно сгрести все эти данные в один&lt;br /&gt;
календарь, но смысл отдельных календарей в том, что вы можете предвидеть свою жизнь, если хотите – то в виде баланса работа/жизнь, на&lt;br /&gt;
месяц вперед и, если необходимо, полностью «отключить» какую-то из&lt;br /&gt;
линий, если требуется сосредоточиться на другом.&lt;br /&gt;
&lt;br /&gt;
Первым делом надо переименовать домашний календарь по умолчанию – Мой календарь: он идеально подойдет как календарь обще-&lt;br /&gt;
ственных мероприятий, поскольку к нему не нужен удаленный доступ.&lt;br /&gt;
Щелкните правой кнопкой мыши на Моем календаре, выберите&lt;br /&gt;
Свойства (или дважды щелкните на нем) и введите новое имя. Здесь&lt;br /&gt;
вы можете также задать новый цвет календаря.&lt;br /&gt;
&lt;br /&gt;
Для создания нового календаря, щелкните правой кнопкой мыши&lt;br /&gt;
в панели календарей (слева в главном окне) и выберите Новый календарь... или просто выполните двойной щелчок где-нибудь на этой&lt;br /&gt;
панели для запуска мастера нового календаря. Вначале вам предложат&lt;br /&gt;
два варианта: календарь на вашем компьютере или в сети? Первый&lt;br /&gt;
просто хранится на вашем компьютере (так же, как переименованный Общественный календарь), а второй для получения информации&lt;br /&gt;
соединяется с календарем в Интернете; однако для доступа или изменения данных сетевого календаря не обязательно подключаться к сети,&lt;br /&gt;
поскольку Sunbird создаст локальное зеркало на то время, пока вы&lt;br /&gt;
отсоединены. Вы можете обновить все позднее, щелкнув правой кнопкой мыши на календаре и выбрав Обновить удаленные календари или&lt;br /&gt;
используя комбинацию клавиш Ctrl+R.&lt;br /&gt;
&lt;br /&gt;
Нас интересует возможность работать с нескольких разных компьютеров, но так, чтобы иметь доступ к данным и в отсутствие сети,&lt;br /&gt;
поэтому создадим сетевой календарь. На самом деле, сперва мы подключим существующий календарь Google, а потом – календарь в формате iCal. Это означает, что нам не придется вновь вводить кучу данных&lt;br /&gt;
или, что более важно, потерять их, если жесткий диск выйдет из строя&lt;br /&gt;
или вор-линуксофил стырит ноутбук LXF: оба аспекта очень важны при&lt;br /&gt;
решении вверить свои данные какому-либо устройству.&lt;br /&gt;
&lt;br /&gt;
Чтобы внести информацию в Sunbird, вначале войдем в службу&lt;br /&gt;
Google Calendar и выберем календарь, к которому собираемся подключиться. Как и в Sunbird (и практически везде), список доступных&lt;br /&gt;
календарей отображается слева. Щелкните на стрелке рядом с именем календаря и выберите Calendar Settings [Настройки календаря].&lt;br /&gt;
Интересующий нас раздел внизу окна справа и озаглавлен Private&lt;br /&gt;
Address [Личный адрес]. Щелкните правой кнопкой мыши на кнопке XML и выберите Copy link location [Скопировать ссылку]. Теперь&lt;br /&gt;
вернитесь в Sunbird и запустите мастер нового календаря. Выберите&lt;br /&gt;
календарь В сети и опцию Google Calendar и, по запросу, вставьте скопированный URL из буфера обмена при помощи Ctrl+V. Нажмите Далее.&lt;br /&gt;
Теперь вам предоставляется возможность задать календарю имя (мы&lt;br /&gt;
выберем Работа), а также цвет отображения. Цвета очень важны с&lt;br /&gt;
точки зрения организации: они сразу же наглядно покажут, чем будет&lt;br /&gt;
занят ваш день, неделя или месяц и насколько вы будете заняты; так&lt;br /&gt;
что выберите цвет, некоторым образом соответствующий целям календаря, и убедитесь, что отличие в оттенках каждого из них бросается в&lt;br /&gt;
глаза. В следующем окне необходимо ввести детали для входа на сервер и выбрать, следует ли сохранить эти детали, чтобы календарь мог&lt;br /&gt;
обновляться автоматически. Когда вы дойдете до конца, данные будут&lt;br /&gt;
загружены, и, как по волшебству, появятся в Sunbird. Теперь сделайте&lt;br /&gt;
то же для остальных ваших личных календарей. Поскольку мы установили для Sunbird модуль расширения Provider, то любые изменения,&lt;br /&gt;
сделанные нами в календарях, связанных с сервисом Google, будут&lt;br /&gt;
отражены в версии, размещенной в сети.&lt;br /&gt;
&lt;br /&gt;
Далее, добавим динамический календарь событий, сосредоточенный на проекте Fedora: вновь запустим мастера нового календаря&lt;br /&gt;
и выберем опцию В сети и формат iCalendar (ICS). Календарь находится на webcal://fedora.redhat.com/participate/schedule/fedora-project.&lt;br /&gt;
ics, так что вставьте этот URL в строку Адрес и нажмите кнопку OK.&lt;br /&gt;
Замечательно то, что если некий пользователь обновит календарь&lt;br /&gt;
Fedora, он будет синхронизирован с вашим, так что у вас всегда будет&lt;br /&gt;
свежая информация. Выше главного окна календаря расположен список встреч: это просто список всего, что вам предстоит, и поскольку&lt;br /&gt;
он отражает содержание календаря ниже, то вы можете включать и&lt;br /&gt;
&lt;br /&gt;
=== Что за дела! ===&lt;br /&gt;
Мы заготовили несколько календарей, предоставляющих долгосрочный обзор того, что нас ждет – и можем сконцентрироваться на&lt;br /&gt;
задачах дня, а для этого необходим Список задач [To Do list]. Sunbird&lt;br /&gt;
имеет окно со списком задач, но бывает удобнее разделить ваше расписание на два вида (долгосрочное и текущее), чтобы, работая над&lt;br /&gt;
непосредственными задачами, вы не отвлекались бы на то, что ждет&lt;br /&gt;
вас за углом.&lt;br /&gt;
&lt;br /&gt;
Для управления нашими списками воспользуемся сервисом под&lt;br /&gt;
названием Remember The Milk [«Не забудь купить молока»] (www.&lt;br /&gt;
rememberthemilk.com). Это сетевое приложение позиционируется как&lt;br /&gt;
«список напоминаний о покупках», но фактически это Управление задачами/Список задач промышленного уровня, и оно прекрасно подойдет&lt;br /&gt;
для наших попыток Привести Дела В Порядок. Мы выбрали Remember&lt;br /&gt;
The Milk (RTM), а не другой сетевой сервис из подобных Списков задач&lt;br /&gt;
по той причине, что RTM позволяет создавать различные списки, способные отражать пометки о событиях в наших календарях. К тому же&lt;br /&gt;
последняя версия программы работает с Google Gears (более подробно – см. http://gears.google.com), а значит, вы сохраните доступ к редактированию ваших списков, будучи вне сети; данные затем будут обновлены при очередном подключении к Интернету.&lt;br /&gt;
&lt;br /&gt;
Прежде всего, надо зарегистрироваться на сервисе и, что не обязательно, загрузить и установить программу Google Gears, запускаемую&lt;br /&gt;
из XPI в Firefox. Зарегистрировавшись и войдя, щелкните на ссылке&lt;br /&gt;
Settings [Настройки], расположенной справа вверху главной страницы&lt;br /&gt;
RTM. Теперь выберите вкладку Lists [Списки]: здесь вы можете опревыключать его части, используя флажки в списке календарей слева.&lt;br /&gt;
делить сколь угодно много своих списков. Щелкните на кнопке Add List&lt;br /&gt;
[Добавить список] и дайте списку имя. При желании быть действительно суперсобранным, можете создать список для каждого дня недели,&lt;br /&gt;
чтобы знать, что вы хотели выполнить в каждый 24-часовой период,&lt;br /&gt;
плюс список Будущее для того, что произойдет чуть позже. Или просто&lt;br /&gt;
следуйте схеме, используемой для вашего календаря. Каким бы способом вы ни решили организовать ваши списки, RTM разместит их в&lt;br /&gt;
алфавитном порядке, а если вы хотите иного упорядочения, придется&lt;br /&gt;
добавить к вашим спискам числа (01, 02, 03 и т.д.). Покончив с этим,&lt;br /&gt;
перейдите на страницу Tasks [Задачи] (ссылка справа вверху) – вы&lt;br /&gt;
увидите, что каждый список имеет свою вкладку; есть еще две стандартные вкладки с именами Inbox [Входящие] и Sent [Отправленные],&lt;br /&gt;
к которым мы сейчас перейдем.&lt;br /&gt;
&lt;br /&gt;
Чтобы начать, щелкните на одной из вкладок. Метод добавления&lt;br /&gt;
задачи тот же, что и при создании различных списков: выберите Add&lt;br /&gt;
Task [Добавить задачу], введите имя задачи и нажмите ввод. По умолчанию, задачи будут появляться в порядке их введения, но вы можете&lt;br /&gt;
изменить этот порядок, установив некоторым из них приоритеты – это&lt;br /&gt;
один из фундаментальных аспектов серьезной организации, достойный применения. RTM имеет четыре настройки приоритетов: 1, 2, 3 и&lt;br /&gt;
none [нет]. Для придания задаче приоритета, выберите ее, используя&lt;br /&gt;
флажок слева от имени задачи, а затем в выпадающем списке над&lt;br /&gt;
задачами укажите соответствующий приоритет. Задача при этом подсветится и, в зависимости от выбранных вами настроек, может также&lt;br /&gt;
изменить свою позицию в списке. Высокоприоритетные элементы&lt;br /&gt;
всплывут к верху краю списка, элементы без приоритета останутся&lt;br /&gt;
внизу. Вы можете также повысить или понизить приоритет области&lt;br /&gt;
задач, выбрав все те, что нужно изменить, и применив к ним пункт&lt;br /&gt;
списка Move Priority Up... [Повысить приоритет...]. При этом приоритет&lt;br /&gt;
3 у задач изменится на 2, а 2 изменится на 1. События без приоритета&lt;br /&gt;
автоматически получат приоритет 3.&lt;br /&gt;
&lt;br /&gt;
Это облегчает управление приоритетами в течение дня. Завершив&lt;br /&gt;
задачу с высоким приоритетом, вы можете выбрать ее и пометить как&lt;br /&gt;
Complete [Выполнено], а затем выбрать следующую и увеличить ее&lt;br /&gt;
приоритет на 1, чтобы знать новую первоочередную задачу.&lt;br /&gt;
&lt;br /&gt;
Вы могли заметить, что задачи по умолчанию не связаны с датой;&lt;br /&gt;
добавить ее и можно, и несложно. Сперва выберите задачу, установив&lt;br /&gt;
флажок, а затем перейдите в раздел справа от списка задач. На вид это&lt;br /&gt;
просто информационный список, но все записи в нем можно редактировать, и если вы щелкнете на тексте рядом с записью Due: [Срок],&lt;br /&gt;
то сможете добавить информацию о сроке выполнения задачи. RTM&lt;br /&gt;
хватает ума, чтобы проверить и реализовать ваши намерения; например, если вы введете срок как ‘next tuesday’ [следующий вторник], он&lt;br /&gt;
автоматически введет за вас дату, а если вы укажете только время, он&lt;br /&gt;
сочтет, что вы имели в виду «сегодня», если время еще не прошло;&lt;br /&gt;
иначе он впишет его на «завтра». Вы можете также установить опцию&lt;br /&gt;
повторения (она работает так же, как и в календаре), добавить предположительное время завершения, поместить тэги для категорий поверх&lt;br /&gt;
уже имеющихся и даже добавить URL, если, например, задача связана&lt;br /&gt;
с неким web-сайтом или документом в сети.&lt;br /&gt;
&lt;br /&gt;
В добавление ко вкладке Task [Задача], имеется также опция Notes&lt;br /&gt;
[Заметки] – это небольшая, автоматически сохраняющаяся текстовая&lt;br /&gt;
область, где можно внести дополнительные детали конкретной задачи. Все эти детали окажутся под рукой, когда вы выберете задачу из –&lt;br /&gt;
весьма мощное подспорье. Задачи можно также добавлять в список по&lt;br /&gt;
электронной почте, SMS или, если вы хотите приобщиться к Web 2.0,&lt;br /&gt;
даже через учетную запись Twitter.&lt;br /&gt;
&lt;br /&gt;
=== Полный цикл ===&lt;br /&gt;
Итак, мы организовали наше расписание в Sunbird и справились с организацией управления текущими задачами посредством Remember The&lt;br /&gt;
Milk. Настало время небольшого объединения мыслей и связей: соединим обе службы вместе. RTM имеет возможность вывода вашего списка задач – по крайней мере, тех, у которых есть дата завершения – в&lt;br /&gt;
виде iCal-файла, то есть мы можем подписаться на этот URL при помощи Sunbird и получить автоматическое появление задач в календаре.&lt;br /&gt;
Стандартная система RTM выводит каждый список в виде отдельного iCal-файла, но не худо бы собрать их в один синхронизированный&lt;br /&gt;
файл. Так что вновь перейдите на страницу Settings [Настройки] и&lt;br /&gt;
выберите вкладку Info. Здесь вы найдете адрес электронной почты для&lt;br /&gt;
пересылки задач в ваш список, адрес ленты Atom (и сможете просматривать ваш список задач в читалке RSS), а также два адреса, которые&lt;br /&gt;
можно добавить в строку Адрес в окне нового календаря Sunbird.&lt;br /&gt;
&lt;br /&gt;
Здесь есть две опции. Во-первых, возможен экспорт списка задач в&lt;br /&gt;
виде списка, но он поддерживается немногими программами. Лучший&lt;br /&gt;
(да и единственный) выбор для Sunbird – заставить RTM экспортировать списки как события. Щелкните правой кнопкой на URL с пометкой&lt;br /&gt;
iCalendar Events Service (All Lists) [Служба событий iCalendar (Все списки)] и выберите Copy Link Location [Копировать ссылку]. Теперь вернитесь в Sunbird и вставьте эту информацию в строку Адрес нового календаря. Задайте новому календарю имя и цвет, и ваши события перекочуют в Sunbird. Однако помните, что в отличие от календаря Google, к&lt;br /&gt;
которому мы подключались ранее, это езда в один конец: изменение&lt;br /&gt;
даты завершения задачи в Sunbird не отразится в списке RTM.&lt;br /&gt;
&lt;br /&gt;
Хотя хорошее управление временем не снизит число распечаток&lt;br /&gt;
и не укоротит бессмысленные споры ваших детей, оно может оказать&lt;br /&gt;
положительное влияние на ваш уровень стресса и улучшить отношения&lt;br /&gt;
с семьей и коллегами. И благодаря осведомленности о том, что мне&lt;br /&gt;
следует делать и когда, я выкроил 20 минут на эффектное завершение&lt;br /&gt;
статьи. А лучше посижу немного в саду...&lt;br /&gt;
&lt;br /&gt;
==== КПК-органайзер Graphite (врезка) ====&lt;br /&gt;
Все еще существуют такие места и времена,&lt;br /&gt;
когда у вас нет доступа к вашим любовно построенным календарям и спискам задач. Для&lt;br /&gt;
таких случаев, органайзер Graphite – прекрасный инструмент внесения данных, готовых для&lt;br /&gt;
синхронизации с вашими календарями и списками задач при первой возможности. Такие&lt;br /&gt;
продаются в любом приличном магазине канцтоваров и в большинстве супермаркетов, причем во всевозможных видах: прошитые, на&lt;br /&gt;
спиральке и клеенные. На пару с маленьким&lt;br /&gt;
карандашом, органайзер можно легко извлечь&lt;br /&gt;
и использовать практически везде, даже там,&lt;br /&gt;
где суеверные туземцы подозревают, что электричество – это мстительный злой дух.&lt;br /&gt;
Основные принципы обращения с подобными&lt;br /&gt;
штуками – выбирать их малого формата,&lt;br /&gt;
использовать по листку на день и, вычеркнув&lt;br /&gt;
все на листке, тут же его выбрасывать, чтобы&lt;br /&gt;
верхним всегда был «сегодня» или «просрочено». Да, и не забывайте о взаимном обмене&lt;br /&gt;
событиями между органайзером и вашим&lt;br /&gt;
списком задач (исключительно нудное занятие).&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Paragon_NTFS</id>
		<title>LXF97:Paragon NTFS</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Paragon_NTFS"/>
				<updated>2008-03-09T12:53:15Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Paragon NTFS for Linux 6.0 ==&lt;br /&gt;
''Нужна запись на жесткие диски Windows XP или Vista из-под Linux?&lt;br /&gt;
'''Нейл Ботвик''' тестирует единственное потенциальное решение&lt;br /&gt;
с поддержкой сжатия NTFS.''&lt;br /&gt;
&lt;br /&gt;
Пользуясь открытым ПО, мы принимаем как должное даваемую им свободу. Здесь нет тайн, и программы&lt;br /&gt;
легко срабатываются друг с другом: ведь их&lt;br /&gt;
внутренние механизмы показаны в исходном&lt;br /&gt;
коде. Если нужен доступ к файловой системе&lt;br /&gt;
Linux из Windows, достаточно лишь установить драйвер – вся информация, необходимая для его написания, открыта и доступна.&lt;br /&gt;
Попробуете сделать наоборот – совсем другая&lt;br /&gt;
история. В ядро Linux встраивается ограниченная поддержка файловой системы NTFS,&lt;br /&gt;
ограниченная в том смысле, что безопасным считается только чтение с этой системы.&lt;br /&gt;
Альтернатива – модуль NTFS-3G FUSE, предоставляющий доступ и на чтение, и на запись.&lt;br /&gt;
Paragon сработал еще одну, коммерческую&lt;br /&gt;
альтернативу, но по плечу ли ей заставить вас&lt;br /&gt;
раскошелиться (а заодно и поступиться принципами свободного ПО)?&lt;br /&gt;
&lt;br /&gt;
Существует две версии NTFS for Linux:&lt;br /&gt;
персональная, о которой пойдет речь в&lt;br /&gt;
нашей статье, устанавливает лишь драйвер&lt;br /&gt;
файловой системы без дополнительных&lt;br /&gt;
инструментов. Профессиональная версия&lt;br /&gt;
оснащена инструментами для создания,&lt;br /&gt;
изменения размеров, архивирования и других операций с NTFS-разделами из-под&lt;br /&gt;
Linux. Обе версии могут похвалиться Live&lt;br /&gt;
CD для доступа к NTFS-разделам, включая&lt;br /&gt;
возможность резервного копирования данных на CD или DVD.&lt;br /&gt;
&lt;br /&gt;
Как же работает программа? Прилично, и&lt;br /&gt;
очень быстро. Файловая система устанавливается в качестве модуля ядра, поэтому перед&lt;br /&gt;
инсталляцией необходимо иметь исходный&lt;br /&gt;
код ядра и среду для компиляции, чего по&lt;br /&gt;
умолчанию в большинстве дистрибутивов нет,&lt;br /&gt;
но все необходимые компоненты присутствуют в стандартном репозитории. Установив их,&lt;br /&gt;
инсталлировать программу нетрудно: достаточно распаковать zip-архив и запустить sh&lt;br /&gt;
install.sh (не верьте документам, советующим&lt;br /&gt;
использовать ./install.sh, поскольку бит ‘x’ на&lt;br /&gt;
нем не установлен). Инсталлятор формирует&lt;br /&gt;
и инсталлирует модуль файловой системы,&lt;br /&gt;
затем разыскивает NTFS-разделы и добавляет&lt;br /&gt;
их в /etc/fstab. Есть возможность автоматического монтирования таких разделов при загрузке. Графического инсталлятора нет, а базовые&lt;br /&gt;
инструкции, пожалуй, чересчур подробны, но&lt;br /&gt;
запуск инсталляционного скрипта – это все,&lt;br /&gt;
что вам нужно сделать.&lt;br /&gt;
&lt;br /&gt;
Будучи установленной, файловая система&lt;br /&gt;
монтируется так же, как и любая другая, но,&lt;br /&gt;
вследствие различий с NTFS, получить такие&lt;br /&gt;
же права доступа и владения, как в Linux,&lt;br /&gt;
не получится. Вместо этого предоставляются&lt;br /&gt;
параметры монтирования с указанием владельца, группы и прав доступа по умолчанию&lt;br /&gt;
для файлов, совершенно так же, как с встроенными в ядро файловыми системами FAT.&lt;br /&gt;
&lt;br /&gt;
==== Производительность (врезка) ====&lt;br /&gt;
Мы пробовали запустить тестовые программы bonnie, bonnie++ и&lt;br /&gt;
iozone, но они не работают с NTFS For Linux, и это показывает, что&lt;br /&gt;
некоторые важные функции файловой системы упущены. Но вряд ли&lt;br /&gt;
кто-нибудь заведет базу данных или почтовый сервер на NTFS-разделе, да и сверхскоростное массовое копирование/создание файлов&lt;br /&gt;
вряд ли понадобится. Так что мы обошлись тестами попроще. Они&lt;br /&gt;
состояли из копирования двух наборов файлов в обоих направлениях.&lt;br /&gt;
Первый набор состоял из 4 ГБ больших видеофайлов, чтобы оценить&lt;br /&gt;
максимальную скорость копирования. Второй набор, из 713 МБ малых&lt;br /&gt;
файлов (49900 на два «ядерных» дерева), показывал способности&lt;br /&gt;
обращения со сложными файловыми структурами при сравнительно&lt;br /&gt;
малом объеме передаваемых данных. NTFS For Linux оказалась медленнее NTFS-3G в первом случае, при копировании файлов большого&lt;br /&gt;
объема, и быстрее – во втором, при наличии сложной системы файлов. Полученные цифры приводятся ниже.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
|NTFS for Linux&lt;br /&gt;
|NTFS-3G&lt;br /&gt;
|-&lt;br /&gt;
|Запись 4 ГБ больших файлов&lt;br /&gt;
|80 секунд&lt;br /&gt;
|128 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Чтение 4 ГБ больших файлов&lt;br /&gt;
|207 секунд&lt;br /&gt;
|108 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Запись 713 МБ малых файлов&lt;br /&gt;
|99 секунд&lt;br /&gt;
|806 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Чтение 713 МБ малых файлов&lt;br /&gt;
|105 секунд&lt;br /&gt;
|545 секунд&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Давление сжатия? ===&lt;br /&gt;
83-страничное руководство, доступное на сайте Paragon (но не включенное в загружаемый&lt;br /&gt;
архив) покрывает вопросы инсталляции и различные параметры монтирования файловых&lt;br /&gt;
систем NTFS, причем речь идет в основном&lt;br /&gt;
об инструментах профессиональной версии.&lt;br /&gt;
Существенное отличие от NTFS-3G – обращение со сжатыми файлами. Это файлы, сжатые&lt;br /&gt;
на уровне файловой системы, а не обычные&lt;br /&gt;
zip-архивы. Хотя читать такие файлы могут&lt;br /&gt;
многие файловые системы, записывать в этот&lt;br /&gt;
формат умеет лишь NTFS for Linux – и если у&lt;br /&gt;
вас сжатая NTFS, ваш выбор уже сделан. LXF&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:MailEnforcer_3.0</id>
		<title>LXF97:MailEnforcer 3.0</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:MailEnforcer_3.0"/>
				<updated>2008-03-09T12:51:40Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: == MailEnforcer 3.0 == ''На рынке ПО для предприятий затевается нечто действительно серьезное, если '''Грэм Морри...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== MailEnforcer 3.0 ==&lt;br /&gt;
''На рынке ПО для предприятий затевается нечто действительно серьезное, если '''Грэм Моррисон'''&lt;br /&gt;
решился вставить в обзор выражение «проталкивать».''&lt;br /&gt;
&lt;br /&gt;
Безопасность Linux общеизвестна; главным образом потому-то мы им и пользуемся. Но это видимое преимущество&lt;br /&gt;
лишь сейчас начинает влиять на мир бизнеса:&lt;br /&gt;
сразу несколько компаний готовят продукты, призванные протолкнуть Linux на широкий рынок. Устройство Yoggie Gatekeeper Pro,&lt;br /&gt;
которое мы рассматривали в LXF95 – яркий&lt;br /&gt;
тому пример. Это встраиваемый Linux-компьютер, установленный на USB-брелок, для&lt;br /&gt;
фильтрации и защиты интернет-данных – при&lt;br /&gt;
этом неважно, под какой ОС работает компьютер-хост. MailEnforcer имеет сходное назначение, только масштаб крупнее. Продукт поставляется предустановленным на сервер по вашему выбору либо в виде комплекта DVD/CD для&lt;br /&gt;
инсталляции на имеющееся оборудование, с&lt;br /&gt;
целью обеспечения безопасности электронной&lt;br /&gt;
почты на уровне предприятия. После установки программа занимает место между почтовыми серверами и Интернетом, проверяя сообщения на соответствие строгим критериям, а&lt;br /&gt;
заодно регистрируя все сообщения, создавая&lt;br /&gt;
отчеты и посылая предупреждения.&lt;br /&gt;
&lt;br /&gt;
=== Мудрость Oracle ===&lt;br /&gt;
Для установки MailEnforcer на наш сервер Athlon&lt;br /&gt;
64 X2 мы взяли DVD-версию. Фактически, устанавливается 64-битная версия Oracle Enterprise&lt;br /&gt;
Linux, и это был первый раз, когда данный&lt;br /&gt;
отпочкованный Oracle от Red Hat дистрибутив&lt;br /&gt;
повстречался нам в живой природе. Литература&lt;br /&gt;
о продукте утверждает, что глубоких познаний&lt;br /&gt;
Linux не требуется, и это соответствует истине – по крайней мере, во время инсталляции:&lt;br /&gt;
даются точные указания о том, что устанавливать, какие службы включить (есть только SSH&lt;br /&gt;
и SMTP) и как сменить пароль суперпользователя. Все остальное делается через web-интерфейс, доступный после инсталляции. Однако&lt;br /&gt;
мы не рекомендуем слепо полагаться на Linux,&lt;br /&gt;
не обладая хотя бы минимальными навыками.&lt;br /&gt;
Средний администратор без опыта работы в&lt;br /&gt;
Linux может споткнуться, даже делая такие&lt;br /&gt;
простые вещи, как смена IP-адреса сервера –&lt;br /&gt;
особенно если инсталляция не включает X11.&lt;br /&gt;
&lt;br /&gt;
Web-интерфейс – облицовка либо для&lt;br /&gt;
встроенного Java-апплета, либо для загружаемого приложения Java Web&lt;br /&gt;
Start (последнее работает&lt;br /&gt;
на нашей машине немного&lt;br /&gt;
быстрее). Успешным был&lt;br /&gt;
и опыт с Blackdown Java –&lt;br /&gt;
единственный метод получить 64-битную версию&lt;br /&gt;
Web Start. Да и любая другая 32-битная инсталляция&lt;br /&gt;
Java (1.4 и 1.5) не должна&lt;br /&gt;
вызвать особых проблем. Во время работы&lt;br /&gt;
внутри MailEnforcer крутится столько страниц,&lt;br /&gt;
что ими можно было бы наполнить мифическую Вавилонскую библиотеку. Это пугает&lt;br /&gt;
до тех пор, пока вы не уясните, как все-таки&lt;br /&gt;
работает эта система. MailEnforcer напоминает web-прокси, а чтобы поместить программу между вашими почтовыми клиентами и&lt;br /&gt;
серверами (как правило, Microsoft Exchange&lt;br /&gt;
или Sendmail), ее нужно настроить. В малом&lt;br /&gt;
окружении MailEnforcer можно использовать&lt;br /&gt;
даже как самостоятельный POP-сервер, установив простые настройки и включив пользователей во внутреннюю группу – кстати, это&lt;br /&gt;
неплохая возможность протестировать систему перед началом ее серьезного использования. Правильно настроенный, MailEnforcer&lt;br /&gt;
должен быть прозрачен для конечного пользователя, проявляясь разве что в извещениях&lt;br /&gt;
о блокировке сообщения, которое нужно както вызволять.&lt;br /&gt;
&lt;br /&gt;
=== Изобилие настроек ===&lt;br /&gt;
Сказать, что MailEnforcer легко настраивается – значит, сказать очень мало. Под собственные нужды здесь можно перекроить буквально все. Характерный пример – фильтры&lt;br /&gt;
сканирования почты, имеющие более сорока&lt;br /&gt;
параметров настройки (и все включены по&lt;br /&gt;
умолчанию). Среди них проверка коммерческим (Kaspersky) и открытым (ClamAV) антивирусами, доступ к различным онлайн-базам&lt;br /&gt;
данных по фишингу и спаму, черные списки&lt;br /&gt;
DNS, оптическое распознавание изображений и многие другие тесты. Мы заваливали&lt;br /&gt;
программу сотнями писем из наших коллекций спама, а MailEnforcer добросовестно&lt;br /&gt;
блокировал их или помечал как подозрительные. Страница обзора статистики, кроме&lt;br /&gt;
своего прямого назначения, позволит вам&lt;br /&gt;
засечь необычно высокую почтовую активность и направит на ваш электронный адрес&lt;br /&gt;
более подробные отчеты. Вдумчиво комбинируя подразделения и группы, можно добиться&lt;br /&gt;
осуществления любой мыслимой политики,&lt;br /&gt;
а также переложить часть бремени администрирования, используя микроменеджмент.&lt;br /&gt;
Продукт легко масштабируется и подходит как&lt;br /&gt;
для малых/средних предприятий, так и для&lt;br /&gt;
сравнительно крупных организаций. Подобной&lt;br /&gt;
программы для Linux мы до сих пор просто не&lt;br /&gt;
встречали. LXF&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Yellow_Dog_PS_3</id>
		<title>LXF97:Yellow Dog PS 3</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Yellow_Dog_PS_3"/>
				<updated>2008-03-09T12:48:10Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: == Yellow Dog Linux 5.0.2 == ''Из-за перехода Apple c PowerPC на процессоры Intel будущее Yellow Dog заволакивается туманом. '''Грэ...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Yellow Dog Linux 5.0.2 ==&lt;br /&gt;
''Из-за перехода Apple c PowerPC на процессоры Intel будущее Yellow Dog заволакивается туманом.&lt;br /&gt;
'''Грэм Моррисон''' видит (маловероятного) спасителя в PlayStation 3 от Sony.''&lt;br /&gt;
&lt;br /&gt;
Когда Apple перешла на архитектуру&lt;br /&gt;
Intel, сразу же встал вопрос о выживании PowerPC-ориентированных&lt;br /&gt;
дистрибутивов вроде Yellow Dog Linux (YDL)&lt;br /&gt;
без своей главной пользовательской базы.&lt;br /&gt;
Но процессор PlayStation 3 (PS3) Cell (производная от PPC), вкупе с решением Sony оставить возможность установки альтернативной&lt;br /&gt;
ОС, открывают двери для Linux. Есть версии&lt;br /&gt;
Ubuntu и Fedora, специально собранные для&lt;br /&gt;
PS3, но YDL была здесь с самого начала.&lt;br /&gt;
&lt;br /&gt;
=== Другая ОС ===&lt;br /&gt;
Понадобятся обычные USB-клавиатура и&lt;br /&gt;
мышь – мы успешно опробовали несколько разных устройств. После инсталляции&lt;br /&gt;
Linux игровой контроллер PS3 поддерживается через USB-порт, но только как джойстик.&lt;br /&gt;
Проблема инсталляции Linux на PS3 состоит&lt;br /&gt;
в том, что приходится переформатировать и&lt;br /&gt;
заново разбивать жесткий диск из главного&lt;br /&gt;
меню приставки – инструменты дистрибутива&lt;br /&gt;
для этого использовать невозможно, так как&lt;br /&gt;
Sony ограничила прямой доступ и к жесткому&lt;br /&gt;
диску, и к графической аппаратуре. Видимо,&lt;br /&gt;
фирма опасается посягательства Linux-разработчиков на ее мировое господство в игровой&lt;br /&gt;
сфере. Есть угроза потерять весь загруженный&lt;br /&gt;
контент, сохраненные игры, музыку, видео и&lt;br /&gt;
фотографии, если только предварительно не&lt;br /&gt;
сделать резервную копию. К счастью, функция резервирования и восстановления в PS3&lt;br /&gt;
развита хорошо: приятно видеть, что не все&lt;br /&gt;
потеряно, обретая прежнюю консоль после&lt;br /&gt;
переформатирования. Сетевая учетная запись&lt;br /&gt;
PlayStation Network сохраняется, на месте и&lt;br /&gt;
настройка беспроводного доступа, и другие&lt;br /&gt;
настройки, сделанные вами ранее.&lt;br /&gt;
&lt;br /&gt;
Нужно установить загрузчик YDL с DVD&lt;br /&gt;
(достаточно вставить диск и выбрать «Install&lt;br /&gt;
Other OS» в системном меню PS3) и сменить&lt;br /&gt;
ОС приставки по умолчанию, чтобы подобие&lt;br /&gt;
загрузчика Sony изменилось на Grub или LILO.&lt;br /&gt;
Мы обнаружили, что в случае возникновения&lt;br /&gt;
каких-либо проблем, достаточно выключить&lt;br /&gt;
питание консоли, затем удерживать кнопку&lt;br /&gt;
питания в течение пяти секунд – и стандартная&lt;br /&gt;
конфигурация Sony полностью восстановится.&lt;br /&gt;
Инсталляция продолжительна, занимает свыше 90 минут – хотя инсталлятор и уверяет, что&lt;br /&gt;
25 минут для установки вполне достаточно.&lt;br /&gt;
&lt;br /&gt;
=== Недоуправление пакетами ===&lt;br /&gt;
Набор ПО в YDL довольно скуден. Вы получаете Firefox, OpenOffice.org и Eclipse IDE,&lt;br /&gt;
плюс пригоршню игр Gnome, и все это искусно вплетено в рабочий стол Enlightenment.&lt;br /&gt;
Запущен и OpenSSH, а VNC держится наготове&lt;br /&gt;
на случай, если вам захочется использовать&lt;br /&gt;
ТВ. Менеджер пакетов YUM инсталлирован,&lt;br /&gt;
поэтому нетрудно добавить дополнительные&lt;br /&gt;
репозитории и загрузить все необходимые&lt;br /&gt;
пакеты. Удобная среда с несколькими API&lt;br /&gt;
для многопоточной Cell-разработки выглядит&lt;br /&gt;
и работает гладко, а сравнительно небольшое потребление памяти E17 (у PS3 только&lt;br /&gt;
256 МБ RAM) сохраняет отзывчивость системы. Правда, если запустить программу с чуть&lt;br /&gt;
большими потребностями по памяти, рабочий стол начинает тормозить. Firefox, например, запускается 8 секунд, а после запуска&lt;br /&gt;
еле тащится. Аппаратные ограничения Sony&lt;br /&gt;
вынуждают Linux-дистрибутивы применять&lt;br /&gt;
для графического вывода фрейм-буфер, не&lt;br /&gt;
извлекая никакой выгоды из мощной аппаратуры Nvidia. Но не все так плохо, как может&lt;br /&gt;
показаться – например, полноэкранное видео&lt;br /&gt;
со стандартным разрешением работает без&lt;br /&gt;
проблем. И все же графическое ускорение&lt;br /&gt;
могло бы помочь YDL выйти на «большую&lt;br /&gt;
дорогу» и получить более широкое признание.&lt;br /&gt;
&lt;br /&gt;
=== Свойства навскидку (врезка) ===&lt;br /&gt;
'''Пакеты YUM'''&lt;br /&gt;
&lt;br /&gt;
Добавьте собственные&lt;br /&gt;
репозитории для установки&lt;br /&gt;
новых приложений – и ваша PS3&lt;br /&gt;
превратится в полноценный&lt;br /&gt;
медиаплейер.&lt;br /&gt;
&lt;br /&gt;
'''Специально для PS3'''&lt;br /&gt;
&lt;br /&gt;
Инсталляция ПО и поддержка&lt;br /&gt;
сети специфичны для PS3, а&lt;br /&gt;
значит, заставить заработать&lt;br /&gt;
функции вроде беспроводного&lt;br /&gt;
доступа совсем несложно.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Google_Desktop</id>
		<title>LXF97:Google Desktop</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Google_Desktop"/>
				<updated>2008-03-09T12:43:32Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: == Google Desktop 1.0 == ''Страсти по настольному поиску отбушевали двенадцать месяцев назад. '''Грэм Моррисон''' с...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Google Desktop 1.0 ==&lt;br /&gt;
''Страсти по настольному поиску отбушевали двенадцать месяцев назад. '''Грэм Моррисон''' считает,&lt;br /&gt;
что Google припозднился с предложением для Linux.''&lt;br /&gt;
&lt;br /&gt;
Спустя почти три года после выпуска&lt;br /&gt;
первоначальной версии для Microsoft&lt;br /&gt;
Windows и на два месяца позже версии для Apple OS X, Google Desktop наконец-то&lt;br /&gt;
пришел в Linux. Слово «desktop» в названии&lt;br /&gt;
несколько двусмысленно. Google Desktop –&lt;br /&gt;
только поисковый инструмент, способный&lt;br /&gt;
заменить Kat [ныне Strigi, – прим.ред.] в KDE&lt;br /&gt;
или Beagle в Gnome, но никак не рабочий стол&lt;br /&gt;
KDE или Gnome. Хотя программа далеко не&lt;br /&gt;
бесполезна: до сих пор нам не сильно везло&lt;br /&gt;
с приличными поисковыми инструментами&lt;br /&gt;
для Linux. Несмотря на потенциальную полезность, они либо занимают под свой индекс&lt;br /&gt;
весь жесткий диск, либо отъедают солидные&lt;br /&gt;
куски оперативной памяти, либо полностью&lt;br /&gt;
блокируют компьютер после нескольких дней&lt;br /&gt;
использования. Хотелось бы встретить работоспособную версию.&lt;br /&gt;
&lt;br /&gt;
=== 64 – быть? ===&lt;br /&gt;
Google предоставляет 32-битные двоичные&lt;br /&gt;
пакеты в форматах Deb и RPM для большинства Linux-дистрибутивов. Обещана 64-битная версия, хотя мы без особого труда установили 32-битный вариант на нашу 64-битную машину. Затем остается вручную запустить программу командой gdlinux – на панели&lt;br /&gt;
инструментов появляется маленький значок&lt;br /&gt;
Google Desktop, и начинается важнейший процесс индексирования. Кажется, что он длится&lt;br /&gt;
целую вечность. Индекс формируется лишь во&lt;br /&gt;
время простоя компьютера, поэтому прошло&lt;br /&gt;
несколько дней, прежде чем 81361 файлов на&lt;br /&gt;
нашей машине были полностью проиндексированы, что составило около 7 часов чистого&lt;br /&gt;
времени обработки. Подобно Kat или Beagle,&lt;br /&gt;
поиск Google Desktop проникающий: просматривается и анализируется не только имя файла и его местонахождение, но и содержание,&lt;br /&gt;
причем каждый тип файлов требует особой&lt;br /&gt;
обработки. Поддерживается множество различных форматов с уклоном в Linux: документы OpenOffice.org, стандартные почтовые&lt;br /&gt;
директории, Thunderbird, PDF, Ogg Vorbis, mp3&lt;br /&gt;
и истории браузеров. Тот, у кого есть почта&lt;br /&gt;
на Google, может включить в индекс учетную&lt;br /&gt;
запись Gmail, интегрировав таким образом ее с&lt;br /&gt;
рабочим столом. Удивляет лишь полное отсутствие поддержки формата Microsoft Office.&lt;br /&gt;
&lt;br /&gt;
=== Встроенный сервер ===&lt;br /&gt;
Есть два способа начать поиск. Можно дваж-&lt;br /&gt;
ды нажать клавишу Ctrl, и откроется малень-&lt;br /&gt;
кий поисковый инструмент, а можно вызвать&lt;br /&gt;
новую домашнюю страницу Google из панели.&lt;br /&gt;
Поисковый инструмент интуитивно понятнее и&lt;br /&gt;
хорошо интегрируется в рабочий стол, подобно Beagle или Spotlight на OS X. Во время набора слов запроса результаты появляются ниже&lt;br /&gt;
поля ввода. Нажатие Enter выводит более&lt;br /&gt;
подробные результаты поиска в отдельном&lt;br /&gt;
окне браузера. Выглядит все это совершенно&lt;br /&gt;
так же, как онлайн-поиск Google, который все&lt;br /&gt;
мы знаем и любим, включая краткий конспект&lt;br /&gt;
по содержанию результата каждого запроса.&lt;br /&gt;
Google утверждает, что никакие данные с персональных серверов на его собственные серверы не поступают. Типы файлов обозначаются маленькими значками, а щелчок на одном&lt;br /&gt;
из файлов в списке найденных открывает его&lt;br /&gt;
в назначенном по умолчанию приложении.&lt;br /&gt;
&lt;br /&gt;
Все это работает безупречно, без всяких проблем с производительностью, которыми страдают «родные» Linux-приложения. Но&lt;br /&gt;
вывод web-браузера не очень хорош с точки&lt;br /&gt;
зрения интеграции в рабочий стол – вдобавок&lt;br /&gt;
не работает опция ИЛИ – и возникает неприятное чувство, что это скорее циничная попытка&lt;br /&gt;
Google навязать пользователю зависимость&lt;br /&gt;
от своей поисковой технологии, чем действительно полезное Linux-приложение. Windowsверсия обладает виджетами, чья функциональность схожа с Dashboard/SuperKaramba,&lt;br /&gt;
что гораздо удобнее. Хотелось бы увидеть&lt;br /&gt;
нечто подобное и в Linux. А пока это только очередной настольный поисковый инструмент. Пускай и работоспособный...&lt;br /&gt;
&lt;br /&gt;
==== Свойства навскидку (врезка) ====&lt;br /&gt;
'''Интеграция'''&lt;br /&gt;
&lt;br /&gt;
Дважды нажмите клавишу Ctrl –&lt;br /&gt;
поисковик Google откроется и&lt;br /&gt;
заполнит свое окно результатами поиска по вашему запросу.&lt;br /&gt;
&lt;br /&gt;
'''Проникающий поиск'''&lt;br /&gt;
&lt;br /&gt;
Google Search читает содержание файлов многочисленных&lt;br /&gt;
типов и добавляет результаты&lt;br /&gt;
чтения к своему индексу для&lt;br /&gt;
удобства последующего поиска.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:eSys_PC</id>
		<title>LXF97:eSys PC</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:eSys_PC"/>
				<updated>2008-03-09T12:37:35Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: == eSys ePC basic == ''Данный ПК – еще не ноутбук за $ 100, но он доказывает, что концепция реализуема. ''Ник Вейч'' п...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== eSys ePC basic ==&lt;br /&gt;
''Данный ПК – еще не ноутбук за $ 100, но он доказывает, что концепция реализуема.&lt;br /&gt;
''Ник Вейч'' проверяет, может ли такая удача быть правдой...''&lt;br /&gt;
&lt;br /&gt;
Ну что можно купить за 280 долларов?&lt;br /&gt;
Кусок PlayStation 3? 736 консервных&lt;br /&gt;
банок фасоли? Четыре подписки на&lt;br /&gt;
лучший в мире журнал о Linux? А настольный&lt;br /&gt;
компьютер с предустановленным Linux – не&lt;br /&gt;
хотите? Компания eSys – известный производитель систем, которые специалисты&lt;br /&gt;
по маркетингу называют «доступными», в&lt;br /&gt;
диапазоне от самых простых до умеренно&lt;br /&gt;
«навороченных». Наша модель – простей-&lt;br /&gt;
шая из простых – дешева до предела. Но:&lt;br /&gt;
дешевка ли?&lt;br /&gt;
&lt;br /&gt;
Качество изготовления – хоть куда. Чашку&lt;br /&gt;
кофе можно ставить сверху без опаски. И&lt;br /&gt;
хотя корпус – гадкий midi-tower серебристого&lt;br /&gt;
пластика от магазина бытовой техники High&lt;br /&gt;
Street, свое дело он делает. Предусмотрены&lt;br /&gt;
свободные отсеки для дополнительного оборудования (отрада самоделкиных), несколько&lt;br /&gt;
USB- и аудио-портов спереди и обычный частокол выводов сзади, включая стандартный&lt;br /&gt;
VGA-разъем для монитора.&lt;br /&gt;
&lt;br /&gt;
В комплект входят мультимедиа-клавиатура и мышь, а вот на монитор придется раскошелиться. Найдите такой, чтобы работал со&lt;br /&gt;
стандартным VGA-входом – впрочем, многие&lt;br /&gt;
ЖК-дисплеи это до сих пор умеют.&lt;br /&gt;
&lt;br /&gt;
По части графики, материнская плата, на&lt;br /&gt;
которой собрана система, оснащена встроенным графическим чипсетом VIA, но это&lt;br /&gt;
&lt;br /&gt;
не есть хорошо. Конечно, VIA позаботилась&lt;br /&gt;
о поддержке Linux на своем оборудовании,&lt;br /&gt;
но лучший результат зачастую достигается&lt;br /&gt;
при использовании свободных драйверов, не&lt;br /&gt;
полностью поддержанных VIA. Однако даже&lt;br /&gt;
проект Openchrome, всеобщая палочка-выручалочка, на время написания статьи не поддерживал данный чипсет. Винить eSys особо не за что, но, честно говоря, компания&lt;br /&gt;
могла бы подобрать материнскую плату от&lt;br /&gt;
Intel с интегрированной поддержкой графики.&lt;br /&gt;
Досадно осознавать, что потенциал аппаратуры используется не полностью. Стоит, правда,&lt;br /&gt;
заметить, что улучшенная поддержка графики&lt;br /&gt;
могла бы повлиять разве что на качество воспроизведения фильмов – того, кто ищет мощную графическую станцию, наша машина вряд&lt;br /&gt;
ли заинтересует.&lt;br /&gt;
&lt;br /&gt;
=== Ubuntu навсегда ===&lt;br /&gt;
В комплект входят клавиатура и мышь. Оба&lt;br /&gt;
устройства оснащены разъемами PS/2, и это&lt;br /&gt;
радует. Клавиатура выглядит вполне солидно,&lt;br /&gt;
есть все функциональные клавиши, а сверху&lt;br /&gt;
еще и панель медиакнопок. Удивительно, но&lt;br /&gt;
все они (ну, почти все) исправно работают!&lt;br /&gt;
Разве не здорово, что можно изменить громкость или запустить браузер без мороки с X-настройками или lineak?&lt;br /&gt;
&lt;br /&gt;
Менее удивительно то, что сборщики eSys&lt;br /&gt;
EPC выбрали в качестве системы для установки Ubuntu (между прочим, компьютер снабжается сопроводительным диском с драйверами&lt;br /&gt;
VIA, хотя толку от него мало, ведь на нем нет&lt;br /&gt;
специальных Linux-драйверов). Это уже тенденция, и с учетом того, что Dell тоже собирается ставить Ubuntu, выбор явно неплох. Не&lt;br /&gt;
могут же ошибаться сразу несколько миллионов пользователей, верно?&lt;br /&gt;
&lt;br /&gt;
Разочаровывает, однако, что это голая инсталляция Ubuntu. Похоже, произошло следующее: Ubuntu (речь идет о 6.06 LTS) установили&lt;br /&gt;
на компьютер, использовав стандартное имя&lt;br /&gt;
пользователя и пароль (кстати, они есть на&lt;br /&gt;
стикере на боку коробки!), затем полученный&lt;br /&gt;
образ залили на жесткие диски всех новых&lt;br /&gt;
компьютеров. Зная это, нетрудно предугадать&lt;br /&gt;
последствия подобной установки Ubuntu.&lt;br /&gt;
&lt;br /&gt;
Например, если вы задумали подарить&lt;br /&gt;
такой компьютер племяннику на Рождество,&lt;br /&gt;
готовьтесь к продолжительным телефонным&lt;br /&gt;
переговорам. После первой загрузки и входа в&lt;br /&gt;
систему пользователь получает стандартный,&lt;br /&gt;
пустой рабочий стол Ubuntu: ни на экране,&lt;br /&gt;
ни в коробке нет никаких сведений о том, что&lt;br /&gt;
делать дальше. Невольно возникает идея сразу же сменить пароль и/или настроить новую&lt;br /&gt;
учетную запись!&lt;br /&gt;
&lt;br /&gt;
Но это не единственная проблема. Конечно,&lt;br /&gt;
бывалый линуксоид запросто добьется правильной работы, установив дополнительные&lt;br /&gt;
пакеты, но ведь большинство покупателей&lt;br /&gt;
будут новичками. Так вот, когда они запустят Firefox и набредут на какой-нибудь сайт с&lt;br /&gt;
Flash-эффектами, обнаружится, что по фак&lt;br /&gt;
ту ничего не работает. Firefox, естественно,&lt;br /&gt;
предложит загрузить подходящий модуль, но&lt;br /&gt;
мы-то с вами знаем, что из этого ничего&lt;br /&gt;
не выйдет; а пользователь зайдет в тупик.&lt;br /&gt;
Инсталлировать Flash-player от Adobe вручную&lt;br /&gt;
для новобранца весьма непросто, даже если&lt;br /&gt;
он знает, откуда его можно скачать. Политика&lt;br /&gt;
Adobe в отношении OEM настолько либераль-&lt;br /&gt;
на, что производители eSys могли бы преспо-&lt;br /&gt;
койно предустановить Flash. Пусть такое ПО&lt;br /&gt;
может «запятнать» систему щепоткой «несво-&lt;br /&gt;
боды», но лица, кому эти пятна не дают покоя,&lt;br /&gt;
обычно способны инсталлировать и стериль-&lt;br /&gt;
ную систему с сопроводительного диска.&lt;br /&gt;
&lt;br /&gt;
Выходит, что это не проблемы Ubuntu. Да&lt;br /&gt;
это и не проблемы самого устройства: скорее,&lt;br /&gt;
упущенные возможности завоевать симпатии&lt;br /&gt;
пользователей, что могло бы благотворно&lt;br /&gt;
отразиться на имидже Linux.&lt;br /&gt;
&lt;br /&gt;
Компьютер явно заслуживает внимания;&lt;br /&gt;
его легко использовать как домашний сер-&lt;br /&gt;
вер или настольную систему для непритяза-&lt;br /&gt;
тельного пользователя. Скорости процессора&lt;br /&gt;
вполне достаточно для повседневных нужд.&lt;br /&gt;
Правда, воспроизведение фильмов несколько&lt;br /&gt;
отрывистое, а 3D-эффекты Compiz недоступ-&lt;br /&gt;
ны, но ведь для рабочей лошадки это не глав-&lt;br /&gt;
ное. Зато устройство вызывающе дешево, и в&lt;br /&gt;
этом есть своя «изюминка». Мы рекомендуем&lt;br /&gt;
взять да и установить на купленный компью-&lt;br /&gt;
тер свой любимый дистрибутив – терять особо&lt;br /&gt;
нечего.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Paragon_NTFS</id>
		<title>LXF97:Paragon NTFS</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Paragon_NTFS"/>
				<updated>2008-03-09T12:28:45Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: /* Производительность */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Paragon NTFS for Linux 6.0 ==&lt;br /&gt;
''Нужна запись на жесткие диски Windows XP или Vista из-под Linux?&lt;br /&gt;
'''Нейл Ботвик''' тестирует единственное потенциальное решение&lt;br /&gt;
с поддержкой сжатия NTFS.''&lt;br /&gt;
&lt;br /&gt;
Пользуясь открытым ПО, мы прини-&lt;br /&gt;
маем как должное даваемую им сво-&lt;br /&gt;
боду. Здесь нет тайн, и программы&lt;br /&gt;
легко срабатываются друг с другом: ведь их&lt;br /&gt;
внутренние механизмы показаны в исходном&lt;br /&gt;
коде. Если нужен доступ к файловой системе&lt;br /&gt;
Linux из Windows, достаточно лишь устано-&lt;br /&gt;
вить драйвер – вся информация, необходи-&lt;br /&gt;
мая для его написания, открыта и доступна.&lt;br /&gt;
Попробуете сделать наоборот – совсем другая&lt;br /&gt;
история. В ядро Linux встраивается ограни-&lt;br /&gt;
ченная поддержка файловой системы NTFS,&lt;br /&gt;
ограниченная в том смысле, что безопас-&lt;br /&gt;
ным считается только чтение с этой системы.&lt;br /&gt;
Альтернатива – модуль NTFS-3G FUSE, предо-&lt;br /&gt;
ставляющий доступ и на чтение, и на запись.&lt;br /&gt;
Paragon сработал еще одну, коммерческую&lt;br /&gt;
альтернативу, но по плечу ли ей заставить вас&lt;br /&gt;
раскошелиться (а заодно и поступиться прин-&lt;br /&gt;
ципами свободного ПО)?&lt;br /&gt;
&lt;br /&gt;
Существует две версии NTFS for Linux:&lt;br /&gt;
персональная, о которой пойдет речь в&lt;br /&gt;
нашей статье, устанавливает лишь драйвер&lt;br /&gt;
файловой системы без дополнительных&lt;br /&gt;
инструментов. Профессиональная версия&lt;br /&gt;
оснащена инструментами для создания,&lt;br /&gt;
изменения размеров, архивирования и дру-&lt;br /&gt;
гих операций с NTFS-разделами из-под&lt;br /&gt;
Linux. Обе версии могут похвалиться Live&lt;br /&gt;
CD для доступа к NTFS-разделам, включая&lt;br /&gt;
возможность резервного копирования дан-&lt;br /&gt;
ных на CD или DVD.&lt;br /&gt;
&lt;br /&gt;
Как же работает программа? Прилично, и&lt;br /&gt;
очень быстро. Файловая система устанавли-&lt;br /&gt;
вается в качестве модуля ядра, поэтому перед&lt;br /&gt;
инсталляцией необходимо иметь исходный&lt;br /&gt;
код ядра и среду для компиляции, чего по&lt;br /&gt;
умолчанию в большинстве дистрибутивов нет,&lt;br /&gt;
но все необходимые компоненты присутству-&lt;br /&gt;
ют в стандартном репозитории. Установив их,&lt;br /&gt;
инсталлировать программу нетрудно: доста-&lt;br /&gt;
точно распаковать zip-архив и запустить sh&lt;br /&gt;
install.sh (не верьте документам, советующим&lt;br /&gt;
использовать ./install.sh, поскольку бит ‘x’ на&lt;br /&gt;
нем не установлен). Инсталлятор формирует&lt;br /&gt;
и инсталлирует модуль файловой системы,&lt;br /&gt;
затем разыскивает NTFS-разделы и добавляет&lt;br /&gt;
их в /etc/fstab. Есть возможность автоматичес-&lt;br /&gt;
кого монтирования таких разделов при загруз-&lt;br /&gt;
ке. Графического инсталлятора нет, а базовые&lt;br /&gt;
инструкции, пожалуй, чересчур подробны, но&lt;br /&gt;
запуск инсталляционного скрипта – это все,&lt;br /&gt;
что вам нужно сделать.&lt;br /&gt;
&lt;br /&gt;
Будучи установленной, файловая система&lt;br /&gt;
монтируется так же, как и любая другая, но,&lt;br /&gt;
вследствие различий с NTFS, получить такие&lt;br /&gt;
же права доступа и владения, как в Linux,&lt;br /&gt;
не получится. Вместо этого предоставляются&lt;br /&gt;
параметры монтирования с указанием вла-&lt;br /&gt;
дельца, группы и прав доступа по умолчанию&lt;br /&gt;
для файлов, совершенно так же, как с встро-&lt;br /&gt;
енными в ядро файловыми системами FAT.&lt;br /&gt;
&lt;br /&gt;
==== Производительность (врезка) ====&lt;br /&gt;
Мы пробовали запустить тестовые программы bonnie, bonnie++ и&lt;br /&gt;
iozone, но они не работают с NTFS For Linux, и это показывает, что&lt;br /&gt;
некоторые важные функции файловой системы упущены. Но вряд ли&lt;br /&gt;
кто-нибудь заведет базу данных или почтовый сервер на NTFS-разде-&lt;br /&gt;
ле, да и сверхскоростное массовое копирование/создание файлов&lt;br /&gt;
вряд ли понадобится. Так что мы обошлись тестами попроще. Они&lt;br /&gt;
состояли из копирования двух наборов файлов в обоих направлениях.&lt;br /&gt;
Первый набор состоял из 4 ГБ больших видеофайлов, чтобы оценить&lt;br /&gt;
максимальную скорость копирования. Второй набор, из 713 МБ малых&lt;br /&gt;
файлов (49900 на два «ядерных» дерева), показывал способности&lt;br /&gt;
обращения со сложными файловыми структурами при сравнительно&lt;br /&gt;
малом объеме передаваемых данных. NTFS For Linux оказалась мед-&lt;br /&gt;
леннее NTFS-3G в первом случае, при копировании файлов большого&lt;br /&gt;
объема, и быстрее – во втором, при наличии сложной системы фай-&lt;br /&gt;
лов. Полученные цифры приводятся ниже.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
|NTFS for Linux&lt;br /&gt;
|NTFS-3G&lt;br /&gt;
|-&lt;br /&gt;
|Запись 4 ГБ больших файлов&lt;br /&gt;
|80 секунд&lt;br /&gt;
|128 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Чтение 4 ГБ больших файлов&lt;br /&gt;
|207 секунд&lt;br /&gt;
|108 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Запись 713 МБ малых файлов&lt;br /&gt;
|99 секунд&lt;br /&gt;
|806 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Чтение 713 МБ малых файлов&lt;br /&gt;
|105 секунд&lt;br /&gt;
|545 секунд&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Давление сжатия? ===&lt;br /&gt;
83-страничное руководство, доступное на сай-&lt;br /&gt;
те Paragon (но не включенное в загружаемый&lt;br /&gt;
архив) покрывает вопросы инсталляции и раз-&lt;br /&gt;
личные параметры монтирования файловых&lt;br /&gt;
систем NTFS, причем речь идет в основном&lt;br /&gt;
об инструментах профессиональной версии.&lt;br /&gt;
Существенное отличие от NTFS-3G – обраще-&lt;br /&gt;
ние со сжатыми файлами. Это файлы, сжатые&lt;br /&gt;
на уровне файловой системы, а не обычные&lt;br /&gt;
zip-архивы. Хотя читать такие файлы могут&lt;br /&gt;
многие файловые системы, записывать в этот&lt;br /&gt;
формат умеет лишь NTFS for Linux – и если у&lt;br /&gt;
вас сжатая NTFS, ваш выбор уже сделан. LXF&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Paragon_NTFS</id>
		<title>LXF97:Paragon NTFS</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Paragon_NTFS"/>
				<updated>2008-03-09T12:27:43Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: == Paragon NTFS for Linux 6.0 == ''Нужна запись на жесткие диски Windows XP или Vista из-под Linux? '''Нейл Ботвик''' тестирует еди...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Paragon NTFS for Linux 6.0 ==&lt;br /&gt;
''Нужна запись на жесткие диски Windows XP или Vista из-под Linux?&lt;br /&gt;
'''Нейл Ботвик''' тестирует единственное потенциальное решение&lt;br /&gt;
с поддержкой сжатия NTFS.''&lt;br /&gt;
&lt;br /&gt;
Пользуясь открытым ПО, мы прини-&lt;br /&gt;
маем как должное даваемую им сво-&lt;br /&gt;
боду. Здесь нет тайн, и программы&lt;br /&gt;
легко срабатываются друг с другом: ведь их&lt;br /&gt;
внутренние механизмы показаны в исходном&lt;br /&gt;
коде. Если нужен доступ к файловой системе&lt;br /&gt;
Linux из Windows, достаточно лишь устано-&lt;br /&gt;
вить драйвер – вся информация, необходи-&lt;br /&gt;
мая для его написания, открыта и доступна.&lt;br /&gt;
Попробуете сделать наоборот – совсем другая&lt;br /&gt;
история. В ядро Linux встраивается ограни-&lt;br /&gt;
ченная поддержка файловой системы NTFS,&lt;br /&gt;
ограниченная в том смысле, что безопас-&lt;br /&gt;
ным считается только чтение с этой системы.&lt;br /&gt;
Альтернатива – модуль NTFS-3G FUSE, предо-&lt;br /&gt;
ставляющий доступ и на чтение, и на запись.&lt;br /&gt;
Paragon сработал еще одну, коммерческую&lt;br /&gt;
альтернативу, но по плечу ли ей заставить вас&lt;br /&gt;
раскошелиться (а заодно и поступиться прин-&lt;br /&gt;
ципами свободного ПО)?&lt;br /&gt;
&lt;br /&gt;
Существует две версии NTFS for Linux:&lt;br /&gt;
персональная, о которой пойдет речь в&lt;br /&gt;
нашей статье, устанавливает лишь драйвер&lt;br /&gt;
файловой системы без дополнительных&lt;br /&gt;
инструментов. Профессиональная версия&lt;br /&gt;
оснащена инструментами для создания,&lt;br /&gt;
изменения размеров, архивирования и дру-&lt;br /&gt;
гих операций с NTFS-разделами из-под&lt;br /&gt;
Linux. Обе версии могут похвалиться Live&lt;br /&gt;
CD для доступа к NTFS-разделам, включая&lt;br /&gt;
возможность резервного копирования дан-&lt;br /&gt;
ных на CD или DVD.&lt;br /&gt;
&lt;br /&gt;
Как же работает программа? Прилично, и&lt;br /&gt;
очень быстро. Файловая система устанавли-&lt;br /&gt;
вается в качестве модуля ядра, поэтому перед&lt;br /&gt;
инсталляцией необходимо иметь исходный&lt;br /&gt;
код ядра и среду для компиляции, чего по&lt;br /&gt;
умолчанию в большинстве дистрибутивов нет,&lt;br /&gt;
но все необходимые компоненты присутству-&lt;br /&gt;
ют в стандартном репозитории. Установив их,&lt;br /&gt;
инсталлировать программу нетрудно: доста-&lt;br /&gt;
точно распаковать zip-архив и запустить sh&lt;br /&gt;
install.sh (не верьте документам, советующим&lt;br /&gt;
использовать ./install.sh, поскольку бит ‘x’ на&lt;br /&gt;
нем не установлен). Инсталлятор формирует&lt;br /&gt;
и инсталлирует модуль файловой системы,&lt;br /&gt;
затем разыскивает NTFS-разделы и добавляет&lt;br /&gt;
их в /etc/fstab. Есть возможность автоматичес-&lt;br /&gt;
кого монтирования таких разделов при загруз-&lt;br /&gt;
ке. Графического инсталлятора нет, а базовые&lt;br /&gt;
инструкции, пожалуй, чересчур подробны, но&lt;br /&gt;
запуск инсталляционного скрипта – это все,&lt;br /&gt;
что вам нужно сделать.&lt;br /&gt;
&lt;br /&gt;
Будучи установленной, файловая система&lt;br /&gt;
монтируется так же, как и любая другая, но,&lt;br /&gt;
вследствие различий с NTFS, получить такие&lt;br /&gt;
же права доступа и владения, как в Linux,&lt;br /&gt;
не получится. Вместо этого предоставляются&lt;br /&gt;
параметры монтирования с указанием вла-&lt;br /&gt;
дельца, группы и прав доступа по умолчанию&lt;br /&gt;
для файлов, совершенно так же, как с встро-&lt;br /&gt;
енными в ядро файловыми системами FAT.&lt;br /&gt;
&lt;br /&gt;
==== Производительность ====&lt;br /&gt;
Мы пробовали запустить тестовые программы bonnie, bonnie++ и&lt;br /&gt;
iozone, но они не работают с NTFS For Linux, и это показывает, что&lt;br /&gt;
некоторые важные функции файловой системы упущены. Но вряд ли&lt;br /&gt;
кто-нибудь заведет базу данных или почтовый сервер на NTFS-разде-&lt;br /&gt;
ле, да и сверхскоростное массовое копирование/создание файлов&lt;br /&gt;
вряд ли понадобится. Так что мы обошлись тестами попроще. Они&lt;br /&gt;
состояли из копирования двух наборов файлов в обоих направлениях.&lt;br /&gt;
Первый набор состоял из 4 ГБ больших видеофайлов, чтобы оценить&lt;br /&gt;
максимальную скорость копирования. Второй набор, из 713 МБ малых&lt;br /&gt;
файлов (49900 на два «ядерных» дерева), показывал способности&lt;br /&gt;
обращения со сложными файловыми структурами при сравнительно&lt;br /&gt;
малом объеме передаваемых данных. NTFS For Linux оказалась мед-&lt;br /&gt;
леннее NTFS-3G в первом случае, при копировании файлов большого&lt;br /&gt;
объема, и быстрее – во втором, при наличии сложной системы фай-&lt;br /&gt;
лов. Полученные цифры приводятся ниже.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
|NTFS for Linux&lt;br /&gt;
|NTFS-3G&lt;br /&gt;
|-&lt;br /&gt;
|Запись 4 ГБ больших файлов&lt;br /&gt;
|80 секунд&lt;br /&gt;
|128 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Чтение 4 ГБ больших файлов&lt;br /&gt;
|207 секунд&lt;br /&gt;
|108 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Запись 713 МБ малых файлов&lt;br /&gt;
|99 секунд&lt;br /&gt;
|806 секунд&lt;br /&gt;
|-&lt;br /&gt;
|Чтение 713 МБ малых файлов&lt;br /&gt;
|105 секунд&lt;br /&gt;
|545 секунд&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Давление сжатия? ===&lt;br /&gt;
83-страничное руководство, доступное на сай-&lt;br /&gt;
те Paragon (но не включенное в загружаемый&lt;br /&gt;
архив) покрывает вопросы инсталляции и раз-&lt;br /&gt;
личные параметры монтирования файловых&lt;br /&gt;
систем NTFS, причем речь идет в основном&lt;br /&gt;
об инструментах профессиональной версии.&lt;br /&gt;
Существенное отличие от NTFS-3G – обраще-&lt;br /&gt;
ние со сжатыми файлами. Это файлы, сжатые&lt;br /&gt;
на уровне файловой системы, а не обычные&lt;br /&gt;
zip-архивы. Хотя читать такие файлы могут&lt;br /&gt;
многие файловые системы, записывать в этот&lt;br /&gt;
формат умеет лишь NTFS for Linux – и если у&lt;br /&gt;
вас сжатая NTFS, ваш выбор уже сделан. LXF&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Bash</id>
		<title>LXF97:Bash</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Bash"/>
				<updated>2008-03-09T12:11:57Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bash: Используем командную строку ==&lt;br /&gt;
''Часть 2 Хотите проводить в командной строке больше времени? '''Рэйчел Проберт'''&lt;br /&gt;
расскажет о grep, pipe и других командах, которые обязательно надо знать.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы говорили о действиях, потенциально способных &lt;br /&gt;
отобрать много времени: например, необходимо быстро найти отчет, &lt;br /&gt;
написанный когда-то давно. Вы забыли имя файла, но помните, что &lt;br /&gt;
темой отчета было соглашение с компанией ABC. После обнаружения &lt;br /&gt;
документа его содержимое нужно отправить коллеге или шефу.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat filename | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Для начала мы разомнемся с помощью нескольких команд для &lt;br /&gt;
опытных пользователей. Они вряд ли пригодятся обычным пользователям для каждодневной работы, но если вы администратор системы &lt;br /&gt;
и устанавливаете программы для своих пользователей, значение этих &lt;br /&gt;
команд повышается.&lt;br /&gt;
Команда  whoami не вовлечет вас в философские дискуссии по &lt;br /&gt;
самопознанию, но напомнит, под каким именем пользователя вы вошли в систему; очень удобно, когда вы работаете с несколькими учетными записями, используемыми для решения различных задач, и постоянно переключаетесь между ними. Похожая команда, whatis, позволит &lt;br /&gt;
понять, что делает та или иная программа. В Linux сотни программ, и &lt;br /&gt;
невозможно запомнить, что делает каждая из них. Например, напечатав whatis grep, вы увидите:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep (1) - print lines matching a pattern&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Команда whereis поможет найти другие нужные вам команды или&lt;br /&gt;
программы. Если вы загружаете из Интернета программу, для работы&lt;br /&gt;
которой нужна другая программа, вам захочется узнать, установлена&lt;br /&gt;
ли она в вашей системе. Чтобы выяснить местонахождение программы&lt;br /&gt;
и ее man-страницы, наберите whereis [имя программы]. Так, например,&lt;br /&gt;
находится расположение популярного текстового редактора vi:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 whereis vi&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Echo – небольшая команда, повторяющая все, что вы ни напечатали. Например, если набрать echo hello, на экране появится слово &amp;quot;hello&amp;quot;.&lt;br /&gt;
Вообще говоря, обычно это делать незачем: команда echo может пригодиться вам в будущем, если вы начнете писать скрипты. (Скрипт – это&lt;br /&gt;
небольшая программа, позволяющая выполнить несколько команд за&lt;br /&gt;
один раз.) В скриптах  echo может использоваться для отображения&lt;br /&gt;
действий скрипта в каждый момент времени, или чтобы попросить&lt;br /&gt;
пользователя что-нибудь сделать, например, ввести текст.&lt;br /&gt;
Команда  last выведет список пользователей, заходивших сегодня в систему, и терминалы, которые они используют (использовали).&lt;br /&gt;
Набрав  exit, вы завершите сеанс работы с терминалом. Если нужно&lt;br /&gt;
зайти в систему под другим пользователем, используйте вместо нее&lt;br /&gt;
команду logout.&lt;br /&gt;
&lt;br /&gt;
=== Часть 1: По Grep’у! ===&lt;br /&gt;
Вот теперь повеселимся! Grep – команда, которая находит слова в &lt;br /&gt;
файлах. Охотно сказала бы, что ее название произошло от слова &lt;br /&gt;
&amp;quot;поиск&amp;quot; по-клингонски, но это было бы неправдой и только укрепило бы стереотип, что все технари любят Star Trek! На самом деле &lt;br /&gt;
название команды – сокращение от &amp;quot;Глобальный Парсер Регулярных &lt;br /&gt;
Выражений&amp;quot; (Global Regular Expression Parser), что означает &amp;quot;глобальный поиск строк, соответствующих регулярному выражению, и их &lt;br /&gt;
вывод на экран&amp;quot;. Название команды происходит от команды текстового &lt;br /&gt;
редактора ed g/re/p, выполняющей подобные действия.&lt;br /&gt;
Начнем с создания специального каталога, где будем размещать новые &lt;br /&gt;
файлы. Чтобы убедиться, что каталог создан, используйте команду ls.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mkdir Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Откроем текстовый редактор и создадим новый файл report1.txt:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico report1.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Pico – это текстовый редактор, который я использовала при написании &lt;br /&gt;
этой статьи. В дистрибутив Linux включено несколько текстовых редакторов; выбор одного из них определяется лишь вашими предпочтениями и наличием у редактора специальных функций, которые помогут &lt;br /&gt;
в решении именно вашей задачи. Когда текстовый редактор откроется, &lt;br /&gt;
напечатайте слово CompanyABC. Затем точно так же создайте второй &lt;br /&gt;
файл с именем report2.txt, который будет содержать слово companyabc. &lt;br /&gt;
Закончив, введите команду ls, и вы увидите примерно такой список:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music report1.txt report2.txt Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что файлы, которые мы создали, находятся рядом &lt;br /&gt;
с каталогом Work. Давайте переместим их в нужный каталог:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mv report*.txt /home/probert/Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Звездочка (*) – это специальный символ, который позволяет нам &lt;br /&gt;
делать все, что мы хотим, с файлами, название которых начинается со &lt;br /&gt;
слова  report; каждый из таких файлов включается в команду. У меня &lt;br /&gt;
есть правила именования файлов и разделения их на категории, которых я строго придерживаюсь. Например, названия всех файлов отчетов &lt;br /&gt;
начинаются со слова report, счетов – со слова invoice и т.д. Пускай это &lt;br /&gt;
выглядит как ритуальные действия безнадежно больного ОКР, зато при &lt;br /&gt;
наличии методичного подхода нужные вещи находятся очень быстро!&lt;br /&gt;
Переместимся в каталог Work и снова используем ls, чтобы убедиться,&lt;br /&gt;
что все файлы перемещены:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cd Work&lt;br /&gt;
 probert@ubuntu:~/Work$ ls&lt;br /&gt;
 report1.txt report2.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Сейчас мы сделаем следующий шаг в поисках этого крайне важного &lt;br /&gt;
файла для нашего коллеги. Команда grep обладает множеством опций &lt;br /&gt;
(их список выведет команда man grep). Опция -r позволяет выполнить &lt;br /&gt;
рекурсивный поиск файлов, начиная с названного каталога, а опция  -i &lt;br /&gt;
выполнит поиск без учета регистра. Попробуйте следующие команды с &lt;br /&gt;
опцией -i и без -i и посмотрите, как это повлияет на результаты поиска.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~/Work$ grep -r -i ‘CompanyABC’ /home/&lt;br /&gt;
 probert/Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 /home/probert/Work/report1.txt:CompanyABC&lt;br /&gt;
 /home/probert/Work/report2.txt:companyabc&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Итак, мы нашли этот неуловимый файл; что же дальше?&lt;br /&gt;
&lt;br /&gt;
=== Часть 2: Стандартный ввод-вывод ===&lt;br /&gt;
Стандартный ввод/вывод позволяет вводить данные в программу из&lt;br /&gt;
любого источника и выводить данные в любой источник. Таким образом, можно направить вывод одной команды непосредственно на ввод&lt;br /&gt;
другой команды... правда, мило? Linux предоставляет три канала ввода/вывода, более известных как потоки ввода/вывода. По умолчанию стандартный ввод подразумевает клавиатуру, стандартный вывод – экран.&lt;br /&gt;
Третий поток ввода/вывода – это на самом деле поток вывода для сообщений об ошибках, предупреждений и оповещений: так легче отличить&lt;br /&gt;
сообщения об ошибках от остальных сообщений. Поток ошибок обычно&lt;br /&gt;
также выводится на экран, но (как и каждый из трех стандартных потоков) может быть перенаправлен. Этим мы сейчас и займемся.&lt;br /&gt;
Есть два основных способа перенаправления потоков данных; мы&lt;br /&gt;
можем использовать &amp;gt; или | (перенаправление и каналы соответственно). Если нужно просто направить стандартный вывод в файл, можно&lt;br /&gt;
напечатать команда &amp;gt; файл. Давайте попробуем это на реальном примере: найдем все файлы с именем passwd в каталоге /etc. Наберите&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 find /etc -name passwd &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким (он зависит от особенностей вашего&lt;br /&gt;
дистрибутива Linux):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что команда генерирует как стандартный поток&lt;br /&gt;
вывода, так и поток ошибок. Сейчас мы создадим файл  findresult и&lt;br /&gt;
перенаправим стандартный поток вывода в этот файл, оставив на экране только ошибки.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd &amp;gt; findresult&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Перенаправим эти ошибки в другой файл, finderrors, используя 2&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt; finderrors&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Наберите ls, и вы получите результат, похожий на мой.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples finderrors findresult LAN Music&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Чтобы прочитать содержимое этих файлов, можно открыть их в текстовом редакторе pico:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Я предпочитаю просматривать небольшие файлы с помощью команды &lt;br /&gt;
cat. Ниже я использовала эту команду для просмотра результатов поиска в файлах findresult и finderrors.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cat findresult&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 probert@ubuntu:~$ cat finderrors&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы также можете добавить информацию в файл с помощью команды &lt;br /&gt;
&amp;gt;&amp;gt;. Давайте перенаправим стандартный вывод, чтобы добавить информацию в наш первый файл findresult следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt;&amp;gt; findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы можете снова проверить результаты с помощью команды  cat &lt;br /&gt;
findresult. Второй способ перенаправления потоков – вывод одной &lt;br /&gt;
команды прямо на вход другой (канализация). Давайте проверим &lt;br /&gt;
содержимое каталога  /usr/lib, где находятся объектные файлы, библиотеки и системные двоичные файлы. В моем каталоге  /usr/lib примерно полторы тысячи файлов – многовато, чтобы прокручивать этот &lt;br /&gt;
список один за другим! Если мы перенаправим вывод ls на ввод команды less, то получим список, в котором можно перемещаться по страницам, в удобном для нас темпе. Попробуйте:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Достигнув конца документа, нажмите клавишу  Q, чтобы вернуться в &lt;br /&gt;
командную строку. Вы также можете предварительно отсортировать &lt;br /&gt;
этот список по убыванию, например, таким образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | sort -r | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Краеугольный камень философии Unix заключается в том, чтобы каждая программа делала что-то одно по-настоящему хорошо, позволяя &lt;br /&gt;
использовать свой вывод как ввод другой программы. Использование &lt;br /&gt;
каналов позволяет провести этот принцип в жизнь, создавая очень &lt;br /&gt;
эффективные цепочки команд.&lt;br /&gt;
Теперь, разузнав, как работают  grep и каналы, сведем их вместе для &lt;br /&gt;
поиска того самого отчета и отправим его нашему коллеге:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat report1.txt | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Миссия завершена!&lt;br /&gt;
&lt;br /&gt;
==== Помощь по grep (врезка) ====&lt;br /&gt;
Поскольку  grep производит поиск соответствий по шаблонам, вы &lt;br /&gt;
должны предоставить ему регулярное выражение для этого шаблона. &lt;br /&gt;
Регулярные выражения бывают простыми и сложными. Наиболее распространенные (и простые) типы регулярных выражений выглядят так:&lt;br /&gt;
*abc Соответствует строкам, которые содержат &amp;quot;abc&amp;quot; в любом месте.&lt;br /&gt;
*^abc Соответствует строкам, начинающимся с &amp;quot;abc&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Мини-проект: команды для умных (врезка) ====&lt;br /&gt;
Есть несколько общих команд, о которых &lt;br /&gt;
полезно знать. Привожу некоторые из них без &lt;br /&gt;
объяснений; эти команды можно использовать &lt;br /&gt;
независимо от дополнительных опций. &lt;br /&gt;
Наберите их и посмотрите на результат.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|date&lt;br /&gt;
|df&lt;br /&gt;
|-&lt;br /&gt;
|date +%D&lt;br /&gt;
|free&lt;br /&gt;
|-&lt;br /&gt;
|date +%T&lt;br /&gt;
|du&lt;br /&gt;
|-&lt;br /&gt;
|cal&lt;br /&gt;
|top&lt;br /&gt;
|-&lt;br /&gt;
|cal 1066&lt;br /&gt;
|ps&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
Через месяц Moнтирование, создание резервных копий, распаковка файлов из tar и zip.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Bash</id>
		<title>LXF97:Bash</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Bash"/>
				<updated>2008-03-08T17:46:38Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bash: Используем командную строку ==&lt;br /&gt;
''Часть 2 Хотите проводить в командной строке больше времени? '''Рэйчел Проберт'''&lt;br /&gt;
расскажет о grep, pipe и других командах, которые обязательно надо знать.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы говорили о действиях, потенциально способных &lt;br /&gt;
отобрать много времени: например, необходимо быстро найти отчет, &lt;br /&gt;
написанный когда-то давно. Вы забыли имя файла, но помните, что &lt;br /&gt;
темой отчета было соглашение с компанией ABC. После обнаружения &lt;br /&gt;
документа его содержимое нужно отправить коллеге или шефу.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat filename | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Для начала мы разомнемся с помощью нескольких команд для &lt;br /&gt;
опытных пользователей. Они вряд ли пригодятся обычным пользователям для каждодневной работы, но если вы администратор системы &lt;br /&gt;
и устанавливаете программы для своих пользователей, значение этих &lt;br /&gt;
команд повышается.&lt;br /&gt;
Команда  whoami не вовлечет вас в философские дискуссии по &lt;br /&gt;
самопознанию, но напомнит, под каким именем пользователя вы вошли в систему; очень удобно, когда вы работаете с несколькими учетными записями, используемыми для решения различных задач, и постоянно переключаетесь между ними. Похожая команда, whatis, позволит &lt;br /&gt;
понять, что делает та или иная программа. В Linux сотни программ, и &lt;br /&gt;
невозможно запомнить, что делает каждая из них. Например, напечатав whatis grep, вы увидите:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep (1) - print lines matching a pattern&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Команда whereis поможет найти другие нужные вам команды или&lt;br /&gt;
программы. Если вы загружаете из Интернета программу, для работы&lt;br /&gt;
которой нужна другая программа, вам захочется узнать, установлена&lt;br /&gt;
ли она в вашей системе. Чтобы выяснить местонахождение программы&lt;br /&gt;
и ее man-страницы, наберите whereis [имя программы]. Так, например,&lt;br /&gt;
находится расположение популярного текстового редактора vi:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 whereis vi&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Echo – небольшая команда, повторяющая все, что вы ни напечатали. Например, если набрать echo hello, на экране появится слово &amp;quot;hello&amp;quot;.&lt;br /&gt;
Вообще говоря, обычно это делать незачем: команда echo может пригодиться вам в будущем, если вы начнете писать скрипты. (Скрипт – это&lt;br /&gt;
небольшая программа, позволяющая выполнить несколько команд за&lt;br /&gt;
один раз.) В скриптах  echo может использоваться для отображения&lt;br /&gt;
действий скрипта в каждый момент времени, или чтобы попросить&lt;br /&gt;
пользователя что-нибудь сделать, например, ввести текст.&lt;br /&gt;
Команда  last выведет список пользователей, заходивших сегодня в систему, и терминалы, которые они используют (использовали).&lt;br /&gt;
Набрав  exit, вы завершите сеанс работы с терминалом. Если нужно&lt;br /&gt;
зайти в систему под другим пользователем, используйте вместо нее&lt;br /&gt;
команду logout.&lt;br /&gt;
&lt;br /&gt;
=== Часть 1: По Grep’у! ===&lt;br /&gt;
Вот теперь повеселимся! Grep – команда, которая находит слова в &lt;br /&gt;
файлах. Охотно сказала бы, что ее название произошло от слова &lt;br /&gt;
&amp;quot;поиск&amp;quot; по-клингонски, но это было бы неправдой и только укрепило бы стереотип, что все технари любят Star Trek! На самом деле &lt;br /&gt;
название команды – сокращение от &amp;quot;Глобальный Парсер Регулярных &lt;br /&gt;
Выражений&amp;quot; (Global Regular Expression Parser), что означает &amp;quot;глобальный поиск строк, соответствующих регулярному выражению, и их &lt;br /&gt;
вывод на экран&amp;quot;. Название команды происходит от команды текстового &lt;br /&gt;
редактора ed g/re/p, выполняющей подобные действия.&lt;br /&gt;
Начнем с создания специального каталога, где будем размещать новые &lt;br /&gt;
файлы. Чтобы убедиться, что каталог создан, используйте команду ls.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mkdir Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Откроем текстовый редактор и создадим новый файл report1.txt:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico report1.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Pico – это текстовый редактор, который я использовала при написании &lt;br /&gt;
этой статьи. В дистрибутив Linux включено несколько текстовых редакторов; выбор одного из них определяется лишь вашими предпочтениями и наличием у редактора специальных функций, которые помогут &lt;br /&gt;
в решении именно вашей задачи. Когда текстовый редактор откроется, &lt;br /&gt;
напечатайте слово CompanyABC. Затем точно так же создайте второй &lt;br /&gt;
файл с именем report2.txt, который будет содержать слово companyabc. &lt;br /&gt;
Закончив, введите команду ls, и вы увидите примерно такой список:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music report1.txt report2.txt Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что файлы, которые мы создали, находятся рядом &lt;br /&gt;
с каталогом Work. Давайте переместим их в нужный каталог:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mv report*.txt /home/probert/Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Звездочка (*) – это специальный символ, который позволяет нам &lt;br /&gt;
делать все, что мы хотим, с файлами, название которых начинается со &lt;br /&gt;
слова  report; каждый из таких файлов включается в команду. У меня &lt;br /&gt;
есть правила именования файлов и разделения их на категории, которых я строго придерживаюсь. Например, названия всех файлов отчетов &lt;br /&gt;
начинаются со слова report, счетов – со слова invoice и т.д. Пускай это &lt;br /&gt;
выглядит как ритуальные действия безнадежно больного ОКР, зато при &lt;br /&gt;
наличии методичного подхода нужные вещи находятся очень быстро!&lt;br /&gt;
Переместимся в каталог Work и снова используем ls, чтобы убедиться,&lt;br /&gt;
что все файлы перемещены:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cd Work&lt;br /&gt;
 probert@ubuntu:~/Work$ ls&lt;br /&gt;
 report1.txt report2.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Сейчас мы сделаем следующий шаг в поисках этого крайне важного &lt;br /&gt;
файла для нашего коллеги. Команда grep обладает множеством опций &lt;br /&gt;
(их список выведет команда man grep). Опция -r позволяет выполнить &lt;br /&gt;
рекурсивный поиск файлов, начиная с названного каталога, а опция  -i &lt;br /&gt;
выполнит поиск без учета регистра. Попробуйте следующие команды с &lt;br /&gt;
опцией -i и без -i и посмотрите, как это повлияет на результаты поиска.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~/Work$ grep -r -i ‘CompanyABC’ /home/&lt;br /&gt;
 probert/Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 /home/probert/Work/report1.txt:CompanyABC&lt;br /&gt;
 /home/probert/Work/report2.txt:companyabc&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Итак, мы нашли этот неуловимый файл; что же дальше?&lt;br /&gt;
&lt;br /&gt;
=== Часть 2: Стандартный ввод-вывод ===&lt;br /&gt;
Стандартный ввод/вывод позволяет вводить данные в программу из&lt;br /&gt;
любого источника и выводить данные в любой источник. Таким образом, можно направить вывод одной команды непосредственно на ввод&lt;br /&gt;
другой команды... правда, мило? Linux предоставляет три канала ввода/вывода, более известных как потоки ввода/вывода. По умолчанию стандартный ввод подразумевает клавиатуру, стандартный вывод – экран.&lt;br /&gt;
Третий поток ввода/вывода – это на самом деле поток вывода для сообщений об ошибках, предупреждений и оповещений: так легче отличить&lt;br /&gt;
сообщения об ошибках от остальных сообщений. Поток ошибок обычно&lt;br /&gt;
также выводится на экран, но (как и каждый из трех стандартных потоков) может быть перенаправлен. Этим мы сейчас и займемся.&lt;br /&gt;
Есть два основных способа перенаправления потоков данных; мы&lt;br /&gt;
можем использовать &amp;gt; или | (перенаправление и каналы соответственно). Если нужно просто направить стандартный вывод в файл, можно&lt;br /&gt;
напечатать команда &amp;gt; файл. Давайте попробуем это на реальном примере: найдем все файлы с именем passwd в каталоге /etc. Наберите&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 find /etc -name passwd &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким (он зависит от особенностей вашего&lt;br /&gt;
дистрибутива Linux):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что команда генерирует как стандартный поток&lt;br /&gt;
вывода, так и поток ошибок. Сейчас мы создадим файл  findresult и&lt;br /&gt;
перенаправим стандартный поток вывода в этот файл, оставив на экране только ошибки.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd &amp;gt; findresult&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Перенаправим эти ошибки в другой файл, finderrors, используя 2&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt; finderrors&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Наберите ls, и вы получите результат, похожий на мой.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples finderrors findresult LAN Music&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Чтобы прочитать содержимое этих файлов, можно открыть их в текстовом редакторе pico:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Я предпочитаю просматривать небольшие файлы с помощью команды &lt;br /&gt;
cat. Ниже я использовала эту команду для просмотра результатов поиска в файлах findresult и finderrors.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cat findresult&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 probert@ubuntu:~$ cat finderrors&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы также можете добавить информацию в файл с помощью команды &lt;br /&gt;
&amp;gt;&amp;gt;. Давайте перенаправим стандартный вывод, чтобы добавить информацию в наш первый файл findresult следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt;&amp;gt; findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы можете снова проверить результаты с помощью команды  cat &lt;br /&gt;
findresult. Второй способ перенаправления потоков – вывод одной &lt;br /&gt;
команды прямо на вход другой (канализация). Давайте проверим &lt;br /&gt;
содержимое каталога  /usr/lib, где находятся объектные файлы, библиотеки и системные двоичные файлы. В моем каталоге  /usr/lib примерно полторы тысячи файлов – многовато, чтобы прокручивать этот &lt;br /&gt;
список один за другим! Если мы перенаправим вывод ls на ввод команды less, то получим список, в котором можно перемещаться по страницам, в удобном для нас темпе. Попробуйте:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Достигнув конца документа, нажмите клавишу  Q, чтобы вернуться в &lt;br /&gt;
командную строку. Вы также можете предварительно отсортировать &lt;br /&gt;
этот список по убыванию, например, таким образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | sort -r | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Краеугольный камень философии Unix заключается в том, чтобы каждая программа делала что-то одно по-настоящему хорошо, позволяя &lt;br /&gt;
использовать свой вывод как ввод другой программы. Использование &lt;br /&gt;
каналов позволяет провести этот принцип в жизнь, создавая очень &lt;br /&gt;
эффективные цепочки команд.&lt;br /&gt;
Теперь, разузнав, как работают  grep и каналы, сведем их вместе для &lt;br /&gt;
поиска того самого отчета и отправим его нашему коллеге:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat report1.txt | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Миссия завершена!&lt;br /&gt;
&lt;br /&gt;
==== Помощь по grep (вырезка) ====&lt;br /&gt;
Поскольку  grep производит поиск соответствий по шаблонам, вы &lt;br /&gt;
должны предоставить ему регулярное выражение для этого шаблона. &lt;br /&gt;
Регулярные выражения бывают простыми и сложными. Наиболее распространенные (и простые) типы регулярных выражений выглядят так:&lt;br /&gt;
*abc Соответствует строкам, которые содержат &amp;quot;abc&amp;quot; в любом месте.&lt;br /&gt;
*^abc Соответствует строкам, начинающимся с &amp;quot;abc&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Мини-проект: команды для умных (вырезка) ====&lt;br /&gt;
Есть несколько общих команд, о которых &lt;br /&gt;
полезно знать. Привожу некоторые из них без &lt;br /&gt;
объяснений; эти команды можно использовать &lt;br /&gt;
независимо от дополнительных опций. &lt;br /&gt;
Наберите их и посмотрите на результат.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|date&lt;br /&gt;
|df&lt;br /&gt;
|-&lt;br /&gt;
|date +%D&lt;br /&gt;
|free&lt;br /&gt;
|-&lt;br /&gt;
|date +%T&lt;br /&gt;
|du&lt;br /&gt;
|-&lt;br /&gt;
|cal&lt;br /&gt;
|top&lt;br /&gt;
|-&lt;br /&gt;
|cal 1066&lt;br /&gt;
|ps&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
Через месяц Moнтирование, создание резервных копий, распаковка файлов из tar и zip.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Bash</id>
		<title>LXF97:Bash</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Bash"/>
				<updated>2008-03-08T17:44:55Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: /* Мини-проект: команды для умных */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bash: Используем командную строку ==&lt;br /&gt;
''Часть 2 Хотите проводить в командной строке больше времени? '''Рэйчел Проберт'''&lt;br /&gt;
расскажет о grep, pipe и других командах, которые обязательно надо знать.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы говорили о действиях, потенциально способных &lt;br /&gt;
отобрать много времени: например, необходимо быстро найти отчет, &lt;br /&gt;
написанный когда-то давно. Вы забыли имя файла, но помните, что &lt;br /&gt;
темой отчета было соглашение с компанией ABC. После обнаружения &lt;br /&gt;
документа его содержимое нужно отправить коллеге или шефу.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat filename | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Для начала мы разомнемся с помощью нескольких команд для &lt;br /&gt;
опытных пользователей. Они вряд ли пригодятся обычным пользователям для каждодневной работы, но если вы администратор системы &lt;br /&gt;
и устанавливаете программы для своих пользователей, значение этих &lt;br /&gt;
команд повышается.&lt;br /&gt;
Команда  whoami не вовлечет вас в философские дискуссии по &lt;br /&gt;
самопознанию, но напомнит, под каким именем пользователя вы вошли в систему; очень удобно, когда вы работаете с несколькими учетными записями, используемыми для решения различных задач, и постоянно переключаетесь между ними. Похожая команда, whatis, позволит &lt;br /&gt;
понять, что делает та или иная программа. В Linux сотни программ, и &lt;br /&gt;
невозможно запомнить, что делает каждая из них. Например, напечатав whatis grep, вы увидите:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep (1) - print lines matching a pattern&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Команда whereis поможет найти другие нужные вам команды или&lt;br /&gt;
программы. Если вы загружаете из Интернета программу, для работы&lt;br /&gt;
которой нужна другая программа, вам захочется узнать, установлена&lt;br /&gt;
ли она в вашей системе. Чтобы выяснить местонахождение программы&lt;br /&gt;
и ее man-страницы, наберите whereis [имя программы]. Так, например,&lt;br /&gt;
находится расположение популярного текстового редактора vi:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 whereis vi&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Echo – небольшая команда, повторяющая все, что вы ни напечатали. Например, если набрать echo hello, на экране появится слово &amp;quot;hello&amp;quot;.&lt;br /&gt;
Вообще говоря, обычно это делать незачем: команда echo может пригодиться вам в будущем, если вы начнете писать скрипты. (Скрипт – это&lt;br /&gt;
небольшая программа, позволяющая выполнить несколько команд за&lt;br /&gt;
один раз.) В скриптах  echo может использоваться для отображения&lt;br /&gt;
действий скрипта в каждый момент времени, или чтобы попросить&lt;br /&gt;
пользователя что-нибудь сделать, например, ввести текст.&lt;br /&gt;
Команда  last выведет список пользователей, заходивших сегодня в систему, и терминалы, которые они используют (использовали).&lt;br /&gt;
Набрав  exit, вы завершите сеанс работы с терминалом. Если нужно&lt;br /&gt;
зайти в систему под другим пользователем, используйте вместо нее&lt;br /&gt;
команду logout.&lt;br /&gt;
&lt;br /&gt;
=== Часть 1: По Grep’у! ===&lt;br /&gt;
Вот теперь повеселимся! Grep – команда, которая находит слова в &lt;br /&gt;
файлах. Охотно сказала бы, что ее название произошло от слова &lt;br /&gt;
&amp;quot;поиск&amp;quot; по-клингонски, но это было бы неправдой и только укрепило бы стереотип, что все технари любят Star Trek! На самом деле &lt;br /&gt;
название команды – сокращение от &amp;quot;Глобальный Парсер Регулярных &lt;br /&gt;
Выражений&amp;quot; (Global Regular Expression Parser), что означает &amp;quot;глобальный поиск строк, соответствующих регулярному выражению, и их &lt;br /&gt;
вывод на экран&amp;quot;. Название команды происходит от команды текстового &lt;br /&gt;
редактора ed g/re/p, выполняющей подобные действия.&lt;br /&gt;
Начнем с создания специального каталога, где будем размещать новые &lt;br /&gt;
файлы. Чтобы убедиться, что каталог создан, используйте команду ls.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mkdir Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Откроем текстовый редактор и создадим новый файл report1.txt:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico report1.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Pico – это текстовый редактор, который я использовала при написании &lt;br /&gt;
этой статьи. В дистрибутив Linux включено несколько текстовых редакторов; выбор одного из них определяется лишь вашими предпочтениями и наличием у редактора специальных функций, которые помогут &lt;br /&gt;
в решении именно вашей задачи. Когда текстовый редактор откроется, &lt;br /&gt;
напечатайте слово CompanyABC. Затем точно так же создайте второй &lt;br /&gt;
файл с именем report2.txt, который будет содержать слово companyabc. &lt;br /&gt;
Закончив, введите команду ls, и вы увидите примерно такой список:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music report1.txt report2.txt Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что файлы, которые мы создали, находятся рядом &lt;br /&gt;
с каталогом Work. Давайте переместим их в нужный каталог:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mv report*.txt /home/probert/Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Звездочка (*) – это специальный символ, который позволяет нам &lt;br /&gt;
делать все, что мы хотим, с файлами, название которых начинается со &lt;br /&gt;
слова  report; каждый из таких файлов включается в команду. У меня &lt;br /&gt;
есть правила именования файлов и разделения их на категории, которых я строго придерживаюсь. Например, названия всех файлов отчетов &lt;br /&gt;
начинаются со слова report, счетов – со слова invoice и т.д. Пускай это &lt;br /&gt;
выглядит как ритуальные действия безнадежно больного ОКР, зато при &lt;br /&gt;
наличии методичного подхода нужные вещи находятся очень быстро!&lt;br /&gt;
Переместимся в каталог Work и снова используем ls, чтобы убедиться,&lt;br /&gt;
что все файлы перемещены:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cd Work&lt;br /&gt;
 probert@ubuntu:~/Work$ ls&lt;br /&gt;
 report1.txt report2.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Сейчас мы сделаем следующий шаг в поисках этого крайне важного &lt;br /&gt;
файла для нашего коллеги. Команда grep обладает множеством опций &lt;br /&gt;
(их список выведет команда man grep). Опция -r позволяет выполнить &lt;br /&gt;
рекурсивный поиск файлов, начиная с названного каталога, а опция  -i &lt;br /&gt;
выполнит поиск без учета регистра. Попробуйте следующие команды с &lt;br /&gt;
опцией -i и без -i и посмотрите, как это повлияет на результаты поиска.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~/Work$ grep -r -i ‘CompanyABC’ /home/&lt;br /&gt;
 probert/Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 /home/probert/Work/report1.txt:CompanyABC&lt;br /&gt;
 /home/probert/Work/report2.txt:companyabc&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Итак, мы нашли этот неуловимый файл; что же дальше?&lt;br /&gt;
&lt;br /&gt;
=== Часть 2: Стандартный ввод-вывод ===&lt;br /&gt;
Стандартный ввод/вывод позволяет вводить данные в программу из&lt;br /&gt;
любого источника и выводить данные в любой источник. Таким образом, можно направить вывод одной команды непосредственно на ввод&lt;br /&gt;
другой команды... правда, мило? Linux предоставляет три канала ввода/вывода, более известных как потоки ввода/вывода. По умолчанию стандартный ввод подразумевает клавиатуру, стандартный вывод – экран.&lt;br /&gt;
Третий поток ввода/вывода – это на самом деле поток вывода для сообщений об ошибках, предупреждений и оповещений: так легче отличить&lt;br /&gt;
сообщения об ошибках от остальных сообщений. Поток ошибок обычно&lt;br /&gt;
также выводится на экран, но (как и каждый из трех стандартных потоков) может быть перенаправлен. Этим мы сейчас и займемся.&lt;br /&gt;
Есть два основных способа перенаправления потоков данных; мы&lt;br /&gt;
можем использовать &amp;gt; или | (перенаправление и каналы соответственно). Если нужно просто направить стандартный вывод в файл, можно&lt;br /&gt;
напечатать команда &amp;gt; файл. Давайте попробуем это на реальном примере: найдем все файлы с именем passwd в каталоге /etc. Наберите&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 find /etc -name passwd &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким (он зависит от особенностей вашего&lt;br /&gt;
дистрибутива Linux):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что команда генерирует как стандартный поток&lt;br /&gt;
вывода, так и поток ошибок. Сейчас мы создадим файл  findresult и&lt;br /&gt;
перенаправим стандартный поток вывода в этот файл, оставив на экране только ошибки.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd &amp;gt; findresult&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Перенаправим эти ошибки в другой файл, finderrors, используя 2&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt; finderrors&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Наберите ls, и вы получите результат, похожий на мой.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples finderrors findresult LAN Music&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Помощь по grep (вырезка) ====&lt;br /&gt;
Поскольку  grep производит поиск соответствий по шаблонам, вы &lt;br /&gt;
должны предоставить ему регулярное выражение для этого шаблона. &lt;br /&gt;
Регулярные выражения бывают простыми и сложными. Наиболее распространенные (и простые) типы регулярных выражений выглядят так:&lt;br /&gt;
*abc Соответствует строкам, которые содержат &amp;quot;abc&amp;quot; в любом месте.&lt;br /&gt;
*^abc Соответствует строкам, начинающимся с &amp;quot;abc&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Чтобы прочитать содержимое этих файлов, можно открыть их в текстовом редакторе pico:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Я предпочитаю просматривать небольшие файлы с помощью команды &lt;br /&gt;
cat. Ниже я использовала эту команду для просмотра результатов поиска в файлах findresult и finderrors.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cat findresult&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 probert@ubuntu:~$ cat finderrors&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы также можете добавить информацию в файл с помощью команды &lt;br /&gt;
&amp;gt;&amp;gt;. Давайте перенаправим стандартный вывод, чтобы добавить информацию в наш первый файл findresult следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt;&amp;gt; findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы можете снова проверить результаты с помощью команды  cat &lt;br /&gt;
findresult. Второй способ перенаправления потоков – вывод одной &lt;br /&gt;
команды прямо на вход другой (канализация). Давайте проверим &lt;br /&gt;
содержимое каталога  /usr/lib, где находятся объектные файлы, библиотеки и системные двоичные файлы. В моем каталоге  /usr/lib примерно полторы тысячи файлов – многовато, чтобы прокручивать этот &lt;br /&gt;
список один за другим! Если мы перенаправим вывод ls на ввод команды less, то получим список, в котором можно перемещаться по страницам, в удобном для нас темпе. Попробуйте:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Достигнув конца документа, нажмите клавишу  Q, чтобы вернуться в &lt;br /&gt;
командную строку. Вы также можете предварительно отсортировать &lt;br /&gt;
этот список по убыванию, например, таким образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | sort -r | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Краеугольный камень философии Unix заключается в том, чтобы каждая программа делала что-то одно по-настоящему хорошо, позволяя &lt;br /&gt;
использовать свой вывод как ввод другой программы. Использование &lt;br /&gt;
каналов позволяет провести этот принцип в жизнь, создавая очень &lt;br /&gt;
эффективные цепочки команд.&lt;br /&gt;
Теперь, разузнав, как работают  grep и каналы, сведем их вместе для &lt;br /&gt;
поиска того самого отчета и отправим его нашему коллеге:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat report1.txt | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Миссия завершена!&lt;br /&gt;
&lt;br /&gt;
==== Мини-проект: команды для умных (вырезка) ====&lt;br /&gt;
Есть несколько общих команд, о которых &lt;br /&gt;
полезно знать. Привожу некоторые из них без &lt;br /&gt;
объяснений; эти команды можно использовать &lt;br /&gt;
независимо от дополнительных опций. &lt;br /&gt;
Наберите их и посмотрите на результат.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|date&lt;br /&gt;
|df&lt;br /&gt;
|-&lt;br /&gt;
|date +%D&lt;br /&gt;
|free&lt;br /&gt;
|-&lt;br /&gt;
|date +%T&lt;br /&gt;
|du&lt;br /&gt;
|-&lt;br /&gt;
|cal&lt;br /&gt;
|top&lt;br /&gt;
|-&lt;br /&gt;
|cal 1066&lt;br /&gt;
|ps&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Через месяц Moнтирование, создание резервных копий, распаковка файлов из tar и zip.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Bash</id>
		<title>LXF97:Bash</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Bash"/>
				<updated>2008-03-08T17:40:18Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: /* Помощь по grep (вырезка) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bash: Используем командную строку ==&lt;br /&gt;
''Часть 2 Хотите проводить в командной строке больше времени? '''Рэйчел Проберт'''&lt;br /&gt;
расскажет о grep, pipe и других командах, которые обязательно надо знать.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы говорили о действиях, потенциально способных &lt;br /&gt;
отобрать много времени: например, необходимо быстро найти отчет, &lt;br /&gt;
написанный когда-то давно. Вы забыли имя файла, но помните, что &lt;br /&gt;
темой отчета было соглашение с компанией ABC. После обнаружения &lt;br /&gt;
документа его содержимое нужно отправить коллеге или шефу.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat filename | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Для начала мы разомнемся с помощью нескольких команд для &lt;br /&gt;
опытных пользователей. Они вряд ли пригодятся обычным пользователям для каждодневной работы, но если вы администратор системы &lt;br /&gt;
и устанавливаете программы для своих пользователей, значение этих &lt;br /&gt;
команд повышается.&lt;br /&gt;
Команда  whoami не вовлечет вас в философские дискуссии по &lt;br /&gt;
самопознанию, но напомнит, под каким именем пользователя вы вошли в систему; очень удобно, когда вы работаете с несколькими учетными записями, используемыми для решения различных задач, и постоянно переключаетесь между ними. Похожая команда, whatis, позволит &lt;br /&gt;
понять, что делает та или иная программа. В Linux сотни программ, и &lt;br /&gt;
невозможно запомнить, что делает каждая из них. Например, напечатав whatis grep, вы увидите:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep (1) - print lines matching a pattern&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Команда whereis поможет найти другие нужные вам команды или&lt;br /&gt;
программы. Если вы загружаете из Интернета программу, для работы&lt;br /&gt;
которой нужна другая программа, вам захочется узнать, установлена&lt;br /&gt;
ли она в вашей системе. Чтобы выяснить местонахождение программы&lt;br /&gt;
и ее man-страницы, наберите whereis [имя программы]. Так, например,&lt;br /&gt;
находится расположение популярного текстового редактора vi:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 whereis vi&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Echo – небольшая команда, повторяющая все, что вы ни напечатали. Например, если набрать echo hello, на экране появится слово &amp;quot;hello&amp;quot;.&lt;br /&gt;
Вообще говоря, обычно это делать незачем: команда echo может пригодиться вам в будущем, если вы начнете писать скрипты. (Скрипт – это&lt;br /&gt;
небольшая программа, позволяющая выполнить несколько команд за&lt;br /&gt;
один раз.) В скриптах  echo может использоваться для отображения&lt;br /&gt;
действий скрипта в каждый момент времени, или чтобы попросить&lt;br /&gt;
пользователя что-нибудь сделать, например, ввести текст.&lt;br /&gt;
Команда  last выведет список пользователей, заходивших сегодня в систему, и терминалы, которые они используют (использовали).&lt;br /&gt;
Набрав  exit, вы завершите сеанс работы с терминалом. Если нужно&lt;br /&gt;
зайти в систему под другим пользователем, используйте вместо нее&lt;br /&gt;
команду logout.&lt;br /&gt;
&lt;br /&gt;
=== Часть 1: По Grep’у! ===&lt;br /&gt;
Вот теперь повеселимся! Grep – команда, которая находит слова в &lt;br /&gt;
файлах. Охотно сказала бы, что ее название произошло от слова &lt;br /&gt;
&amp;quot;поиск&amp;quot; по-клингонски, но это было бы неправдой и только укрепило бы стереотип, что все технари любят Star Trek! На самом деле &lt;br /&gt;
название команды – сокращение от &amp;quot;Глобальный Парсер Регулярных &lt;br /&gt;
Выражений&amp;quot; (Global Regular Expression Parser), что означает &amp;quot;глобальный поиск строк, соответствующих регулярному выражению, и их &lt;br /&gt;
вывод на экран&amp;quot;. Название команды происходит от команды текстового &lt;br /&gt;
редактора ed g/re/p, выполняющей подобные действия.&lt;br /&gt;
Начнем с создания специального каталога, где будем размещать новые &lt;br /&gt;
файлы. Чтобы убедиться, что каталог создан, используйте команду ls.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mkdir Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Откроем текстовый редактор и создадим новый файл report1.txt:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico report1.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Pico – это текстовый редактор, который я использовала при написании &lt;br /&gt;
этой статьи. В дистрибутив Linux включено несколько текстовых редакторов; выбор одного из них определяется лишь вашими предпочтениями и наличием у редактора специальных функций, которые помогут &lt;br /&gt;
в решении именно вашей задачи. Когда текстовый редактор откроется, &lt;br /&gt;
напечатайте слово CompanyABC. Затем точно так же создайте второй &lt;br /&gt;
файл с именем report2.txt, который будет содержать слово companyabc. &lt;br /&gt;
Закончив, введите команду ls, и вы увидите примерно такой список:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music report1.txt report2.txt Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что файлы, которые мы создали, находятся рядом &lt;br /&gt;
с каталогом Work. Давайте переместим их в нужный каталог:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mv report*.txt /home/probert/Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Звездочка (*) – это специальный символ, который позволяет нам &lt;br /&gt;
делать все, что мы хотим, с файлами, название которых начинается со &lt;br /&gt;
слова  report; каждый из таких файлов включается в команду. У меня &lt;br /&gt;
есть правила именования файлов и разделения их на категории, которых я строго придерживаюсь. Например, названия всех файлов отчетов &lt;br /&gt;
начинаются со слова report, счетов – со слова invoice и т.д. Пускай это &lt;br /&gt;
выглядит как ритуальные действия безнадежно больного ОКР, зато при &lt;br /&gt;
наличии методичного подхода нужные вещи находятся очень быстро!&lt;br /&gt;
Переместимся в каталог Work и снова используем ls, чтобы убедиться,&lt;br /&gt;
что все файлы перемещены:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cd Work&lt;br /&gt;
 probert@ubuntu:~/Work$ ls&lt;br /&gt;
 report1.txt report2.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Сейчас мы сделаем следующий шаг в поисках этого крайне важного &lt;br /&gt;
файла для нашего коллеги. Команда grep обладает множеством опций &lt;br /&gt;
(их список выведет команда man grep). Опция -r позволяет выполнить &lt;br /&gt;
рекурсивный поиск файлов, начиная с названного каталога, а опция  -i &lt;br /&gt;
выполнит поиск без учета регистра. Попробуйте следующие команды с &lt;br /&gt;
опцией -i и без -i и посмотрите, как это повлияет на результаты поиска.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~/Work$ grep -r -i ‘CompanyABC’ /home/&lt;br /&gt;
 probert/Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 /home/probert/Work/report1.txt:CompanyABC&lt;br /&gt;
 /home/probert/Work/report2.txt:companyabc&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Итак, мы нашли этот неуловимый файл; что же дальше?&lt;br /&gt;
&lt;br /&gt;
=== Часть 2: Стандартный ввод-вывод ===&lt;br /&gt;
Стандартный ввод/вывод позволяет вводить данные в программу из&lt;br /&gt;
любого источника и выводить данные в любой источник. Таким образом, можно направить вывод одной команды непосредственно на ввод&lt;br /&gt;
другой команды... правда, мило? Linux предоставляет три канала ввода/вывода, более известных как потоки ввода/вывода. По умолчанию стандартный ввод подразумевает клавиатуру, стандартный вывод – экран.&lt;br /&gt;
Третий поток ввода/вывода – это на самом деле поток вывода для сообщений об ошибках, предупреждений и оповещений: так легче отличить&lt;br /&gt;
сообщения об ошибках от остальных сообщений. Поток ошибок обычно&lt;br /&gt;
также выводится на экран, но (как и каждый из трех стандартных потоков) может быть перенаправлен. Этим мы сейчас и займемся.&lt;br /&gt;
Есть два основных способа перенаправления потоков данных; мы&lt;br /&gt;
можем использовать &amp;gt; или | (перенаправление и каналы соответственно). Если нужно просто направить стандартный вывод в файл, можно&lt;br /&gt;
напечатать команда &amp;gt; файл. Давайте попробуем это на реальном примере: найдем все файлы с именем passwd в каталоге /etc. Наберите&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 find /etc -name passwd &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким (он зависит от особенностей вашего&lt;br /&gt;
дистрибутива Linux):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что команда генерирует как стандартный поток&lt;br /&gt;
вывода, так и поток ошибок. Сейчас мы создадим файл  findresult и&lt;br /&gt;
перенаправим стандартный поток вывода в этот файл, оставив на экране только ошибки.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd &amp;gt; findresult&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Перенаправим эти ошибки в другой файл, finderrors, используя 2&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt; finderrors&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Наберите ls, и вы получите результат, похожий на мой.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples finderrors findresult LAN Music&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Помощь по grep (вырезка) ====&lt;br /&gt;
Поскольку  grep производит поиск соответствий по шаблонам, вы &lt;br /&gt;
должны предоставить ему регулярное выражение для этого шаблона. &lt;br /&gt;
Регулярные выражения бывают простыми и сложными. Наиболее распространенные (и простые) типы регулярных выражений выглядят так:&lt;br /&gt;
*abc Соответствует строкам, которые содержат &amp;quot;abc&amp;quot; в любом месте.&lt;br /&gt;
*^abc Соответствует строкам, начинающимся с &amp;quot;abc&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Чтобы прочитать содержимое этих файлов, можно открыть их в текстовом редакторе pico:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Я предпочитаю просматривать небольшие файлы с помощью команды &lt;br /&gt;
cat. Ниже я использовала эту команду для просмотра результатов поиска в файлах findresult и finderrors.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cat findresult&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 probert@ubuntu:~$ cat finderrors&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы также можете добавить информацию в файл с помощью команды &lt;br /&gt;
&amp;gt;&amp;gt;. Давайте перенаправим стандартный вывод, чтобы добавить информацию в наш первый файл findresult следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt;&amp;gt; findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы можете снова проверить результаты с помощью команды  cat &lt;br /&gt;
findresult. Второй способ перенаправления потоков – вывод одной &lt;br /&gt;
команды прямо на вход другой (канализация). Давайте проверим &lt;br /&gt;
содержимое каталога  /usr/lib, где находятся объектные файлы, библиотеки и системные двоичные файлы. В моем каталоге  /usr/lib примерно полторы тысячи файлов – многовато, чтобы прокручивать этот &lt;br /&gt;
список один за другим! Если мы перенаправим вывод ls на ввод команды less, то получим список, в котором можно перемещаться по страницам, в удобном для нас темпе. Попробуйте:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Достигнув конца документа, нажмите клавишу  Q, чтобы вернуться в &lt;br /&gt;
командную строку. Вы также можете предварительно отсортировать &lt;br /&gt;
этот список по убыванию, например, таким образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | sort -r | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Краеугольный камень философии Unix заключается в том, чтобы каждая программа делала что-то одно по-настоящему хорошо, позволяя &lt;br /&gt;
использовать свой вывод как ввод другой программы. Использование &lt;br /&gt;
каналов позволяет провести этот принцип в жизнь, создавая очень &lt;br /&gt;
эффективные цепочки команд.&lt;br /&gt;
Теперь, разузнав, как работают  grep и каналы, сведем их вместе для &lt;br /&gt;
поиска того самого отчета и отправим его нашему коллеге:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat report1.txt | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Миссия завершена!&lt;br /&gt;
&lt;br /&gt;
==== Мини-проект: команды для умных ====&lt;br /&gt;
Есть несколько общих команд, о которых &lt;br /&gt;
полезно знать. Привожу некоторые из них без &lt;br /&gt;
объяснений; эти команды можно использовать &lt;br /&gt;
независимо от дополнительных опций. &lt;br /&gt;
Наберите их и посмотрите на результат.&lt;br /&gt;
date   df&lt;br /&gt;
date +%D    free&lt;br /&gt;
date +%T     du&lt;br /&gt;
cal   top&lt;br /&gt;
cal 1066    ps&lt;br /&gt;
&lt;br /&gt;
Через месяц Moнтирование, создание резервных копий, распаковка файлов из tar и zip.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Bash</id>
		<title>LXF97:Bash</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Bash"/>
				<updated>2008-03-08T17:39:36Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: /* Часть 1: По Grep’у! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bash: Используем командную строку ==&lt;br /&gt;
''Часть 2 Хотите проводить в командной строке больше времени? '''Рэйчел Проберт'''&lt;br /&gt;
расскажет о grep, pipe и других командах, которые обязательно надо знать.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы говорили о действиях, потенциально способных &lt;br /&gt;
отобрать много времени: например, необходимо быстро найти отчет, &lt;br /&gt;
написанный когда-то давно. Вы забыли имя файла, но помните, что &lt;br /&gt;
темой отчета было соглашение с компанией ABC. После обнаружения &lt;br /&gt;
документа его содержимое нужно отправить коллеге или шефу.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat filename | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Для начала мы разомнемся с помощью нескольких команд для &lt;br /&gt;
опытных пользователей. Они вряд ли пригодятся обычным пользователям для каждодневной работы, но если вы администратор системы &lt;br /&gt;
и устанавливаете программы для своих пользователей, значение этих &lt;br /&gt;
команд повышается.&lt;br /&gt;
Команда  whoami не вовлечет вас в философские дискуссии по &lt;br /&gt;
самопознанию, но напомнит, под каким именем пользователя вы вошли в систему; очень удобно, когда вы работаете с несколькими учетными записями, используемыми для решения различных задач, и постоянно переключаетесь между ними. Похожая команда, whatis, позволит &lt;br /&gt;
понять, что делает та или иная программа. В Linux сотни программ, и &lt;br /&gt;
невозможно запомнить, что делает каждая из них. Например, напечатав whatis grep, вы увидите:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep (1) - print lines matching a pattern&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Команда whereis поможет найти другие нужные вам команды или&lt;br /&gt;
программы. Если вы загружаете из Интернета программу, для работы&lt;br /&gt;
которой нужна другая программа, вам захочется узнать, установлена&lt;br /&gt;
ли она в вашей системе. Чтобы выяснить местонахождение программы&lt;br /&gt;
и ее man-страницы, наберите whereis [имя программы]. Так, например,&lt;br /&gt;
находится расположение популярного текстового редактора vi:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 whereis vi&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Echo – небольшая команда, повторяющая все, что вы ни напечатали. Например, если набрать echo hello, на экране появится слово &amp;quot;hello&amp;quot;.&lt;br /&gt;
Вообще говоря, обычно это делать незачем: команда echo может пригодиться вам в будущем, если вы начнете писать скрипты. (Скрипт – это&lt;br /&gt;
небольшая программа, позволяющая выполнить несколько команд за&lt;br /&gt;
один раз.) В скриптах  echo может использоваться для отображения&lt;br /&gt;
действий скрипта в каждый момент времени, или чтобы попросить&lt;br /&gt;
пользователя что-нибудь сделать, например, ввести текст.&lt;br /&gt;
Команда  last выведет список пользователей, заходивших сегодня в систему, и терминалы, которые они используют (использовали).&lt;br /&gt;
Набрав  exit, вы завершите сеанс работы с терминалом. Если нужно&lt;br /&gt;
зайти в систему под другим пользователем, используйте вместо нее&lt;br /&gt;
команду logout.&lt;br /&gt;
&lt;br /&gt;
=== Часть 1: По Grep’у! ===&lt;br /&gt;
Вот теперь повеселимся! Grep – команда, которая находит слова в &lt;br /&gt;
файлах. Охотно сказала бы, что ее название произошло от слова &lt;br /&gt;
&amp;quot;поиск&amp;quot; по-клингонски, но это было бы неправдой и только укрепило бы стереотип, что все технари любят Star Trek! На самом деле &lt;br /&gt;
название команды – сокращение от &amp;quot;Глобальный Парсер Регулярных &lt;br /&gt;
Выражений&amp;quot; (Global Regular Expression Parser), что означает &amp;quot;глобальный поиск строк, соответствующих регулярному выражению, и их &lt;br /&gt;
вывод на экран&amp;quot;. Название команды происходит от команды текстового &lt;br /&gt;
редактора ed g/re/p, выполняющей подобные действия.&lt;br /&gt;
Начнем с создания специального каталога, где будем размещать новые &lt;br /&gt;
файлы. Чтобы убедиться, что каталог создан, используйте команду ls.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mkdir Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Откроем текстовый редактор и создадим новый файл report1.txt:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico report1.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Pico – это текстовый редактор, который я использовала при написании &lt;br /&gt;
этой статьи. В дистрибутив Linux включено несколько текстовых редакторов; выбор одного из них определяется лишь вашими предпочтениями и наличием у редактора специальных функций, которые помогут &lt;br /&gt;
в решении именно вашей задачи. Когда текстовый редактор откроется, &lt;br /&gt;
напечатайте слово CompanyABC. Затем точно так же создайте второй &lt;br /&gt;
файл с именем report2.txt, который будет содержать слово companyabc. &lt;br /&gt;
Закончив, введите команду ls, и вы увидите примерно такой список:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music report1.txt report2.txt Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что файлы, которые мы создали, находятся рядом &lt;br /&gt;
с каталогом Work. Давайте переместим их в нужный каталог:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mv report*.txt /home/probert/Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Звездочка (*) – это специальный символ, который позволяет нам &lt;br /&gt;
делать все, что мы хотим, с файлами, название которых начинается со &lt;br /&gt;
слова  report; каждый из таких файлов включается в команду. У меня &lt;br /&gt;
есть правила именования файлов и разделения их на категории, которых я строго придерживаюсь. Например, названия всех файлов отчетов &lt;br /&gt;
начинаются со слова report, счетов – со слова invoice и т.д. Пускай это &lt;br /&gt;
выглядит как ритуальные действия безнадежно больного ОКР, зато при &lt;br /&gt;
наличии методичного подхода нужные вещи находятся очень быстро!&lt;br /&gt;
Переместимся в каталог Work и снова используем ls, чтобы убедиться,&lt;br /&gt;
что все файлы перемещены:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cd Work&lt;br /&gt;
 probert@ubuntu:~/Work$ ls&lt;br /&gt;
 report1.txt report2.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Сейчас мы сделаем следующий шаг в поисках этого крайне важного &lt;br /&gt;
файла для нашего коллеги. Команда grep обладает множеством опций &lt;br /&gt;
(их список выведет команда man grep). Опция -r позволяет выполнить &lt;br /&gt;
рекурсивный поиск файлов, начиная с названного каталога, а опция  -i &lt;br /&gt;
выполнит поиск без учета регистра. Попробуйте следующие команды с &lt;br /&gt;
опцией -i и без -i и посмотрите, как это повлияет на результаты поиска.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~/Work$ grep -r -i ‘CompanyABC’ /home/&lt;br /&gt;
 probert/Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 /home/probert/Work/report1.txt:CompanyABC&lt;br /&gt;
 /home/probert/Work/report2.txt:companyabc&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Итак, мы нашли этот неуловимый файл; что же дальше?&lt;br /&gt;
&lt;br /&gt;
=== Часть 2: Стандартный ввод-вывод ===&lt;br /&gt;
Стандартный ввод/вывод позволяет вводить данные в программу из&lt;br /&gt;
любого источника и выводить данные в любой источник. Таким образом, можно направить вывод одной команды непосредственно на ввод&lt;br /&gt;
другой команды... правда, мило? Linux предоставляет три канала ввода/вывода, более известных как потоки ввода/вывода. По умолчанию стандартный ввод подразумевает клавиатуру, стандартный вывод – экран.&lt;br /&gt;
Третий поток ввода/вывода – это на самом деле поток вывода для сообщений об ошибках, предупреждений и оповещений: так легче отличить&lt;br /&gt;
сообщения об ошибках от остальных сообщений. Поток ошибок обычно&lt;br /&gt;
также выводится на экран, но (как и каждый из трех стандартных потоков) может быть перенаправлен. Этим мы сейчас и займемся.&lt;br /&gt;
Есть два основных способа перенаправления потоков данных; мы&lt;br /&gt;
можем использовать &amp;gt; или | (перенаправление и каналы соответственно). Если нужно просто направить стандартный вывод в файл, можно&lt;br /&gt;
напечатать команда &amp;gt; файл. Давайте попробуем это на реальном примере: найдем все файлы с именем passwd в каталоге /etc. Наберите&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 find /etc -name passwd &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким (он зависит от особенностей вашего&lt;br /&gt;
дистрибутива Linux):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что команда генерирует как стандартный поток&lt;br /&gt;
вывода, так и поток ошибок. Сейчас мы создадим файл  findresult и&lt;br /&gt;
перенаправим стандартный поток вывода в этот файл, оставив на экране только ошибки.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd &amp;gt; findresult&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Перенаправим эти ошибки в другой файл, finderrors, используя 2&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt; finderrors&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Наберите ls, и вы получите результат, похожий на мой.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples finderrors findresult LAN Music&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Помощь по grep (вырезка) ====&lt;br /&gt;
Поскольку  grep производит поиск соответствий по шаблонам, вы &lt;br /&gt;
должны предоставить ему регулярное выражение для этого шаблона. &lt;br /&gt;
Регулярные выражения бывают простыми и сложными. Наиболее распространенные (и простые) типы регулярных выражений выглядят так:&lt;br /&gt;
*abc Соответствует строкам, которые содержат “abc” в любом месте.&lt;br /&gt;
*^abc Соответствует строкам, начинающимся с “abc”.&lt;br /&gt;
&lt;br /&gt;
Чтобы прочитать содержимое этих файлов, можно открыть их в текстовом редакторе pico:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Я предпочитаю просматривать небольшие файлы с помощью команды &lt;br /&gt;
cat. Ниже я использовала эту команду для просмотра результатов поиска в файлах findresult и finderrors.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cat findresult&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 probert@ubuntu:~$ cat finderrors&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы также можете добавить информацию в файл с помощью команды &lt;br /&gt;
&amp;gt;&amp;gt;. Давайте перенаправим стандартный вывод, чтобы добавить информацию в наш первый файл findresult следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt;&amp;gt; findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы можете снова проверить результаты с помощью команды  cat &lt;br /&gt;
findresult. Второй способ перенаправления потоков – вывод одной &lt;br /&gt;
команды прямо на вход другой (канализация). Давайте проверим &lt;br /&gt;
содержимое каталога  /usr/lib, где находятся объектные файлы, библиотеки и системные двоичные файлы. В моем каталоге  /usr/lib примерно полторы тысячи файлов – многовато, чтобы прокручивать этот &lt;br /&gt;
список один за другим! Если мы перенаправим вывод ls на ввод команды less, то получим список, в котором можно перемещаться по страницам, в удобном для нас темпе. Попробуйте:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Достигнув конца документа, нажмите клавишу  Q, чтобы вернуться в &lt;br /&gt;
командную строку. Вы также можете предварительно отсортировать &lt;br /&gt;
этот список по убыванию, например, таким образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | sort -r | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Краеугольный камень философии Unix заключается в том, чтобы каждая программа делала что-то одно по-настоящему хорошо, позволяя &lt;br /&gt;
использовать свой вывод как ввод другой программы. Использование &lt;br /&gt;
каналов позволяет провести этот принцип в жизнь, создавая очень &lt;br /&gt;
эффективные цепочки команд.&lt;br /&gt;
Теперь, разузнав, как работают  grep и каналы, сведем их вместе для &lt;br /&gt;
поиска того самого отчета и отправим его нашему коллеге:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat report1.txt | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Миссия завершена!&lt;br /&gt;
&lt;br /&gt;
==== Мини-проект: команды для умных ====&lt;br /&gt;
Есть несколько общих команд, о которых &lt;br /&gt;
полезно знать. Привожу некоторые из них без &lt;br /&gt;
объяснений; эти команды можно использовать &lt;br /&gt;
независимо от дополнительных опций. &lt;br /&gt;
Наберите их и посмотрите на результат.&lt;br /&gt;
date   df&lt;br /&gt;
date +%D    free&lt;br /&gt;
date +%T     du&lt;br /&gt;
cal   top&lt;br /&gt;
cal 1066    ps&lt;br /&gt;
&lt;br /&gt;
Через месяц Moнтирование, создание резервных копий, распаковка файлов из tar и zip.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Bash</id>
		<title>LXF97:Bash</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Bash"/>
				<updated>2008-03-08T17:38:38Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bash: Используем командную строку ==&lt;br /&gt;
''Часть 2 Хотите проводить в командной строке больше времени? '''Рэйчел Проберт'''&lt;br /&gt;
расскажет о grep, pipe и других командах, которые обязательно надо знать.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы говорили о действиях, потенциально способных &lt;br /&gt;
отобрать много времени: например, необходимо быстро найти отчет, &lt;br /&gt;
написанный когда-то давно. Вы забыли имя файла, но помните, что &lt;br /&gt;
темой отчета было соглашение с компанией ABC. После обнаружения &lt;br /&gt;
документа его содержимое нужно отправить коллеге или шефу.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat filename | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Для начала мы разомнемся с помощью нескольких команд для &lt;br /&gt;
опытных пользователей. Они вряд ли пригодятся обычным пользователям для каждодневной работы, но если вы администратор системы &lt;br /&gt;
и устанавливаете программы для своих пользователей, значение этих &lt;br /&gt;
команд повышается.&lt;br /&gt;
Команда  whoami не вовлечет вас в философские дискуссии по &lt;br /&gt;
самопознанию, но напомнит, под каким именем пользователя вы вошли в систему; очень удобно, когда вы работаете с несколькими учетными записями, используемыми для решения различных задач, и постоянно переключаетесь между ними. Похожая команда, whatis, позволит &lt;br /&gt;
понять, что делает та или иная программа. В Linux сотни программ, и &lt;br /&gt;
невозможно запомнить, что делает каждая из них. Например, напечатав whatis grep, вы увидите:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep (1) - print lines matching a pattern&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Команда whereis поможет найти другие нужные вам команды или&lt;br /&gt;
программы. Если вы загружаете из Интернета программу, для работы&lt;br /&gt;
которой нужна другая программа, вам захочется узнать, установлена&lt;br /&gt;
ли она в вашей системе. Чтобы выяснить местонахождение программы&lt;br /&gt;
и ее man-страницы, наберите whereis [имя программы]. Так, например,&lt;br /&gt;
находится расположение популярного текстового редактора vi:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 whereis vi&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Echo – небольшая команда, повторяющая все, что вы ни напечатали. Например, если набрать echo hello, на экране появится слово &amp;quot;hello&amp;quot;.&lt;br /&gt;
Вообще говоря, обычно это делать незачем: команда echo может пригодиться вам в будущем, если вы начнете писать скрипты. (Скрипт – это&lt;br /&gt;
небольшая программа, позволяющая выполнить несколько команд за&lt;br /&gt;
один раз.) В скриптах  echo может использоваться для отображения&lt;br /&gt;
действий скрипта в каждый момент времени, или чтобы попросить&lt;br /&gt;
пользователя что-нибудь сделать, например, ввести текст.&lt;br /&gt;
Команда  last выведет список пользователей, заходивших сегодня в систему, и терминалы, которые они используют (использовали).&lt;br /&gt;
Набрав  exit, вы завершите сеанс работы с терминалом. Если нужно&lt;br /&gt;
зайти в систему под другим пользователем, используйте вместо нее&lt;br /&gt;
команду logout.&lt;br /&gt;
&lt;br /&gt;
=== Часть 1: По Grep’у! ===&lt;br /&gt;
Вот теперь повеселимся! Grep – команда, которая находит слова в &lt;br /&gt;
файлах. Охотно сказала бы, что ее название произошло от слова &lt;br /&gt;
&amp;quot;поиск&amp;quot; по-клингонски, но это было бы неправдой и только укрепило бы стереотип, что все технари любят Star Trek! На самом деле &lt;br /&gt;
название команды – сокращение от &amp;quot;Глобальный Парсер Регулярных &lt;br /&gt;
Выражений&amp;quot; (Global Regular Expression Parser), что означает &amp;quot;глобальный поиск строк, соответствующих регулярному выражению, и их &lt;br /&gt;
вывод на экран&amp;quot;. Название команды происходит от команды текстового &lt;br /&gt;
редактора ed g/re/p, выполняющей подобные действия.&lt;br /&gt;
Начнем с создания специального каталога, где будем размещать новые &lt;br /&gt;
файлы. Чтобы убедиться, что каталог создан, используйте команду ls.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mkdir Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Откроем текстовый редактор и создадим новый файл report1.txt:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico report1.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Pico – это текстовый редактор, который я использовала при написании &lt;br /&gt;
этой статьи. В дистрибутив Linux включено несколько текстовых редакторов; выбор одного из них определяется лишь вашими предпочтениями и наличием у редактора специальных функций, которые помогут &lt;br /&gt;
в решении именно вашей задачи. Когда текстовый редактор откроется, &lt;br /&gt;
напечатайте слово CompanyABC. Затем точно так же создайте второй &lt;br /&gt;
файл с именем report2.txt, который будет содержать слово companyabc. &lt;br /&gt;
Закончив, введите команду ls, и вы увидите примерно такой список:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music report1.txt report2.txt Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что файлы, которые мы создали, находятся рядом &lt;br /&gt;
с каталогом Work. Давайте переместим их в нужный каталог:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ mv report*.txt /home/probert/Work&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples LAN Music Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Звездочка (*) – это специальный символ, который позволяет нам &lt;br /&gt;
делать все, что мы хотим, с файлами, название которых начинается со &lt;br /&gt;
слова  report; каждый из таких файлов включается в команду. У меня &lt;br /&gt;
есть правила именования файлов и разделения их на категории, кото-&lt;br /&gt;
рых я строго придерживаюсь. Например, названия всех файлов отчетов &lt;br /&gt;
начинаются со слова report, счетов – со слова invoice и т.д. Пускай это &lt;br /&gt;
выглядит как ритуальные действия безнадежно больного ОКР, зато при &lt;br /&gt;
наличии методичного подхода нужные вещи находятся очень быстро!&lt;br /&gt;
Переместимся в каталог Work и снова используем ls, чтобы убедиться,&lt;br /&gt;
что все файлы перемещены:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cd Work&lt;br /&gt;
 probert@ubuntu:~/Work$ ls&lt;br /&gt;
 report1.txt report2.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Сейчас мы сделаем следующий шаг в поисках этого крайне важного &lt;br /&gt;
файла для нашего коллеги. Команда grep обладает множеством опций &lt;br /&gt;
(их список выведет команда man grep). Опция -r позволяет выполнить &lt;br /&gt;
рекурсивный поиск файлов, начиная с названного каталога, а опция  -i &lt;br /&gt;
выполнит поиск без учета регистра. Попробуйте следующие команды с &lt;br /&gt;
опцией -i и без -i и посмотрите, как это повлияет на результаты поиска.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~/Work$ grep -r -i ‘CompanyABC’ /home/&lt;br /&gt;
 probert/Work&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 /home/probert/Work/report1.txt:CompanyABC&lt;br /&gt;
 /home/probert/Work/report2.txt:companyabc&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Итак, мы нашли этот неуловимый файл; что же дальше?&lt;br /&gt;
&lt;br /&gt;
=== Часть 2: Стандартный ввод-вывод ===&lt;br /&gt;
Стандартный ввод/вывод позволяет вводить данные в программу из&lt;br /&gt;
любого источника и выводить данные в любой источник. Таким образом, можно направить вывод одной команды непосредственно на ввод&lt;br /&gt;
другой команды... правда, мило? Linux предоставляет три канала ввода/вывода, более известных как потоки ввода/вывода. По умолчанию стандартный ввод подразумевает клавиатуру, стандартный вывод – экран.&lt;br /&gt;
Третий поток ввода/вывода – это на самом деле поток вывода для сообщений об ошибках, предупреждений и оповещений: так легче отличить&lt;br /&gt;
сообщения об ошибках от остальных сообщений. Поток ошибок обычно&lt;br /&gt;
также выводится на экран, но (как и каждый из трех стандартных потоков) может быть перенаправлен. Этим мы сейчас и займемся.&lt;br /&gt;
Есть два основных способа перенаправления потоков данных; мы&lt;br /&gt;
можем использовать &amp;gt; или | (перенаправление и каналы соответственно). Если нужно просто направить стандартный вывод в файл, можно&lt;br /&gt;
напечатать команда &amp;gt; файл. Давайте попробуем это на реальном примере: найдем все файлы с именем passwd в каталоге /etc. Наберите&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 find /etc -name passwd &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Результат будет примерно таким (он зависит от особенностей вашего&lt;br /&gt;
дистрибутива Linux):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Обратите внимание, что команда генерирует как стандартный поток&lt;br /&gt;
вывода, так и поток ошибок. Сейчас мы создадим файл  findresult и&lt;br /&gt;
перенаправим стандартный поток вывода в этот файл, оставив на экране только ошибки.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd &amp;gt; findresult&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Перенаправим эти ошибки в другой файл, finderrors, используя 2&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt; finderrors&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Наберите ls, и вы получите результат, похожий на мой.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ ls&lt;br /&gt;
 Bin Desktop Examples finderrors findresult LAN Music&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Помощь по grep (вырезка) ====&lt;br /&gt;
Поскольку  grep производит поиск соответствий по шаблонам, вы &lt;br /&gt;
должны предоставить ему регулярное выражение для этого шаблона. &lt;br /&gt;
Регулярные выражения бывают простыми и сложными. Наиболее распространенные (и простые) типы регулярных выражений выглядят так:&lt;br /&gt;
*abc Соответствует строкам, которые содержат “abc” в любом месте.&lt;br /&gt;
*^abc Соответствует строкам, начинающимся с “abc”.&lt;br /&gt;
&lt;br /&gt;
Чтобы прочитать содержимое этих файлов, можно открыть их в текстовом редакторе pico:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ pico findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Я предпочитаю просматривать небольшие файлы с помощью команды &lt;br /&gt;
cat. Ниже я использовала эту команду для просмотра результатов поиска в файлах findresult и finderrors.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ cat findresult&lt;br /&gt;
 /etc/passwd&lt;br /&gt;
 /etc/pam.d/passwd&lt;br /&gt;
 probert@ubuntu:~$ cat finderrors&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы также можете добавить информацию в файл с помощью команды &lt;br /&gt;
&amp;gt;&amp;gt;. Давайте перенаправим стандартный вывод, чтобы добавить информацию в наш первый файл findresult следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 probert@ubuntu:~$ find /etc -name passwd 2&amp;gt;&amp;gt; findresult&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вы можете снова проверить результаты с помощью команды  cat &lt;br /&gt;
findresult. Второй способ перенаправления потоков – вывод одной &lt;br /&gt;
команды прямо на вход другой (канализация). Давайте проверим &lt;br /&gt;
содержимое каталога  /usr/lib, где находятся объектные файлы, библиотеки и системные двоичные файлы. В моем каталоге  /usr/lib примерно полторы тысячи файлов – многовато, чтобы прокручивать этот &lt;br /&gt;
список один за другим! Если мы перенаправим вывод ls на ввод команды less, то получим список, в котором можно перемещаться по страницам, в удобном для нас темпе. Попробуйте:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Достигнув конца документа, нажмите клавишу  Q, чтобы вернуться в &lt;br /&gt;
командную строку. Вы также можете предварительно отсортировать &lt;br /&gt;
этот список по убыванию, например, таким образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ls /usr/lib | sort -r | less&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Краеугольный камень философии Unix заключается в том, чтобы каждая программа делала что-то одно по-настоящему хорошо, позволяя &lt;br /&gt;
использовать свой вывод как ввод другой программы. Использование &lt;br /&gt;
каналов позволяет провести этот принцип в жизнь, создавая очень &lt;br /&gt;
эффективные цепочки команд.&lt;br /&gt;
Теперь, разузнав, как работают  grep и каналы, сведем их вместе для &lt;br /&gt;
поиска того самого отчета и отправим его нашему коллеге:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat report1.txt | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Миссия завершена!&lt;br /&gt;
&lt;br /&gt;
==== Мини-проект: команды для умных ====&lt;br /&gt;
Есть несколько общих команд, о которых &lt;br /&gt;
полезно знать. Привожу некоторые из них без &lt;br /&gt;
объяснений; эти команды можно использовать &lt;br /&gt;
независимо от дополнительных опций. &lt;br /&gt;
Наберите их и посмотрите на результат.&lt;br /&gt;
date   df&lt;br /&gt;
date +%D    free&lt;br /&gt;
date +%T     du&lt;br /&gt;
cal   top&lt;br /&gt;
cal 1066    ps&lt;br /&gt;
&lt;br /&gt;
Через месяц Moнтирование, создание резервных копий, распаковка файлов из tar и zip.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Bash</id>
		<title>LXF97:Bash</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Bash"/>
				<updated>2008-03-08T17:20:35Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: == Bash: Используем == ''Часть 2 Хотите проводить в командной строке больше времени? '''Рэйчел Проберт''' расс...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bash: Используем ==&lt;br /&gt;
''Часть 2 Хотите проводить в командной строке больше времени? '''Рэйчел Проберт'''&lt;br /&gt;
расскажет о grep, pipe и других командах, которые обязательно надо знать.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы говорили о действиях, потенциально способных &lt;br /&gt;
отобрать много времени: например, необходимо быстро найти отчет, &lt;br /&gt;
написанный когда-то давно. Вы забыли имя файла, но помните, что &lt;br /&gt;
темой отчета было соглашение с компанией ABC. После обнаружения &lt;br /&gt;
документа его содержимое нужно отправить коллеге или шефу.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep -r -i -H CompanyABC /home/rjprobert/work&lt;br /&gt;
 cat filename | mail colleague@work.com&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Для начала мы разомнемся с помощью нескольких команд для &lt;br /&gt;
опытных пользователей. Они вряд ли пригодятся обычным пользова-&lt;br /&gt;
телям для каждодневной работы, но если вы администратор системы &lt;br /&gt;
и устанавливаете программы для своих пользователей, значение этих &lt;br /&gt;
команд повышается.&lt;br /&gt;
Команда  whoami не вовлечет вас в философские дискуссии по &lt;br /&gt;
самопознанию, но напомнит, под каким именем пользователя вы вош-&lt;br /&gt;
ли в систему; очень удобно, когда вы работаете с несколькими учетны-&lt;br /&gt;
ми записями, используемыми для решения различных задач, и посто-&lt;br /&gt;
янно переключаетесь между ними. Похожая команда, whatis, позволит &lt;br /&gt;
понять, что делает та или иная программа. В Linux сотни программ, и &lt;br /&gt;
невозможно запомнить, что делает каждая из них. Например, напеча-&lt;br /&gt;
тав whatis grep, вы увидите:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grep (1) - print lines matching a pattern&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Команда whereis поможет найти другие нужные вам команды или&lt;br /&gt;
программы. Если вы загружаете из Интернета программу, для работы&lt;br /&gt;
которой нужна другая программа, вам захочется узнать, установлена&lt;br /&gt;
ли она в вашей системе. Чтобы выяснить местонахождение программы&lt;br /&gt;
и ее man-страницы, наберите whereis [имя программы]. Так, например,&lt;br /&gt;
находится расположение популярного текстового редактора vi:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 whereis vi&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Echo – небольшая команда, повторяющая все, что вы ни напечата-&lt;br /&gt;
ли. Например, если набрать echo hello, на экране появится слово &amp;quot;hello&amp;quot;.&lt;br /&gt;
Вообще говоря, обычно это делать незачем: команда echo может при-&lt;br /&gt;
годиться вам в будущем, если вы начнете писать скрипты. (Скрипт – это&lt;br /&gt;
небольшая программа, позволяющая выполнить несколько команд за&lt;br /&gt;
один раз.) В скриптах  echo может использоваться для отображения&lt;br /&gt;
действий скрипта в каждый момент времени, или чтобы попросить&lt;br /&gt;
пользователя что-нибудь сделать, например, ввести текст.&lt;br /&gt;
Команда  last выведет список пользователей, заходивших сегод-&lt;br /&gt;
ня в систему, и терминалы, которые они используют (использовали).&lt;br /&gt;
Набрав  exit, вы завершите сеанс работы с терминалом. Если нужно&lt;br /&gt;
зайти в систему под другим пользователем, используйте вместо нее&lt;br /&gt;
команду logout.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
в процессе написания..&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97</id>
		<title>LXF97</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97"/>
				<updated>2008-03-08T11:35:41Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: /* Linux Format 97 (10), Октябрь 2007 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Linux Format 97 (10), Октябрь 2007==&lt;br /&gt;
&lt;br /&gt;
=== Обзоры ===&lt;br /&gt;
* [[LXF97:eSys PC|eSys PC]]&lt;br /&gt;
* [[LXF97:Google Desktop|Google Desktop]]&lt;br /&gt;
* [[LXF97:Yellow Dog PS 3|Yellow Dog PS 3]]&lt;br /&gt;
* [[LXF97:MailEnforcer 3.0|MailEnforcer 3.0]]&lt;br /&gt;
* [[LXF97:Paragon NTFS|Paragon NTFS]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[LXF97:Сравнение|Сравнение: IRC-клиенты]]&lt;br /&gt;
&lt;br /&gt;
[[LXF97:Ubuntu|Битва за лучший Ubuntu]]&lt;br /&gt;
&lt;br /&gt;
[[LXF97:Игры|Какова цена свободы?]]&lt;br /&gt;
&lt;br /&gt;
[[LXF97:Пережить Slashdot-эффект|Пережить Slashdot-эффект]]&lt;br /&gt;
&lt;br /&gt;
[[LXF97:OpenMoko|Что за штука? OpenMoko]]&lt;br /&gt;
&lt;br /&gt;
[[LXF97:Служба доменных имен|Служба доменных имен]]&lt;br /&gt;
&lt;br /&gt;
=== Учебники ===&lt;br /&gt;
* [[LXF97:Первые шаги|Первые шаги]]&lt;br /&gt;
Откладывай на завтра то, что можешь&lt;br /&gt;
сделать сегодня, но делай это с умом –&lt;br /&gt;
'''Энди Ченнел''' подскажет, как не навредить&lt;br /&gt;
и выкроить минутку для отдыха.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Bash|Bash]]&lt;br /&gt;
Сегодня '''Рэйчел Проберт''' познакомит вас&lt;br /&gt;
с командой grep и каналами, а также&lt;br /&gt;
даст пару советов, достойных&lt;br /&gt;
продвинутых пользователей.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Python|Python]]&lt;br /&gt;
Зачем мучиться с графическим&lt;br /&gt;
приложением, когда для сортировки&lt;br /&gt;
файлов можно использовать Python?&lt;br /&gt;
'''Ник Вейч''' покажет, как.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Командная строка|Командная строка]]&lt;br /&gt;
'''Крис Браун''' знает, как построить из&lt;br /&gt;
невзрачных кирпичей прекрасный&lt;br /&gt;
дворец. Соберите с виду бесполезные&lt;br /&gt;
утилиты в единое целое и наслаждайтесь&lt;br /&gt;
всей мощью Linux!&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Mono|Mono]]&lt;br /&gt;
За приятной внешностью '''Пола Хадсона'''&lt;br /&gt;
скрывается убежденный параноик.&lt;br /&gt;
Зашифруйте с его помощью все самое&lt;br /&gt;
ценное – пока у вас еще есть такая&lt;br /&gt;
возможность...&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Hardcore Linux|Hardcore Linux]]&lt;br /&gt;
Даже двенадцати тысячам пакетов&lt;br /&gt;
Gentoo не испугать '''Нейла Ботвика'''!&lt;br /&gt;
Получите максимум от этого&lt;br /&gt;
дистрибутива под его чутким&lt;br /&gt;
руководством.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Java|Java]]&lt;br /&gt;
Магия Java: всего на нескольких&lt;br /&gt;
страницах '''Александр Бабаев''' напишет&lt;br /&gt;
приличный почтовый клиент и простой&lt;br /&gt;
графический интерфейс к нему.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:GtkSourceView|GtkSourceView]]&lt;br /&gt;
Каждый программист в своей жизни&lt;br /&gt;
должен написать текстовый редактор, и&lt;br /&gt;
желательно помощнее. '''Петр Семилетов'''&lt;br /&gt;
уже справился с этой задачей и готов&lt;br /&gt;
поделиться своим опытом.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Новая серия!|Новая серия!]]&lt;br /&gt;
Нет, вы не открыли по ошибке журнал&lt;br /&gt;
&amp;quot;Наш Сад&amp;quot;! '''Андрей Паскаль''' начинает&lt;br /&gt;
серию статей о свободной учетной&lt;br /&gt;
системе, доступной в Linux.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Hibernate|Hibernate]]&lt;br /&gt;
Не ждите, пока запустится система –&lt;br /&gt;
просто откройте ноутбук и продолжайте&lt;br /&gt;
работать! '''Сергей Яремчук''' посоветует,&lt;br /&gt;
как правильно пожелать вашему Linux&lt;br /&gt;
спокойной ночи.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Препресс в Linux|Препресс в Linux]]&lt;br /&gt;
Мы подобрались к самому&lt;br /&gt;
интересному – '''Александр Чернышов'''&lt;br /&gt;
запасся пленкой и готов к выходу на&lt;br /&gt;
офсет!&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:TeX|TeX]]&lt;br /&gt;
В течение месяца ломали голову, как&lt;br /&gt;
подружить Linux с любовно настроенной&lt;br /&gt;
в прошлый раз точкой доступа? '''Андрей&lt;br /&gt;
Боровский''' знает ответ.&lt;br /&gt;
&lt;br /&gt;
[[LXF97:Ответы|Ответы]]&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97</id>
		<title>LXF97</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97"/>
				<updated>2008-03-08T11:22:42Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: ==Linux Format 97 (10), Октябрь 2007==  === Обзоры === * eSys PC * Google Desktop * Yellow Dog PS 3 * [[...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Linux Format 97 (10), Октябрь 2007==&lt;br /&gt;
&lt;br /&gt;
=== Обзоры ===&lt;br /&gt;
* [[LXF97:eSys PC|eSys PC]]&lt;br /&gt;
* [[LXF97:Google Desktop|Google Desktop]]&lt;br /&gt;
* [[LXF97:Yellow Dog PS 3|Yellow Dog PS 3]]&lt;br /&gt;
* [[LXF97:MailEnforcer 3.0|MailEnforcer 3.0]]&lt;br /&gt;
* [[LXF97:Paragon NTFS|Paragon NTFS]]&lt;br /&gt;
&lt;br /&gt;
=== Учебники ===&lt;br /&gt;
* [[LXF97:Первые шаги|Первые шаги]]&lt;br /&gt;
Откладывай на завтра то, что можешь&lt;br /&gt;
сделать сегодня, но делай это с умом –&lt;br /&gt;
'''Энди Ченнел''' подскажет, как не навредить&lt;br /&gt;
и выкроить минутку для отдыха.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Bash|Bash]]&lt;br /&gt;
Сегодня '''Рэйчел Проберт''' познакомит вас&lt;br /&gt;
с командой grep и каналами, а также&lt;br /&gt;
даст пару советов, достойных&lt;br /&gt;
продвинутых пользователей.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Python|Python]]&lt;br /&gt;
Зачем мучиться с графическим&lt;br /&gt;
приложением, когда для сортировки&lt;br /&gt;
файлов можно использовать Python?&lt;br /&gt;
'''Ник Вейч''' покажет, как.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Командная строка|Командная строка]]&lt;br /&gt;
'''Крис Браун''' знает, как построить из&lt;br /&gt;
невзрачных кирпичей прекрасный&lt;br /&gt;
дворец. Соберите с виду бесполезные&lt;br /&gt;
утилиты в единое целое и наслаждайтесь&lt;br /&gt;
всей мощью Linux!&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Mono|Mono]]&lt;br /&gt;
За приятной внешностью '''Пола Хадсона'''&lt;br /&gt;
скрывается убежденный параноик.&lt;br /&gt;
Зашифруйте с его помощью все самое&lt;br /&gt;
ценное – пока у вас еще есть такая&lt;br /&gt;
возможность...&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Hardcore Linux|Hardcore Linux]]&lt;br /&gt;
Даже двенадцати тысячам пакетов&lt;br /&gt;
Gentoo не испугать '''Нейла Ботвика'''!&lt;br /&gt;
Получите максимум от этого&lt;br /&gt;
дистрибутива под его чутким&lt;br /&gt;
руководством.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Java|Java]]&lt;br /&gt;
Магия Java: всего на нескольких&lt;br /&gt;
страницах '''Александр Бабаев''' напишет&lt;br /&gt;
приличный почтовый клиент и простой&lt;br /&gt;
графический интерфейс к нему.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:GtkSourceView|GtkSourceView]]&lt;br /&gt;
Каждый программист в своей жизни&lt;br /&gt;
должен написать текстовый редактор, и&lt;br /&gt;
желательно помощнее. '''Петр Семилетов'''&lt;br /&gt;
уже справился с этой задачей и готов&lt;br /&gt;
поделиться своим опытом.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Новая серия!|Новая серия!]]&lt;br /&gt;
Нет, вы не открыли по ошибке журнал&lt;br /&gt;
&amp;quot;Наш Сад&amp;quot;! '''Андрей Паскаль''' начинает&lt;br /&gt;
серию статей о свободной учетной&lt;br /&gt;
системе, доступной в Linux.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Hibernate|Hibernate]]&lt;br /&gt;
Не ждите, пока запустится система –&lt;br /&gt;
просто откройте ноутбук и продолжайте&lt;br /&gt;
работать! '''Сергей Яремчук''' посоветует,&lt;br /&gt;
как правильно пожелать вашему Linux&lt;br /&gt;
спокойной ночи.&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Препресс в Linux|Препресс в Linux]]&lt;br /&gt;
Мы подобрались к самому&lt;br /&gt;
интересному – '''Александр Чернышов'''&lt;br /&gt;
запасся пленкой и готов к выходу на&lt;br /&gt;
офсет!&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:TeX|TeX]]&lt;br /&gt;
В течение месяца ломали голову, как&lt;br /&gt;
подружить Linux с любовно настроенной&lt;br /&gt;
в прошлый раз точкой доступа? '''Андрей&lt;br /&gt;
Боровский''' знает ответ.&lt;br /&gt;
&lt;br /&gt;
[[LXF97:Ответы|Ответы]]&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Unix_API</id>
		<title>LXF84:Unix API</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Unix_API"/>
				<updated>2008-03-07T20:34:02Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Сигналы ==&lt;br /&gt;
''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения '''SIGKILL''' система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса '''SIG''', за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал '''SIGHUP''' (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал '''SIGHUP''' посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение '''SIGHUP''' демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал '''SIGINT''' (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш ''Ctrl-C'') .&lt;br /&gt;
*Сигнал '''SIGABRT''' (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал '''SIGKILL''' (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал '''SIGSEGV''' (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал '''SIGTERM''' (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение '''SIGTERM''' свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал '''SIGCHLD''' (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал '''SIGCHLD''' игнорируется.&lt;br /&gt;
*Сигнал '''SIGCONT''' (номер 18) возобновляет выполнение процесса, остановленного сигналом '''SIGSTOP'''. Сигнал '''SIGSTOP''' (номер 19) приостанавливает выполнение процесса. Как и '''SIGKILL''', этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал '''SIGTSTP''' (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал '''SIGIO/SIGPOLL''' (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, '''SIGUSR1''' (в Linux – номер 10) и '''SIGUSR2''' (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 void term_handler(int i) {&lt;br /&gt;
   printf (&amp;quot;Terminating\n&amp;quot;);&lt;br /&gt;
   exit(EXIT_SUCCESS);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main(int argc, char ** argv) {&lt;br /&gt;
   struct sigaction sa;&lt;br /&gt;
   sigset_t newset;&lt;br /&gt;
   sigemptyset(&amp;amp;newset);&lt;br /&gt;
   sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
   sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
   sa.sa_handler = term_handler; &lt;br /&gt;
   sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
   printf(&amp;quot;My pid is %i\n&amp;quot;, getpid()); &lt;br /&gt;
   printf(&amp;quot;Waiting...\n&amp;quot;); &lt;br /&gt;
   while(1)&lt;br /&gt;
     sleep(1); &lt;br /&gt;
   return EXIT_FAILURE;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал '''SIGTERM''' (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала '''SIGTERM''' term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – '''SIGTERM''', может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу '''SIGTERM''' означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала '''SIGTERM'''. В принципе, вы можете придать сигналу '''SIGTERM''' совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик '''SIGTERM''' предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction.&lt;br /&gt;
&lt;br /&gt;
Поля структуры '''sigaction''':&lt;br /&gt;
*sa_handler - Значение Указатель на функцию обработчик сигнала или константа&lt;br /&gt;
*sa_mask - Маска сигналов, блокируемых на время вызова обработчика&lt;br /&gt;
*sa_flags - Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа '''SIG_IGN''' указывает, что сигнал следует игнорировать, а константа '''SIG_DFL''' – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле '''sa_mask''' позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр '''sa_flags''' позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг '''SA_RESETHAND''' указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала '''SIGTERM'''. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал '''SIGTERM''' приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы '''SIGINT''' и '''SIGABRT''' – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 kill &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа '''SIG_BLOCK''' указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа '''SIG_SETMASK''' указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа '''SIG_UNBLOCK''' указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал '''SIGHUP''' и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал '''SIGHUP''' вы можете с помощью консольной команды&lt;br /&gt;
&amp;lt;'''Полужирное начертание'''code&amp;gt;&lt;br /&gt;
 kill –s 1 &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала '''SIGHUP''' (файл swdemo.c на компакт-диске):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 sigprocmask(SIG_BLOCK, &amp;amp;newset, 0);&lt;br /&gt;
 while(!sigwait(&amp;amp;newset, &amp;amp;sig))&lt;br /&gt;
   printf(&amp;quot;SIGHUP recieved\n&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал '''SIGHUP''', распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 sigset_t sset;&lt;br /&gt;
 int sig;&lt;br /&gt;
 ...&lt;br /&gt;
 sigfillset(&amp;amp;sset);&lt;br /&gt;
 sigdelset(&amp;amp;sset, SIGTERM);&lt;br /&gt;
 sigprocmask(SIG_SETMASK, &amp;amp;sset, 0);&lt;br /&gt;
 while(!sigwait(&amp;amp;sset, &amp;amp;sig))&lt;br /&gt;
   printf(&amp;quot;Signal %i - %s\n&amp;quot;, sig, sys_siglist[sig]);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала '''SIGTERM''' (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме '''SIGTERM''' (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры '''sigaction''':&lt;br /&gt;
*PID &amp;gt; 1 - Сигнал посылается процессу с соответствующим PID.&lt;br /&gt;
*PID == 0 - Сигнал посылается всем процессам из той же группы, что и процесс-источник.&lt;br /&gt;
*PID &amp;lt; 0 - Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID.&lt;br /&gt;
*PID == 1 - Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 raise(sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
эквивалентен вызову&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 kill(getpid(), sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
#D. P. Bovet, M. Cesati, '''Understanding the Linux Kernel, 3rd Edition, O’Reilly''', 2005&lt;br /&gt;
#W. R. Stevens, S. A. Rago, '''Advanced Programming in the UNIX® Environment: Second Edition''', Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
'''Через месяц''' Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Unix_API</id>
		<title>LXF84:Unix API</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Unix_API"/>
				<updated>2008-03-07T20:32:13Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Сигналы ==&lt;br /&gt;
''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения '''SIGKILL''' система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса '''SIG''', за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал '''SIGHUP''' (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал '''SIGHUP''' посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение '''SIGHUP''' демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал '''SIGINT''' (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш ''Ctrl-C'') .&lt;br /&gt;
*Сигнал '''SIGABRT''' (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал '''SIGKILL''' (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал '''SIGSEGV''' (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал '''SIGTERM''' (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение '''SIGTERM''' свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал '''SIGCHLD''' (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал '''SIGCHLD''' игнорируется.&lt;br /&gt;
*Сигнал '''SIGCONT''' (номер 18) возобновляет выполнение процесса, остановленного сигналом '''SIGSTOP'''. Сигнал '''SIGSTOP''' (номер 19) приостанавливает выполнение процесса. Как и '''SIGKILL''', этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал '''SIGTSTP''' (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал '''SIGIO/SIGPOLL''' (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, '''SIGUSR1''' (в Linux – номер 10) и '''SIGUSR2''' (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 void term_handler(int i) {&lt;br /&gt;
   printf (&amp;quot;Terminating\n&amp;quot;);&lt;br /&gt;
   exit(EXIT_SUCCESS);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main(int argc, char ** argv) {&lt;br /&gt;
   struct sigaction sa;&lt;br /&gt;
   sigset_t newset;&lt;br /&gt;
   sigemptyset(&amp;amp;newset);&lt;br /&gt;
   sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
   sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
   sa.sa_handler = term_handler; &lt;br /&gt;
   sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
   printf(&amp;quot;My pid is %i\n&amp;quot;, getpid()); &lt;br /&gt;
   printf(&amp;quot;Waiting...\n&amp;quot;); &lt;br /&gt;
   while(1)&lt;br /&gt;
     sleep(1); &lt;br /&gt;
   return EXIT_FAILURE;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал '''SIGTERM''' (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала '''SIGTERM''' term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – '''SIGTERM''', может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу '''SIGTERM''' означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала '''SIGTERM'''. В принципе, вы можете придать сигналу '''SIGTERM''' совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик '''SIGTERM''' предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction.&lt;br /&gt;
&lt;br /&gt;
Поля структуры '''sigaction''':&lt;br /&gt;
*sa_handler - Значение Указатель на функцию обработчик сигнала или константа&lt;br /&gt;
*sa_mask - Маска сигналов, блокируемых на время вызова обработчика&lt;br /&gt;
*sa_flags - Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа '''SIG_IGN''' указывает, что сигнал следует игнорировать, а константа '''SIG_DFL''' – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле '''sa_mask''' позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр '''sa_flags''' позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг '''SA_RESETHAND''' указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала SIGTERM. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал SIGTERM приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы SIGINT и SIGABRT – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 kill &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа '''SIG_BLOCK''' указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа '''SIG_SETMASK''' указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа '''SIG_UNBLOCK''' указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал '''SIGHUP''' и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал '''SIGHUP''' вы можете с помощью консольной команды&lt;br /&gt;
&amp;lt;'''Полужирное начертание'''code&amp;gt;&lt;br /&gt;
 kill –s 1 &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала '''SIGHUP''' (файл swdemo.c на компакт-диске):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 sigprocmask(SIG_BLOCK, &amp;amp;newset, 0);&lt;br /&gt;
 while(!sigwait(&amp;amp;newset, &amp;amp;sig))&lt;br /&gt;
   printf(&amp;quot;SIGHUP recieved\n&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал '''SIGHUP''', распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 sigset_t sset;&lt;br /&gt;
 int sig;&lt;br /&gt;
 ...&lt;br /&gt;
 sigfillset(&amp;amp;sset);&lt;br /&gt;
 sigdelset(&amp;amp;sset, SIGTERM);&lt;br /&gt;
 sigprocmask(SIG_SETMASK, &amp;amp;sset, 0);&lt;br /&gt;
 while(!sigwait(&amp;amp;sset, &amp;amp;sig))&lt;br /&gt;
   printf(&amp;quot;Signal %i - %s\n&amp;quot;, sig, sys_siglist[sig]);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала '''SIGTERM''' (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме '''SIGTERM''' (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры '''sigaction''':&lt;br /&gt;
*PID &amp;gt; 1 - Сигнал посылается процессу с соответствующим PID.&lt;br /&gt;
*PID == 0 - Сигнал посылается всем процессам из той же группы, что и процесс-источник.&lt;br /&gt;
*PID &amp;lt; 0 - Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID.&lt;br /&gt;
*PID == 1 - Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 raise(sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
эквивалентен вызову&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 kill(getpid(), sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
#D. P. Bovet, M. Cesati, '''Understanding the Linux Kernel, 3rd Edition, O’Reilly''', 2005&lt;br /&gt;
#W. R. Stevens, S. A. Rago, '''Advanced Programming in the UNIX® Environment: Second Edition''', Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
'''Через месяц''' Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Java</id>
		<title>LXF84:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Java"/>
				<updated>2008-03-07T19:54:40Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Отмена правки № 71 участника OWeRQ (обсуждение)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Сказка Java ==&lt;br /&gt;
''ЧАСТЬ 1: От кофеварок до промышленных серверов и биллинговых систем - Java можно встретить буквально везде. Начните изучение этой технологии вместе с '''Антоном Черноусовым'''.''&lt;br /&gt;
&lt;br /&gt;
Начиная ряд статей о программировании на объектно-ориентированном языке Java, хотел бы выразить свое мнение относительно корпоративного рынка разработки программного обеспечения, на котором в данный момент борются за лидерство два гиганта, две платформы: J2EE и .NET.&lt;br /&gt;
&lt;br /&gt;
В основе платформы J2EE лежит язык программирования Java – приложения, созданные с его помощью, являются кроссплатформенными, сам язык, средства разработки и технология активно поддерживаются многими корпорациями: Sun, Google, IBM, Oracle, BEA. Платформа пользуется большой популярностью и среди компаний, ориентированных на OpenSource, таких как Apache Foundation. В противовес J2EE, корпорация Microsoft предлагает свою технологию .NET, которая является колоссом, построенным на мощи программного обеспечения Microsoft.&lt;br /&gt;
&lt;br /&gt;
Сегодня еще нельзя сказать, какая технология станет доминирующей, и, возможно, от вас зависит скорость распространения современной кроссплатформенной технологии создания приложений J2EE и языка программирования Java.&lt;br /&gt;
&lt;br /&gt;
Предложенные вашему вниманию уроки позволят овладеть основными понятиями ООЯ Java и создавать различные приложения с его помощью. Рассмотрев основы языка, мы сможем изучить типовые решения (паттерны) в программировании и приступить к изучению J2EE.&lt;br /&gt;
В первом уроке мы создадим свое первое приложение и разберемся с основными понятиями: инкапсуляция, наследование и полиморфизм. Для выполнения этого урока нам понадобится пакет Java SDK 1.5, текстовый редактор и немного терпения.&lt;br /&gt;
=== Героический объект ===&lt;br /&gt;
Приступая к этой серии материалов, я вспомнил, что, как правило, изучение языков программирования начинается с написания приложения «Hello World!», но такой прием настолько изъезжен, что я намереваюсь предложить пример поинтереснее: мы напишем приложение, рассказывающее сказку. Основа приложения – два класса. Каждый класс содержит члены двух видов: атрибуты и методы. Атрибуты – это данные, принадлежащие самому классу. Совокупное значение атрибутов определяет состояние объекта или класса. Метод – это последовательность операторов, изменяющих значения атрибутов и, как следствие, состояние класса или объекта.&lt;br /&gt;
&lt;br /&gt;
В каждой интересной сказке должен быть свой герой. Предлагаю взглянуть на класс, который реализует нашего героя. Итак, по порядку. Следующий код необходимо сохранить в файл '''FirstHero.java.'''&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public class FirstHero {&lt;br /&gt;
   private String quest;&lt;br /&gt;
   public FirstHero(String Quest) {&lt;br /&gt;
     this.quest = Quest;&lt;br /&gt;
   }&lt;br /&gt;
   public void setQuest(String Quest){&lt;br /&gt;
     this.quest = Quest;&lt;br /&gt;
   };&lt;br /&gt;
   public String getQuest(){&lt;br /&gt;
     return quest;&lt;br /&gt;
   };&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Расположение одного класса в одном файле считается хорошим тоном среди программистов на Java – так что приучайтесь к нему сразу. Имя файла должно совпадать с названием класса, расширение у файла – '''.java.'''&lt;br /&gt;
&lt;br /&gt;
Первый созданный нами класс содержит один защищенный атрибут (private – модификатор, зарезервированное слово, которое обеспечивает возможность обращения к члену класса только внутри класса) и три открытых метода (public – модификатор, зарезервированное слово, которое обеспечивает возможность обращения к члену класса из любого другого класса.). Хорошо спроектированный класс не имеет открытых атрибутов, что позволяет быть уверенным в правильной работе с ними. Доступ к защищенным атрибутам осуществляется через открытые методы. Такая организация класса позволяет разработчику через методы реализовать различные проверки и исключить неправильное поведение объекта. Класс представляет собой объединение атрибутов и методов в единое целое – подобное объединение называется инкапсуляцией.&lt;br /&gt;
&lt;br /&gt;
Вы можете заметить, что первый метод (третья строка представленного ранее листинга) имеет то же название, что и класс – FirstHero. Такой метод называется конструктором. Конструктор – это метод, который используется при создании экземпляра класса для задания внутреннего состояния объекта, например:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 FirstHero ourNewHero = new FirstHero(“Спасти царевну”);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Единственный атрибут нашего класса quest имеет тип строка (String). Для установки значения атрибута quest используется метод&lt;br /&gt;
setQuest. Метод setQuest является public и не возвращает никакого значения. Для обозначения методов, не возвращающих значение, используется зарезервированное слово void. Для вызова метода setQuest необходим обязательный параметр: Quest типа String. Для получения значения атрибута quest используется метод getQuest, который вызывается без параметров, является открытым и возвращает значение типа String.&lt;br /&gt;
&lt;br /&gt;
Вызов описанных выше методов для объекта ourNewHero осуществляется следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ourNewHero.getQuest();&lt;br /&gt;
 ourNewHero.setQuest(“какая-то строка”);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Парные методы, различающиеся приставками set и get, принято создавать для работы с закрытыми атрибутами. Это обязательное&lt;br /&gt;
условие для реализации объекта в виде JavaBean. Что такое JavaBean, мы обсудим позже – сейчас запомните, что такое наименование методов позволяет избавиться от ряда проблем в больших системах.&lt;br /&gt;
&lt;br /&gt;
Приступим к написанию самой сказки. Возьмите следующий код и поместите его в файл '''Story.java'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public class Story {&lt;br /&gt;
   public static void main(String[] args) {&lt;br /&gt;
     FirstHero ourNewHero = new FirstHero(“Спасти царевну “);&lt;br /&gt;
     System.out.println(“Наш герой хочет отправиться в путь и “ + ourNewHero.getQuest());&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это класс Story, он имеет всего один метод main, который является статичным (static-методы и переменные принято называть переменными класса и методами класса, т.к. они общие для всех объектов) и используется для работы с классом в целом. Метод main – это стартовая точка для запуска программы, с которой начинается интерпретация кода.&lt;br /&gt;
&lt;br /&gt;
В ходе интерпретации метода main создается новый объект ourNewHero, а также вызывается метод println объекта out, который обеспечивает вывод в стандартный выходной поток строковойпеременной.&lt;br /&gt;
&lt;br /&gt;
Откомпилируем код и увидим, что у нас получилось. Для компиляции переместитесь в каталог, где вы разместили свои файлы и выполните следующую команду:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 # javac *.java&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
При желании вы можете откомпилировать классы по отдельности, следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 # javac Story.java&lt;br /&gt;
 # javac FirstHero.java&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
В итоге вы получите два файла '''Story.class''' и '''FirstHero.class'''. Теперь посмотрим на результат:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 # java Story&lt;br /&gt;
 Наш герой хочет отправиться в квест и Спасти царевну&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Первая программа на Java готова и работает! Вы создали два класса и научились выводить информацию в консоль. Но мы забыли о&lt;br /&gt;
комментариях...&lt;br /&gt;
&lt;br /&gt;
Комментарии бывают нескольких типов:&lt;br /&gt;
*Строчные начинаются с символа // и длятся до окончания строки.&lt;br /&gt;
*Многострочные комментарии заключаются между /* и */.&lt;br /&gt;
*Комментарии JavaDoc – это многострочные комментарии, заключенные между /** и */, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 /**&lt;br /&gt;
  * Класс является прототипом объекта “герой”&lt;br /&gt;
  * @author Chernousov Anton&lt;br /&gt;
  * @version 0.1&lt;br /&gt;
  */&lt;br /&gt;
 public class FirstHero {&lt;br /&gt;
 …&lt;br /&gt;
 /**&lt;br /&gt;
    * Метод предназначен для установки внутренней переменной&lt;br /&gt;
 quest&lt;br /&gt;
    * в значение Quest.&lt;br /&gt;
    * У этого метода один параметр&lt;br /&gt;
    * @param Quest это переменная означает задание для Героя&lt;br /&gt;
    */&lt;br /&gt;
   public void setQuest(String Quest)&lt;br /&gt;
 …&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Комментарии JavaDoc предназначены для формирования документации к проекту из исходных кодов. Если добавить в файл '''FirstHero.java''' только что приведенные строки, то с помощью команды '''javadoc -author -version *.java''' можно сформировать документацию к нашему проекту.&lt;br /&gt;
&lt;br /&gt;
JavaDoc позволяет создавать подробную документацию, которая просто необходима для любого достаточно крупного проекта.&lt;br /&gt;
=== Наследование, интерфейсы и их реализация ===&lt;br /&gt;
Наша сказка написана, но что делать, если проект большой и над ним работает много людей? Как реализовать одновременное программирование разных классов так, чтобы результаты, полученные отдельными разработчиками, можно было без труда соединить в единое целое? Для решения этой задачи, а также задачи множественного наследования в Java существуют интерфейсы – interface. Но обо всем по порядку.&lt;br /&gt;
&lt;br /&gt;
Наследование – это одна из парадигм программирования, которая связана с инкапсуляцией. Суть наследования заключается в следующем: если есть класс, инкапсулирующий в себе некоторые атрибуты и методы, то класс, наследующий его, автоматически наследует все его атрибуты и методы.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public class SecondHero extends FirstHero{&lt;br /&gt;
   public SecondHero(String Quest) {&lt;br /&gt;
     super(Quest + “ Несмеяну”);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Расположенный выше код объявляет класс SecondHero, который с помощью зарезервированного слова extends наследует (расширяет) класс FirstHero. В Java класс может наследовать (расширять)только один класс. При наследовании класса FirstHero, содержащего&lt;br /&gt;
конструктор, обязательно требуется переопределить его (например, как это делается в методе SecondHero). При выполнении оператора super(Quest) будет вызван аналогичный метод из суперкласса (класс-родителя). Строкой super(Quest + “Несмеяну”) мы переопределяем поведение конструктора. Естественно, класс SecondHero может содержать новые атрибуты и методы.&lt;br /&gt;
&lt;br /&gt;
Для проверки механизма наследования сохраните приведенный текст класса SecondHero в файл '''SecondHero.java''' и в файле '''Story.java''' измените имя класса FirstHero на SecondHero. Откомпилируйте и запустите программу, в результате вы должны увидеть следующее:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 # java Story&lt;br /&gt;
 Наш герой хочет отправиться в путь и Спасти царевну Несмеяну&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
При разработке программы, перед тем, как приступить к программированию, сначала проводится процесс проектирования (например, через UML-нотации). В результате проектирования появляется документация к проекту, а также спецификации классов. Интерфейс – это явно указанная спецификация набора методов, которые должны быть представлены в классе, реализующий эту спецификацию. В серьезном проекте на момент начала программирования перед программистом оказываются интерфейсы, которые он должен реализовать в классах.&lt;br /&gt;
&lt;br /&gt;
Интерфейс в Java – это специальный класс, в котором отсутствует реализация! Давайте напишем интерфейс для нашего класса FirstHero. Следует скопировать следующий далее код и поместить его в файл '''Hero.java''' – именно этот интерфейс мы будет использован далее. Как вы видите, в отличие от других классов, интерфейс объявляется с помощью зарезервированного слова interface. В нашем случае интерфейс представляет собой следующий набор методов:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public interface Hero {&lt;br /&gt;
   public void setQuest(String Quest);&lt;br /&gt;
   public String getQuest();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Чтобы класс FirstHero реализовывал интерфейс Hero, необходимо изменить первую строчку в файле '''FirstHero.java''' на public class FirstHero implements Hero {. Интерфейс может наследовать (расширять) множество других интерфейсов. Наример:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public interface Lord {&lt;br /&gt;
   public String sendToQuest();&lt;br /&gt;
   public void setBodyguard(Hero hisHero);&lt;br /&gt;
   public Hero getBodyguard();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 public interface King extends Hero, Lord{&lt;br /&gt;
   public void setWife (String PrincesName);&lt;br /&gt;
   public String getWife();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Класс может одновременно наследовать класс и реализовывать один или несколько интерфейсов. Например, как в классе LandLord,&lt;br /&gt;
который наследует класс FirstHero и реализует интерфейс Lord:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public class LandLord extends FirstHero implements Lord{&lt;br /&gt;
   private Hero bodyguard;&lt;br /&gt;
   public LandLord(String Quest, Hero hisHero) {&lt;br /&gt;
     super(Quest);&lt;br /&gt;
     this.bodyguard = hisHero;&lt;br /&gt;
   }&lt;br /&gt;
   public String sendToQuest() {&lt;br /&gt;
     bodyguard.setQuest(this.getQuest());&lt;br /&gt;
     return null;&lt;br /&gt;
   }&lt;br /&gt;
   public void setBodyguard(Hero hisHero) {&lt;br /&gt;
     this.bodyguard = hisHero;&lt;br /&gt;
   }&lt;br /&gt;
   public Hero getBodyguard() {&lt;br /&gt;
     return bodyguard;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Чтобы окончательно закрыть тему наследования, необходимо поговорить про абстрактные классы – те, что занимают промежуточное&lt;br /&gt;
место между интерфейсами и реальными классами. Объявление абстрактного класса или метода выполняется с помощью специального&lt;br /&gt;
слова abstract:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 abstract public class Knight&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Абстрактный класс представляет собой неполную реализацию всех объявленных методов, и его можно наследовать, как и любой из классов. Обязательным условием при наследовании является полная реализация абстрактных методов.&lt;br /&gt;
&lt;br /&gt;
=== Полиморфизм ===&lt;br /&gt;
Полиморфизм – это концепция, реализованная в Java, которая позволяет одному и тому же объекту выступать в разных формах. Например, экземпляр класс LandLord можно использовать как объект класса FirstHero. Это стало возможным благодаря тому, что класс LandLord наследует класса FirstHero.&lt;br /&gt;
&lt;br /&gt;
=== Перегруженные методы ===&lt;br /&gt;
Иногда при создании сложных (и не очень) систем есть необходимость реализовать два различных метода, названых одинаково – это возможно с помощью перегруженных (overloading) методов. Выбор реализации зависит от типа объектов, переданных в качестве параметров.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public class GreatKing extends LandLord implements King{&lt;br /&gt;
   private String wife;&lt;br /&gt;
   private boolean theftedWife;&lt;br /&gt;
 &lt;br /&gt;
   public GreatKing(String Quest, Hero hisHero) {&lt;br /&gt;
     super(Quest, hisHero);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   public void setWife(String PrincesName) {&lt;br /&gt;
     this.wife = PrincesName;&lt;br /&gt;
     this.theftedWife = false;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   public String getWife() {&lt;br /&gt;
     if (theftedWife){return null;}&lt;br /&gt;
     else{ return wife;}&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   public String getWife(boolean flag) {&lt;br /&gt;
     if (flag){ this.theftedWife = true;}&lt;br /&gt;
     return wife;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
В представленном классе GreatKing существуют две реализации перезагруженного метода getWife, которые можно вызвать следующим образом:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 GreatKing ourKing = new GreatKing(“Править мудро”, (Hero) new FirstHero(“Охранять господина”));&lt;br /&gt;
 String hisWife = ourKing.getWife();&lt;br /&gt;
 String theftedHisWife = ourKing.getWife(true);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вместо заключения ===&lt;br /&gt;
Ну вот, мы создали всех героев. Разместите интерфейсы Lord, King, а также классы LandLord и GreatKing в соответствующих файлах.&lt;br /&gt;
Немного измените класс Story, чтобы завершить сказку:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public class Story {&lt;br /&gt;
   public static void main(String[] args) {&lt;br /&gt;
     // создадим наших героев&lt;br /&gt;
     Hero ourNewHero = (Hero) new FirstHero(“Спасити царевну”);&lt;br /&gt;
     GreatKing ourKing = new GreatKing(“Править мудро”, (Hero) new FirstHero(“Охранять господина”));&lt;br /&gt;
     LandLord ourNewLandLord = new LandLord(“Похитить царевну”, (Hero) new FirstHero(“Охранять господина”));&lt;br /&gt;
     // Женим нашего короля&lt;br /&gt;
     ourKing.setWife(“Несмеяна”);&lt;br /&gt;
     // И начнем повествование&lt;br /&gt;
     System.out.println(“Жил был мудрый король, и должен был он “ + ourKing.getQuest());&lt;br /&gt;
     System.out.println(“Была у него жена, и звали ее “ + ourKing.getWife());&lt;br /&gt;
     System.out.println(“Был в королевстве коварный Визирь и хотел он “ + ourNewLandLord.getQuest());&lt;br /&gt;
     System.out.println(“И сделал это”);&lt;br /&gt;
     String wife = ourKing.getWife(true);&lt;br /&gt;
     //&lt;br /&gt;
     System.out.println(“А наш герой жаждал “ + ourNewHero.getQuest() + “ ..и добился этого”);&lt;br /&gt;
     ourKing.setWife(wife);&lt;br /&gt;
     System.out.println(“Король был счастлив.”);&lt;br /&gt;
     System.out.println(“Ну а что случилось дальше вы можете придумать сами...”);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Откомпилируйте и насладитесь результатом выполнения урока.&lt;br /&gt;
&lt;br /&gt;
В следующей статье мы поговорим о простых числах и других типах, вычислениях, циклах, массивах и списках.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Unix_API</id>
		<title>LXF84:Unix API</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Unix_API"/>
				<updated>2008-03-07T17:42:47Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Сигналы ==&lt;br /&gt;
''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения SIGKILL система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса SIG, за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал SIGHUP (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал SIGHUP посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение SIGHUP демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал SIGINT (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш Ctrl-C) .&lt;br /&gt;
*Сигнал SIGABRT (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал SIGKILL (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал SIGSEGV (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал SIGTERM (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение SIGTERM свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал SIGCHLD (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал SIGCHLD игнорируется.&lt;br /&gt;
*Сигнал SIGCONT (номер 18) возобновляет выполнение процесса, остановленного сигналом SIGSTOP. Сигнал SIGSTOP (номер 19) приостанавливает выполнение процесса. Как и SIGKILL, этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал SIGTSTP (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал SIGIO/SIGPOLL (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, SIGUSR1 (в Linux – номер 10) и SIGUSR2 (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
  void term_handler(int i) {&lt;br /&gt;
    printf (&amp;quot;Terminating\n&amp;quot;);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  int main(int argc, char ** argv) {&lt;br /&gt;
    struct sigaction sa;&lt;br /&gt;
    sigset_t newset;&lt;br /&gt;
    sigemptyset(&amp;amp;newset);&lt;br /&gt;
    sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
    sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
    sa.sa_handler = term_handler; &lt;br /&gt;
    sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
    printf(&amp;quot;My pid is %i\n&amp;quot;, getpid()); &lt;br /&gt;
    printf(&amp;quot;Waiting...\n&amp;quot;); &lt;br /&gt;
    while(1)&lt;br /&gt;
      sleep(1); &lt;br /&gt;
    return EXIT_FAILURE;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал SIGTERM (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала SIGTERM term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – SIGTERM, может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу SIGTERM означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала SIGTERM. В принципе, вы можете придать сигналу SIGTERM совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик SIGTERM предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction. какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал SIGTERM приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы SIGINT и SIGABRT – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа SIG_BLOCK указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа SIG_SETMASK указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа SIG_UNBLOCK указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал SIGHUP и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал SIGHUP вы можете с помощью консольной команды&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill –s 1 &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала SIGHUP (файл swdemo.c на компакт-диске):&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле sa_handler sa_mask sa_flags Значение Указатель на функцию обработчик сигнала или константа Маска сигналов, блокируемых на время вызова обработчика Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа SIG_IGN указывает, что сигнал следует игнорировать, а константа SIG_DFL – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле sa_mask позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр sa_flags позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг SA_RESETHAND указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала SIGTERM. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigprocmask(SIG_BLOCK, &amp;amp;newset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;newset, &amp;amp;sig))&lt;br /&gt;
    printf(&amp;quot;SIGHUP recieved\n&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал SIGHUP, распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigset_t sset;&lt;br /&gt;
  int sig;&lt;br /&gt;
  ...&lt;br /&gt;
  sigfillset(&amp;amp;sset);&lt;br /&gt;
  sigdelset(&amp;amp;sset, SIGTERM);&lt;br /&gt;
  sigprocmask(SIG_SETMASK, &amp;amp;sset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;sset, &amp;amp;sig))&lt;br /&gt;
    printf(&amp;quot;Signal %i - %s\n&amp;quot;, sig, sys_siglist[sig]);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала SIGTERM (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме SIGTERM (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле PID &amp;gt; 1 PID == 0 PID &amp;lt; 0 Значение Сигнал посылается процессу с соответствующим PID. Сигнал посылается всем процессам из той же группы, что и процесс-источник. Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID. PID == 1 Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  raise(sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
эквивалентен вызову&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill(getpid(), sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
#D. P. Bovet, M. Cesati, '''Understanding the Linux Kernel, 3rd Edition, O’Reilly''', 2005&lt;br /&gt;
#W. R. Stevens, S. A. Rago, '''Advanced Programming in the UNIX® Environment: Second Edition''', Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
'''Через месяц''' Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Java</id>
		<title>LXF84:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Java"/>
				<updated>2008-03-07T17:35:43Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Сигналы ==&lt;br /&gt;
''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения SIGKILL система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса SIG, за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал SIGHUP (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал SIGHUP посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение SIGHUP демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал SIGINT (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш Ctrl-C) .&lt;br /&gt;
*Сигнал SIGABRT (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал SIGKILL (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал SIGSEGV (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал SIGTERM (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение SIGTERM свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал SIGCHLD (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал SIGCHLD игнорируется.&lt;br /&gt;
*Сигнал SIGCONT (номер 18) возобновляет выполнение процесса, остановленного сигналом SIGSTOP. Сигнал SIGSTOP (номер 19) приостанавливает выполнение процесса. Как и SIGKILL, этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал SIGTSTP (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал SIGIO/SIGPOLL (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, SIGUSR1 (в Linux – номер 10) и SIGUSR2 (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 void term_handler(int i) {&lt;br /&gt;
   printf (&amp;quot;Terminating\n&amp;quot;);&lt;br /&gt;
   exit(EXIT_SUCCESS);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main(int argc, char ** argv) {&lt;br /&gt;
   struct sigaction sa;&lt;br /&gt;
   sigset_t newset;&lt;br /&gt;
   sigemptyset(&amp;amp;newset);&lt;br /&gt;
   sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
   sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
   sa.sa_handler = term_handler; &lt;br /&gt;
   sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
   printf(&amp;quot;My pid is %i\n&amp;quot;, getpid()); &lt;br /&gt;
   printf(&amp;quot;Waiting...\n&amp;quot;); &lt;br /&gt;
   while(1) sleep(1); &lt;br /&gt;
   return EXIT_FAILURE;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал SIGTERM (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала SIGTERM term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – SIGTERM, может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу SIGTERM означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала SIGTERM. В принципе, вы можете придать сигналу SIGTERM совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик SIGTERM предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction. какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал SIGTERM приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы SIGINT и SIGABRT – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 kill &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа SIG_BLOCK указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа SIG_SETMASK указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа SIG_UNBLOCK указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал SIGHUP и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал SIGHUP вы можете с помощью консольной команды&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 kill –s 1 &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала SIGHUP (файл swdemo.c на компакт-диске):&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле sa_handler sa_mask sa_flags Значение Указатель на функцию обработчик сигнала или константа Маска сигналов, блокируемых на время вызова обработчика Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа SIG_IGN указывает, что сигнал следует игнорировать, а константа SIG_DFL – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле sa_mask позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр sa_flags позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг SA_RESETHAND указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала SIGTERM. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 sigprocmask(SIG_BLOCK, &amp;amp;newset, 0);&lt;br /&gt;
 while(!sigwait(&amp;amp;newset, &amp;amp;sig))&lt;br /&gt;
   printf(&amp;quot;SIGHUP recieved\n&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал SIGHUP, распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 sigset_t sset;&lt;br /&gt;
 int sig;&lt;br /&gt;
 ...&lt;br /&gt;
 sigfillset(&amp;amp;sset);&lt;br /&gt;
 sigdelset(&amp;amp;sset, SIGTERM);&lt;br /&gt;
 sigprocmask(SIG_SETMASK, &amp;amp;sset, 0);&lt;br /&gt;
 while(!sigwait(&amp;amp;sset, &amp;amp;sig))&lt;br /&gt;
   printf(&amp;quot;Signal %i - %s\n&amp;quot;, sig, sys_siglist[sig]);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала SIGTERM (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме SIGTERM (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле PID &amp;gt; 1 PID == 0 PID &amp;lt; 0 Значение Сигнал посылается процессу с соответствующим PID. Сигнал посылается всем процессам из той же группы, что и процесс-источник. Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID. PID == 1 Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 raise(sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
эквивалентен вызову&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 kill(getpid(), sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
#D. P. Bovet, M. Cesati, '''Understanding the Linux Kernel, 3rd Edition, O’Reilly''', 2005&lt;br /&gt;
#W. R. Stevens, S. A. Rago, '''Advanced Programming in the UNIX® Environment: Second Edition''', Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
'''Через месяц''' Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Unix_API</id>
		<title>LXF84:Unix API</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Unix_API"/>
				<updated>2008-03-07T17:33:37Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Сигналы ==&lt;br /&gt;
''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения SIGKILL система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса SIG, за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал SIGHUP (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал SIGHUP посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение SIGHUP демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал SIGINT (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш Ctrl-C) .&lt;br /&gt;
*Сигнал SIGABRT (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал SIGKILL (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал SIGSEGV (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал SIGTERM (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение SIGTERM свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал SIGCHLD (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал SIGCHLD игнорируется.&lt;br /&gt;
*Сигнал SIGCONT (номер 18) возобновляет выполнение процесса, остановленного сигналом SIGSTOP. Сигнал SIGSTOP (номер 19) приостанавливает выполнение процесса. Как и SIGKILL, этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал SIGTSTP (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал SIGIO/SIGPOLL (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, SIGUSR1 (в Linux – номер 10) и SIGUSR2 (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
  void term_handler(int i) {&lt;br /&gt;
    printf (&amp;quot;Terminating\n&amp;quot;);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  int main(int argc, char ** argv) {&lt;br /&gt;
    struct sigaction sa;&lt;br /&gt;
    sigset_t newset;&lt;br /&gt;
    sigemptyset(&amp;amp;newset);&lt;br /&gt;
    sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
    sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
    sa.sa_handler = term_handler; &lt;br /&gt;
    sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
    printf(&amp;quot;My pid is %i\n&amp;quot;, getpid()); &lt;br /&gt;
    printf(&amp;quot;Waiting...\n&amp;quot;); &lt;br /&gt;
    while(1) sleep(1); &lt;br /&gt;
    return EXIT_FAILURE;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал SIGTERM (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала SIGTERM term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – SIGTERM, может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу SIGTERM означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала SIGTERM. В принципе, вы можете придать сигналу SIGTERM совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик SIGTERM предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction. какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал SIGTERM приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы SIGINT и SIGABRT – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа SIG_BLOCK указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа SIG_SETMASK указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа SIG_UNBLOCK указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал SIGHUP и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал SIGHUP вы можете с помощью консольной команды&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill –s 1 &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала SIGHUP (файл swdemo.c на компакт-диске):&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле sa_handler sa_mask sa_flags Значение Указатель на функцию обработчик сигнала или константа Маска сигналов, блокируемых на время вызова обработчика Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа SIG_IGN указывает, что сигнал следует игнорировать, а константа SIG_DFL – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле sa_mask позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр sa_flags позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг SA_RESETHAND указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала SIGTERM. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigprocmask(SIG_BLOCK, &amp;amp;newset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;newset, &amp;amp;sig))&lt;br /&gt;
    printf(&amp;quot;SIGHUP recieved\n&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал SIGHUP, распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigset_t sset;&lt;br /&gt;
  int sig;&lt;br /&gt;
  ...&lt;br /&gt;
  sigfillset(&amp;amp;sset);&lt;br /&gt;
  sigdelset(&amp;amp;sset, SIGTERM);&lt;br /&gt;
  sigprocmask(SIG_SETMASK, &amp;amp;sset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;sset, &amp;amp;sig))&lt;br /&gt;
    printf(&amp;quot;Signal %i - %s\n&amp;quot;, sig, sys_siglist[sig]);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала SIGTERM (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме SIGTERM (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле PID &amp;gt; 1 PID == 0 PID &amp;lt; 0 Значение Сигнал посылается процессу с соответствующим PID. Сигнал посылается всем процессам из той же группы, что и процесс-источник. Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID. PID == 1 Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  raise(sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
эквивалентен вызову&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill(getpid(), sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
#D. P. Bovet, M. Cesati, '''Understanding the Linux Kernel, 3rd Edition, O’Reilly''', 2005&lt;br /&gt;
#W. R. Stevens, S. A. Rago, '''Advanced Programming in the UNIX® Environment: Second Edition''', Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
'''Через месяц''' Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Unix_API</id>
		<title>LXF84:Unix API</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Unix_API"/>
				<updated>2008-03-07T17:31:34Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Сигналы ==&lt;br /&gt;
''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения SIGKILL система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса SIG, за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал SIGHUP (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал SIGHUP посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение SIGHUP демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал SIGINT (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш Ctrl-C) .&lt;br /&gt;
*Сигнал SIGABRT (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал SIGKILL (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал SIGSEGV (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал SIGTERM (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение SIGTERM свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал SIGCHLD (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал SIGCHLD игнорируется.&lt;br /&gt;
*Сигнал SIGCONT (номер 18) возобновляет выполнение процесса, остановленного сигналом SIGSTOP. Сигнал SIGSTOP (номер 19) приостанавливает выполнение процесса. Как и SIGKILL, этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал SIGTSTP (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал SIGIO/SIGPOLL (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, SIGUSR1 (в Linux – номер 10) и SIGUSR2 (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
  void term_handler(int i) {&lt;br /&gt;
    printf (“Terminating\n”);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  int main(int argc, char ** argv) {&lt;br /&gt;
    struct sigaction sa;&lt;br /&gt;
    sigset_t newset;&lt;br /&gt;
    sigemptyset(&amp;amp;newset);&lt;br /&gt;
    sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
    sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
    sa.sa_handler = term_handler; &lt;br /&gt;
    sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
    printf(“My pid is %i\n”, getpid()); &lt;br /&gt;
    printf(“Waiting...\n”); &lt;br /&gt;
    while(1) sleep(1); &lt;br /&gt;
    return EXIT_FAILURE;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал SIGTERM (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала SIGTERM term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – SIGTERM, может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу SIGTERM означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала SIGTERM. В принципе, вы можете придать сигналу SIGTERM совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик SIGTERM предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction. какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал SIGTERM приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы SIGINT и SIGABRT – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа SIG_BLOCK указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа SIG_SETMASK указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа SIG_UNBLOCK указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал SIGHUP и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал SIGHUP вы можете с помощью консольной команды&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill –s 1 &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала SIGHUP (файл swdemo.c на компакт-диске):&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле sa_handler sa_mask sa_flags Значение Указатель на функцию обработчик сигнала или константа Маска сигналов, блокируемых на время вызова обработчика Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа SIG_IGN указывает, что сигнал следует игнорировать, а константа SIG_DFL – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле sa_mask позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр sa_flags позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг SA_RESETHAND указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала SIGTERM. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigprocmask(SIG_BLOCK, &amp;amp;newset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;newset, &amp;amp;sig))&lt;br /&gt;
    printf(“SIGHUP recieved\n”);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал SIGHUP, распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigset_t sset;&lt;br /&gt;
  int sig;&lt;br /&gt;
  ...&lt;br /&gt;
  sigfillset(&amp;amp;sset);&lt;br /&gt;
  sigdelset(&amp;amp;sset, SIGTERM);&lt;br /&gt;
  sigprocmask(SIG_SETMASK, &amp;amp;sset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;sset, &amp;amp;sig))&lt;br /&gt;
    printf(“Signal %i - %s\n”, sig, sys_siglist[sig]);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала SIGTERM (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме SIGTERM (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле PID &amp;gt; 1 PID == 0 PID &amp;lt; 0 Значение Сигнал посылается процессу с соответствующим PID. Сигнал посылается всем процессам из той же группы, что и процесс-источник. Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID. PID == 1 Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  raise(sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
эквивалентен вызову&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill(getpid(), sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
#D. P. Bovet, M. Cesati, '''Understanding the Linux Kernel, 3rd Edition, O’Reilly''', 2005&lt;br /&gt;
#W. R. Stevens, S. A. Rago, '''Advanced Programming in the UNIX® Environment: Second Edition''', Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
'''Через месяц''' Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Unix_API</id>
		<title>LXF84:Unix API</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Unix_API"/>
				<updated>2008-03-07T17:24:56Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения SIGKILL система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса SIG, за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал SIGHUP (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал SIGHUP посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение SIGHUP демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал SIGINT (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш Ctrl-C) .&lt;br /&gt;
*Сигнал SIGABRT (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал SIGKILL (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал SIGSEGV (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал SIGTERM (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение SIGTERM свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал SIGCHLD (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал SIGCHLD игнорируется.&lt;br /&gt;
*Сигнал SIGCONT (номер 18) возобновляет выполнение процесса, остановленного сигналом SIGSTOP. Сигнал SIGSTOP (номер 19) приостанавливает выполнение процесса. Как и SIGKILL, этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал SIGTSTP (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал SIGIO/SIGPOLL (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, SIGUSR1 (в Linux – номер 10) и SIGUSR2 (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
  void term_handler(int i) {&lt;br /&gt;
    printf (“Terminating\n”);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  int main(int argc, char ** argv) {&lt;br /&gt;
    struct sigaction sa;&lt;br /&gt;
    sigset_t newset;&lt;br /&gt;
    sigemptyset(&amp;amp;newset);&lt;br /&gt;
    sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
    sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
    sa.sa_handler = term_handler; &lt;br /&gt;
    sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
    printf(“My pid is %i\n”, getpid()); &lt;br /&gt;
    printf(“Waiting...\n”); &lt;br /&gt;
    while(1) sleep(1); &lt;br /&gt;
    return EXIT_FAILURE;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал SIGTERM (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала SIGTERM term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – SIGTERM, может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу SIGTERM означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала SIGTERM. В принципе, вы можете придать сигналу SIGTERM совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик SIGTERM предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction. какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал SIGTERM приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы SIGINT и SIGABRT – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа SIG_BLOCK указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа SIG_SETMASK указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа SIG_UNBLOCK указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал SIGHUP и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал SIGHUP вы можете с помощью консольной команды&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill –s 1 &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала SIGHUP (файл swdemo.c на компакт-диске):&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле sa_handler sa_mask sa_flags Значение Указатель на функцию обработчик сигнала или константа Маска сигналов, блокируемых на время вызова обработчика Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа SIG_IGN указывает, что сигнал следует игнорировать, а константа SIG_DFL – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле sa_mask позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр sa_flags позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг SA_RESETHAND указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала SIGTERM. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigprocmask(SIG_BLOCK, &amp;amp;newset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;newset, &amp;amp;sig))&lt;br /&gt;
    printf(“SIGHUP recieved\n”);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал SIGHUP, распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigset_t sset;&lt;br /&gt;
  int sig;&lt;br /&gt;
  ...&lt;br /&gt;
  sigfillset(&amp;amp;sset);&lt;br /&gt;
  sigdelset(&amp;amp;sset, SIGTERM);&lt;br /&gt;
  sigprocmask(SIG_SETMASK, &amp;amp;sset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;sset, &amp;amp;sig))&lt;br /&gt;
    printf(“Signal %i - %s\n”, sig, sys_siglist[sig]);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала SIGTERM (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме SIGTERM (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле PID &amp;gt; 1 PID == 0 PID &amp;lt; 0 Значение Сигнал посылается процессу с соответствующим PID. Сигнал посылается всем процессам из той же группы, что и процесс-источник. Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID. PID == 1 Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  raise(sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
эквивалентен вызову&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill(getpid(), sig);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
1. D. P. Bovet, M. Cesati, Understanding the Linux Kernel, 3rd Edition, O’Reilly, 2005 2. W. R. Stevens, S. A. Rago, Advanced Programming in the UNIX® Environment: Second Edition, Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
Через месяц Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Unix_API</id>
		<title>LXF84:Unix API</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Unix_API"/>
				<updated>2008-03-07T17:21:54Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения SIGKILL система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса SIG, за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал SIGHUP (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал SIGHUP посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение SIGHUP демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал SIGINT (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш Ctrl-C) .&lt;br /&gt;
*Сигнал SIGABRT (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал SIGKILL (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал SIGSEGV (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал SIGTERM (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение SIGTERM свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал SIGCHLD (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал SIGCHLD игнорируется.&lt;br /&gt;
*Сигнал SIGCONT (номер 18) возобновляет выполнение процесса, остановленного сигналом SIGSTOP. Сигнал SIGSTOP (номер 19) приостанавливает выполнение процесса. Как и SIGKILL, этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал SIGTSTP (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал SIGIO/SIGPOLL (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, SIGUSR1 (в Linux – номер 10) и SIGUSR2 (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
  #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  void term_handler(int i) {&lt;br /&gt;
    printf (“Terminating\n”);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  int main(int argc, char ** argv) {&lt;br /&gt;
    struct sigaction sa;&lt;br /&gt;
    sigset_t newset;&lt;br /&gt;
    sigemptyset(&amp;amp;newset);&lt;br /&gt;
    sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
    sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
    sa.sa_handler = term_handler; &lt;br /&gt;
    sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
    printf(“My pid is %i\n”, getpid()); &lt;br /&gt;
    printf(“Waiting...\n”); &lt;br /&gt;
    while(1) sleep(1); &lt;br /&gt;
    return EXIT_FAILURE;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал SIGTERM (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала SIGTERM term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – SIGTERM, может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу SIGTERM означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала SIGTERM. В принципе, вы можете придать сигналу SIGTERM совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик SIGTERM предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction. какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал SIGTERM приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы SIGINT и SIGABRT – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа SIG_BLOCK указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа SIG_SETMASK указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа SIG_UNBLOCK указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал SIGHUP и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал SIGHUP вы можете с помощью консольной команды&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  kill –s 1 &amp;lt;PID&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала SIGHUP (файл swdemo.c на компакт-диске):&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле sa_handler sa_mask sa_flags Значение Указатель на функцию обработчик сигнала или константа Маска сигналов, блокируемых на время вызова обработчика Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа SIG_IGN указывает, что сигнал следует игнорировать, а константа SIG_DFL – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле sa_mask позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр sa_flags позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг SA_RESETHAND указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала SIGTERM. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  sigprocmask(SIG_BLOCK, &amp;amp;newset, 0);&lt;br /&gt;
  while(!sigwait(&amp;amp;newset, &amp;amp;sig))&lt;br /&gt;
    printf(“SIGHUP recieved\n”);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал SIGHUP, распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы: sigset_t sset; int sig; ... sigfillset(&amp;amp;sset); sigdelset(&amp;amp;sset, SIGTERM); sigprocmask(SIG_SETMASK, &amp;amp;sset, 0); while(!sigwait(&amp;amp;sset, &amp;amp;sig)) printf(“Signal %i - %s\n”, sig, sys_siglist[sig]); С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала SIGTERM (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме SIGTERM (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле PID &amp;gt; 1 PID == 0 PID &amp;lt; 0 Значение Сигнал посылается процессу с соответствующим PID. Сигнал посылается всем процессам из той же группы, что и процесс-источник. Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID. PID == 1 Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов raise(sig); эквивалентен вызову kill(getpid(), sig); Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
1. D. P. Bovet, M. Cesati, Understanding the Linux Kernel, 3rd Edition, O’Reilly, 2005 2. W. R. Stevens, S. A. Rago, Advanced Programming in the UNIX® Environment: Second Edition, Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
Через месяц Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Unix_API</id>
		<title>LXF84:Unix API</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Unix_API"/>
				<updated>2008-03-07T17:13:32Z</updated>
		
		<summary type="html">&lt;p&gt;OWeRQ: Новая: ''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но при всем этом они незаменимы, ког...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''ЧАСТЬ 4: Сигналы традиционно считаются трудными в использовании, но&lt;br /&gt;
при всем этом они незаменимы, когда речь заходит о настоящих приложе-&lt;br /&gt;
ниях Unix. Разберитесь в них вместе с '''Андреем Боровским'''!''&lt;br /&gt;
&lt;br /&gt;
Главное отличие сигналов от других средств взаимодействия между процессами заключается в том, что их обработка программой обычно происходит сразу же после поступления сигнала (или не происходит вообще), независимо от того, что программа делает в данный момент. Сигнал прерывает нормальный порядок выполнения инструкций в программе и передает управление специальной функции – обработчику сигнала. Если обработка сигнала не приводит к завершению процесса, то по выходе из функции-обработчика выполнение процесса возобновляется с той точки, в которой оно было прервано. У программ также есть возможность приостановить обработку поступающих сигналов временно, на период выполнения какой-либо важной операции. В традиционной терминологии приостановка получения определенных сигналов называется блокированием. Если для поступившего сигнала было установлено блокирование, сигнал будет передан программе, как только она разблокирует данный тип сигналов. Этим блокирование отличается от игнорирования сигнала, при котором сигналы соответствующего типа никогда не передаются программе. Следует помнить, что не все сигналы могут быть проигнорированы. Например, при получении программой сигнала принудительного завершения SIGKILL система ничего не сообщает программе, а просто прекращает ее работу. Таким образом, преимущество сигналов перед другими средствами межпроцессного взаимодействия заключается в том, что посылать программе сигналы можно в любой момент ее работы, не дожидаясь наступления каких-то особых условий. Источником сигналов может быть как сам операционная система, так и другие пользовательские программы. Если вам показалось, что сигналы похожи на прерывания, то вы совершенно правы. Для реализации сигналов действительно используются программные прерывания. Нужно ли обрабатывать сигналы в вашей программе? Большинство программ не делают этого. В случае программирования для графических оболочек многие функции сигналов берут на себя механизмы сообщений графической оболочки. Тем не менее, есть целый ряд программ (например, демоны и консольные многопоточные приложения), в которых обработка сигналов необходима.&lt;br /&gt;
&lt;br /&gt;
Большинству сигналов системы присвоена конкретная роль и, хотя у программиста существует возможность использовать сигналы для передачи произвольной информации, не соответствующей их стандартному назначению, делать этого не рекомендуется. Собственно говоря, с помощью сигналов можно передать не так уж и много информации – только номер сигнала (хотя на платформе x86, например, можно было бы организовать и передачу дополнительных параметров). Скудость данных, передаваемых сигналами, не удивительна, если учесть, что по умолчанию большинство сигналов просто завершают работу программы. При этом в некоторых случаях на диске сохраняется образ памяти выгруженной программы (знаменитый core dump). Соответственно и программа-источник сигнала обычно не ждет никакого ответа от программы-приемника. Номерам сигналов соответствуют константы, определенные в файле '''signal.h'''. Имена всех этих констант начинаются с префикса SIG, за которыми следует сокращенное название сигнала. Стандарт POSIX определяет две группы сигналов – «классические» сигналы Unix и сигналы реального времени. В отличие от классических сигналов сигналы реального времени всегда буферизуются, так что программа получит все посланные ей сигналы. В этой статье мы рассмотрим только классические сигналы Unix, каковых в Linux насчитывается 31. Этим сигналам назначены номера с 1 до 31 (номер 0, так называемый null-сигнал, имеет особый смысл). Полный список сигналов можно получить из заголовочного файла signal.h. Мы же рассмотрим несколько наиболее интересных сигналов.&lt;br /&gt;
*Сигнал SIGHUP (номер 1) изначально был предназначен для того, чтобы информировать программу о потере связи с управляющим терминалом (терминалы часто подключались к системе с помощью модемов, так что название сигнала происходит от hung up – повесить трубку). Кроме того, сигнал SIGHUP посылается приложению в том случае, если процесс-лидер сессии завершил свою работу. Многие программы-демоны, у которых нет лидера сессии, также обрабатывают этот сигнал. В ответ на получение SIGHUP демон обычно перезапускается (или просто повторно читает файл конфигурации). По умолчанию программа, получившая этот сигнал, завершается.&lt;br /&gt;
*Сигнал SIGINT (номер 2) обычно посылается процессу, если пользователь терминала дал команду прервать процесс (обычно эта команда – сочетание клавиш Ctrl-C) .&lt;br /&gt;
*Сигнал SIGABRT (номер 6) посылается программе в результате вызова функции abort(3). В результате программа завершается с сохранением на диске образа памяти. &lt;br /&gt;
*Сигнал SIGKILL (номер 9) завершает работу программы. Программа не может ни обработать, ни игнорировать этот сигнал.&lt;br /&gt;
*Сигнал SIGSEGV (номер 11) посылается процессу, который пытается обратиться к не принадлежащей ему области памяти. Если обработчик сигнала не установлен, программа завершается с сохранением на диске образа памяти.&lt;br /&gt;
*Сигнал SIGTERM (номер 15) вызывает «вежливое» завершение программы. Получив этот сигнал, программа может выполнить необходимые перед завершением операции (например, высвободить занятые ресурсы). Получение SIGTERM свидетельствует не об ошибке в программе, а о желании ОС или пользователя завершить ее.&lt;br /&gt;
*Сигнал SIGCHLD (номер 17) посылается процессу в том случае, если его дочерний процесс завершился или был приостановлен. Родительский процесс также получит этот сигнал, если он установил режим отслеживания сигналов дочернего процесса и дочерний процесс получил какой-либо сигнал. По умолчанию сигнал SIGCHLD игнорируется.&lt;br /&gt;
*Сигнал SIGCONT (номер 18) возобновляет выполнение процесса, остановленного сигналом SIGSTOP. Сигнал SIGSTOP (номер 19) приостанавливает выполнение процесса. Как и SIGKILL, этот сигнал не возможно перехватить или игнорировать.&lt;br /&gt;
*Сигнал SIGTSTP (номер 20) приостанавливает процесс по команде пользователя (обычно эта команда – сочетание клавиш Ctrl-Z).&lt;br /&gt;
*Сигнал SIGIO/SIGPOLL (в Linux обе константы обозначают один сигнал – номер 29) сообщает процессу, что на одном из дескрипторов, открытых асинхронно, появились данные. По умолчанию этот сигнал, как ни странно, завершает работу программы.&lt;br /&gt;
В стандартной системе Unix определены два сигнала, SIGUSR1 (в Linux – номер 10) и SIGUSR2 (номер 12), предназначенные для передачи произвольной информации, но использование этих сигналов не приветствуется. Одной из причин негативного отношения программистов Unix к пользовательским сигналам является то, что сигналы, вообще говоря, представляют собой ограниченный ресурс, совместное использование которого может вызвать конфликты (например, если программист задействовал эти сигналы в своей программе и при этом использует стороннюю библиотеку, в которой эти сигналы также задействованы).&lt;br /&gt;
&lt;br /&gt;
Если вы не знали, то вам, возможно, будет интересно узнать, что обработка сигналов является частью стандарта языка Си и, как таковая, поддерживается даже на платформе Microsoft Windows. Однако, стандартный интерфейс сигналов Си, основанный на функции signal(), довольно неуклюж (недостатки интерфейса сигналов Си подробно описаны в книге [2]), так что мы воспользуемся более совершенным вариантом интерфейса, основанным на функции sigaction(2). Для демонстрации работы обработки сигналов мы напишем небольшую программу (файл '''sigdemo.c''' на компакт-диске).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void term_handler(int i) {&lt;br /&gt;
	printf (“Terminating\n”);&lt;br /&gt;
	exit(EXIT_SUCCESS);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char ** argv) {&lt;br /&gt;
	struct sigaction sa;&lt;br /&gt;
	sigset_t newset;&lt;br /&gt;
	sigemptyset(&amp;amp;newset);&lt;br /&gt;
	sigaddset(&amp;amp;newset, SIGHUP); &lt;br /&gt;
	sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); &lt;br /&gt;
	sa.sa_handler = term_handler; &lt;br /&gt;
	sigaction(SIGTERM, &amp;amp;sa, 0); &lt;br /&gt;
	printf(“My pid is %i\n”, getpid()); &lt;br /&gt;
	printf(“Waiting...\n”); &lt;br /&gt;
	while(1) sleep(1); &lt;br /&gt;
	return EXIT_FAILURE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наша программа делает две вещи: обрабатывает сигнал SIGTERM (при получении этого сигнала программа выводит диагностическое сообщение и завершает свою работу) и блокирует сигнал SIGHUP, так что этот сигнал не может завершить ее работу. В тексте программы мы первым делом определяем функциюобработчик сигнала SIGTERM term_handler(). Функции-обработчики сигналов – это обычные функции Си, они имеют доступ ко всем глобально видимым переменным и функциям. Однако, поскольку мы не знаем, в какой момент выполнения программы будет вызвана функция-обработчик, мы должны проявлять особую осторожность при обращении к глобальным структурам данных из этой функции. Единственным параметром нашего варианта функции-обработчика сигнала (в Unix-системах существует и другой вариант) является переменная типа int, в которой передается номер сигнала, вызвавшего обработчик. Нам этот номер не нужен, поскольку мы знаем, что только один сигнал – SIGTERM, может вызвать нашу функцию, однако, в принципе, ничто не мешает нам использовать одну функцию для обработки нескольких разных сигналов, и тогда параметр функции-обработчика будет иметь для нас смысл. Функция-обработчик не возвращает никакого значения, что вполне логично, так как она вызывается не нашей программой, а неким системным компонентом. Особый интерес представляет завершение программы из обработчика сигнала. Назначение обработчика сигналу SIGTERM означает, что «умолчательное» действие сигнала – завершение программы не будет выполняться автоматически, и нам необходимо (если, конечно, мы хотим, чтобы этот сигнал завершал программу) позаботиться обо всем явным образом. Если вы закомментируете вызов exit() в нашем примере, то увидите, что программа не будет завершаться по получении сигнала SIGTERM. В принципе, вы можете придать сигналу SIGTERM совершенно иной смысл, например, оповещать программу о наступлении времени вашей любимой телепередачи (или о выходе нового номера журнала Linux Format), однако назначать стандартным сигналам нестандартные действия категорически не рекомендуется. Обработчик SIGTERM предназначен для того, чтобы, по требованию системы или пользователя, программа могла быстро и элегантно закончить текущую задачу и завершить свое выполнение. Именно этим обработчик и должен заниматься. Перейдем теперь к тексту главной функции программы. Установка и удаление обработчиков сигналов осуществляются функцией sigaction(2). Первым параметром этой функции является номер сигнала, а в качестве второго и третьего параметров следует передать указатели на структуру sigaction. Эта структура содержит данные об операции, выполняемой над обработчиком сигнала. Второй параметр sigaction() служит для передачи новых значений для обработки сигнала, а третий – возвращает ранее установленные значения. В таблице 1 приводится краткое описание полей структуры sigaction. какого-либо сигнала. Иначе говоря, любой обрабатываемый сигнал прерывает выполнение sleep(). Впрочем, в нашем примере с бесконечным циклом это не помогло бы программе завершиться. Сигнал SIGTERM приведет к тому, что программа выдаст диагностическое сообщение и завершит работу, а сигналы SIGINT и SIGABRT – к тому, что программа завершится без всякого сообщения. Скомпилируйте и запустите программу в окне терминала. В другом окне скомандуйте kill &amp;lt;PID&amp;gt; где PID – идентификатор процесса программы. Вы увидите, что перед тем как завершиться программа выдает диагностическое сообщение, тогда как при завершении с помощью Ctrl-C никакого сообщения не выводится. Рассмотрим теперь блокировку сигналов. Поскольку игнорирование сигнала устанавливается функцией sigaction(), можно было бы ожидать, что и блокировка устанавливается этой же функцией, но это не так. Поскольку нам, как правило, приходится блокировать несколько сигналов сразу, для блокировки существует специальная функция sigprocmask(2), которая оперирует наборами сигналов (signal sets). Разделение интерфейса между несколькими функциями вызвано еще и требованиями многопоточности. Параметры, устанавливаемые sigaction(), действительны для всей программы в целом, тогда как блокировку сигналов потоки осуществляют независимо друг от друга. Наборы сигналов хранятся в переменных специального типа – sigset_t, а операции над ними осуществляются с помощью специальных функций. Функция sigemptyset() инициализирует набор сигналов пустыми значениями, а функция sigfillset() устанавливает все возможные значения в наборе. Используемая нами функция sigaddset() добавляет значение сигнала в набор, а функция sigdelset() удаляет сигнал из набора. После того как набор сигналов сформирован, мы передаем его функции sigprocmask(), которая выполняет блокировку и разблокировку сигналов. Первым параметром этой функции должна быть одна из констант, определяющих операцию над заданными сигналами. Константа SIG_BLOCK указывает, что сигналы из нового набора должны быть добавлены к списку уже заблокированных сигналов. Константа SIG_SETMASK указывает, что новый набор блокируемых сигналов должен заменить уже существующий (при этом заблокированные ранее сигналы будут разблокированы, если они не заблокированы в новом наборе), а константа SIG_UNBLOCK указывает на необходимость разблокировать сигналы, переданные в наборе. В нашей программе мы блокируем сигнал SIGHUP и вы можете видеть, что программа не обрабатывает этот сигнал. Послать нашей программе сигнал SIGHUP вы можете с помощью консольной команды kill –s 1 &amp;lt;PID&amp;gt; где PID – идентификатор процесса. Сигналы прерывают нормальный порядок выполнения программы и могут завершить работу программы, не способной завершиться иным образом. Но иногда бывает так, что программе просто нечего делать до тех пор, пока она не получит какой-либо сигнал. Иначе говоря, программу нужно заставить ждать появления сигнала, по возможности не нагружая процессор. Такая ситуация может возникнуть, например, в многопоточном приложении, когда нужно синхронизировать завершение нескольких потоков. Ожидание сигнала можно реализовать с помощью цикла, проверяющего значение флажка, который может сбросить обработчик сигнала. В некоторых случаях (таких как рассмотренный выше пример) можно реализовать ожидание и с помощью бесконечного цикла. Очевидно, однако, что эти методы не эффективны и не элегантны. В POSIX-системах существует специальная функция sigwait(3), которая «усыпляет» процесс до тех пор, пока процессу не будет передан один из заданного набора сигналов. Модифицируем нашу программу так, чтобы вместо бесконечного цикла она входила в цикл ожидания сигнала SIGHUP (файл swdemo.c на компакт-диске):&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле sa_handler sa_mask sa_flags Значение Указатель на функцию обработчик сигнала или константа Маска сигналов, блокируемых на время вызова обработчика Дополнительные флаги&lt;br /&gt;
&lt;br /&gt;
Поле sa_handler должно содержать либо адрес функции-обработчика, либо специальную константу, указывающую, что нужно делать с сигналом. Константа SIG_IGN указывает, что сигнал следует игнорировать, а константа SIG_DFL – что нужно восстановить обработку сигнала, заданную системой по умолчанию. Поле sa_mask позволяет заблокировать некоторое множество сигналов на время выполнения обработчика данного сигнала. Делается это для того, чтобы обработка других сигналов не могла прервать обработку данного (это может быть необходимо, особенно, если один обработчик обрабатывает несколько разных сигналов). Параметр sa_flags позволяет задать ряд флагов для выполнения более тонкой настройки обработчика сигналов. Например, флаг SA_RESETHAND указывает, что после завершения обработки сигнала заданным обработчиком должен быть восстановлен обработчик, заданный по умолчанию, так что все последующие сигналы будут обрабатываться «умолчательным» обработчиком. В результате вызова функции sigaction() мы устанавливаем обработчик сигнала SIGTERM. Затем наша программа распечатывает значение PID (это значение понадобится нам для вызова команды kill) и входит в бесконечный цикл, из которого она может быть выведена одним из сигналов. Следует отметить, что функция sleep() прерывается (возобновляет выполнение программы раньше срока) если возвращает управление обработчик sigprocmask(SIG_BLOCK, &amp;amp;newset, 0); while(!sigwait(&amp;amp;newset, &amp;amp;sig)) printf(“SIGHUP recieved\n”); Первым параметром функции sigwait() является указатель на набор сигналов, получения которых будет ждать функция. Во втором параметре sigwait() вернет номер того сигнала, который возобновил работу программы (эта информация может быть полезна, если установлено несколько ожидаемых сигналов). Перед тем как вызывать sigwait(), набор ожидаемых сигналов следует заблокировать с помощью функции sigprocmask(), иначе, при получении сигнала, вместо выхода из sigwait() будет вызван соответствующий обработчик. Сигнал, который возобновил работу программы после вызова sigwait(), уже не может быть перехвачен назначенным ему обработчиком. В нашем примере мы «усыпляем» программу до тех пор, пока она не получит сигнал SIGHUP, распечатываем соответствующее сообщение и снова усыпляем (функция sigwait() возвращает 0, если ее вызов прошел успешно). В то время, когда программа приостановлена в ожидании некоторых сигналов, обработчики всех не заблокированных и не игнорируемых сигналов выполняются обычным образом. Функцию sigwait() можно использовать и для исследования сигналов. На компакт-диске вы найдете программку siglog.c, которая распечатывает информацию о каждом поступившем сигнале (естественно, исследуются только те сигналы, которые могут быть заблокированы). Рассмотрим здесь фрагмент этой программы: sigset_t sset; int sig; ... sigfillset(&amp;amp;sset); sigdelset(&amp;amp;sset, SIGTERM); sigprocmask(SIG_SETMASK, &amp;amp;sset, 0); while(!sigwait(&amp;amp;sset, &amp;amp;sig)) printf(“Signal %i - %s\n”, sig, sys_siglist[sig]); С помощью вызовов sigfillset() и sigdelset() мы создаем набор из всех сигналов, за исключением сигнала SIGTERM (этот сигнал понадобится нам для того, чтобы мы могли завершить работу программы). Далее мы блокируем сигналы набора sset и вызываем для них функцию sigwait(). Функция вернет управление при получении любого сигнала, кроме SIGTERM (для которого назначен отдельный обработчик). Получив новый сигнал, мы распечатываем информацию о нем. Массив char * sys_siglist[] определен в стандартной библиотеке glibc. Этот массив содержит наименования сигналов на «человеческом» языке (эти наименования можно использовать при выводе диагностических и отладочных сообщений). Наименования расположены так, чтобы их индексы в массиве соответствовали номерам сигналов. Те же данные возвращает и функция strsignal(), единственным параметром которой является номер сигнала. На протяжении всей этой статьи мы занимались обработкой сигналов, но не их генерацией. Поскольку основным источником сигналов является операционная система, нам и в «реальной жизни» чаще приходится заниматься именно обработкой. Однако, в заключение статьи следует рассмотреть и функции генерации сигналов. Для генерации сигналов в Unix предусмотрены две функции – kill(2) и raise(3). Первая функция предназначена для передачи сигналов любым процессам, к которым владелец данного процесса имеет доступ, а с помощью второй функции процесс может передать сигнал самому себе. Как это обычно принято в мире Unix, семантика вызова функции kill() совпадает с семантикой одноименной команды ОС. У функции kill() два аргумента – PID процесса-приемника и номер передаваемого сигнала. С помощью функции kill() как и с помощью одноименной команды можно передавать сообщения не только конкретному процессу, но и группе процессов. Таблица 2 демонстрирует поведение функции kill() в зависимости от значения PID:&lt;br /&gt;
&lt;br /&gt;
Поля структуры sigaction&lt;br /&gt;
Поле PID &amp;gt; 1 PID == 0 PID &amp;lt; 0 Значение Сигнал посылается процессу с соответствующим PID. Сигнал посылается всем процессам из той же группы, что и процесс-источник. Сигнал посылается всем процессам, чей идентификатор группы равен абсолютному значению PID. PID == 1 Сигнал посылается всем процессам системы.&lt;br /&gt;
&lt;br /&gt;
Вызов raise(sig); эквивалентен вызову kill(getpid(), sig); Так же как и для других примитивов IPC, для сигналов действует система прав доступа, основанная на правах доступа владельцев процессов. Процесс-приемник получит сигнал только в том случае, если у процесса-источника есть соответствующие права. С помощью функции kill() можно проверить, существует ли в системе процесс с заданным PID, не посылая процессу никаких сигналов. Для этого предназначен псевдо-сигнал с номером 0. Если соответствующего процесса не существует, функция kill() вернет значение 1, соответствующее об ошибке. В любом случае, сигнал не будет отправлен. Читателей, полюбивших обработку сигналов, я могу обрадовать тем, что мы рассмотрели далеко не все функции, связанные с сигналами. При изучении документации вас ждет еще много полезного и приятного, мы же закончим на этом наше знакомство с сигналами. Мы можем столкнуться с необходимостью обработки сигналов при программировании, например, процессов-демонов. Ими мы и займемся в следующей статье. LXF&lt;br /&gt;
&lt;br /&gt;
Литература:&lt;br /&gt;
1. D. P. Bovet, M. Cesati, Understanding the Linux Kernel, 3rd Edition, O’Reilly, 2005 2. W. R. Stevens, S. A. Rago, Advanced Programming in the UNIX® Environment: Second Edition, Addison Wesley Professional, 2005&lt;br /&gt;
&lt;br /&gt;
Через месяц Мы породим монстра... то есть демона.&lt;/div&gt;</summary>
		<author><name>OWeRQ</name></author>	</entry>

	</feed>