Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Операционные системы (часть 1)

.pdf
Скачиваний:
11
Добавлен:
24.03.2015
Размер:
219.83 Кб
Скачать

-o выводить только ту часть строки, что соответствует заданному шаблону

Файлы для поиска не указываются, если grep используется как потоковый фильтр.

(П) grep computer <fortest

cat fortest | grep computer #аналоги предыдущего примера

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

(П) Текстовый файл words содержит словарь английских слов (в каждой строчке одно слово). Нужно найти все слова, содержащие пару сдвоенных букв.

grep -E '(.)\1.*(.)\2' /usr/share/dict/words

или

grep '\(.\)\1.*\(.\)\2' /usr/share/dict/words.

(П) Найти все слова-палиндромы.

grep -E '^(.).?\1$|^(.)(.).?\3\2$|^(.)(.)(.).?\6\5\4$' /usr/share/dict/words; \ grep -E '^(.)(.)(.)(.).?\4\3\2\1$' /usr/share/dict/words #до 9-и букв длиной

(П) Найти все слова из 6 и более букв, в которых буквы следуют в алфавитном порядке.

echo '^a?b?c?d?e?f?g?h?i?j?k?l?m?n?o?p?q?r?s?t?u?v?w?x?y?z?$' >pattern grep -Ef pattern /usr/share/dict/words | grep '......'

(П) Найти все файлы из каталога /usr/include, содержащие слово SIGINT.

grep SIGINT /usr/include/* 2>/dev/null

Программа аук (awk)

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

--- awk [<опции>] [<программа>] [<файлы для обработки>]. Файлы для обработки не указываются, если awk используется как фильтр. Наиболее используемая опция --- -f, после которой указывают имя файла с программой. Программы на awk могут иметь длину в сотни строк. Общий вид простой awk-программы:

<шаблон> {<действие>}

...

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

Вызов awk '/<регулярное выражение>/' [<файлы>] почти

эквивалентен grep -E '<регулярное выражение>' [<файлы>]. Шаблоны строятся в основном из расширенных регулярных выражений с почти таким же синтаксисом, что и в grep. Различие только в том, что в awk нельзя использовать ссылки. Список всех допустимых шаблонов awk:

BEGIN --- соответствует началу работы, до прочтения первой строки; END --- соответствует концу работы, после обработки последней строки;

/<регулярное выражение>/ --- соответствует строке, содержащей в себе подстроку, соответствующую регулярному выражению

<логическое выражение> --- соответствует строке, если истинно

<шаблон> && <шаблон> --- соответствует строке, если оба шаблона ей соответствуют;

<шаблон> || <шаблон> --- соответствует строке, если хотя бы один из шаблонов ей соответствует;

<шаблон> ? <шаблон> : <шаблон> --- если 1-ый шаблон соответствует строке, то осуществляется проверка соответствия строки 2-му шаблону, иначе --- 3-му;

! <шаблон> --- соответствует строке, если шаблон строке не соответствует; (<шаблон>) --- группировка;

<шаблон>, <шаблон> --- диапазонный шаблон, соответствует всем строкам, начиная от строки, соответствующей 1-му шаблону, до строки, соответствующей 2-му.

Первые два и последний шаблоны можно использовать только самостоятельно.

Помимо стандартных отношений (<, >, <=, >=, ==, !=) в логических выражениях можно использовать операции ~ (соответствует), !~ (не соответствует) и in (является членом).

(П) "abc" ~ /^a.*c$/ ---

верно

"a123de4517f" ~ /[1-7]*/ --- верно

"abcd" ~ /[0-9]+/ ---

ложь

"abcd" !~ /^b.*/ ---

верно

Синтаксис действия является Си-подобным. В отличие от Си концом оператора

вawk является не только точка с запятой, но и переход на новую строку. Операторы if, while, do, for, continue, break, return, составной --- аналогичны операторам Си. Кроме того, в awk есть еще операторы for in, delete и exit. Последний аналогичен команде exit оболочки bash. Операции в awk те же, что и

вСи, но знак ^ означает возведение в степень и отсутствуют поразрядные операции и операция следования. Кроме того, знак $ используется подобным оболочке образом и для склейки строк достаточно записать их подряд или через пропуск. Комментарии такие же как в bash. Пустой шаблон соответствует любой строке. Действие по-умолчанию --- печать входной строки.

Входная строка именуется $0. Входная строка рассматривается как запись, которая разбивается на поля символами из множества,

определяемого переменной-строкой FS (инициализируется

пробелом). К каждому полю можно обращаться по его номеру: 1-ое именуется $1, 2-ое --- $2 и т.д. По каждой строке устанавливаются переменные NF ---

число полей в ней и NR --- ее номер. Любое значение awk сначала пытается обрабатывать как число. Если это невозможно, то значение рассматривается как строка. Переменные не описываются и инициализируются 0.

(П) awk '{print}' /etc/passwd #распечатка файла

awk '{print ++n, $0}' /etc/passwd #распечатка с номерами строк awk '{print NR, $0}' /etc/passwd #то же самое

echo 1 2 3 5 | awk '{for (i = 1; i <= NF; i++) sum += $i print sum}' #печать суммы чисел из входного потока

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

(П) ls -l #печать подробной информации о файлах текущего каталога ls -l | awk '{

size += $5; count++}

END {printf "Всего файлов %14d\n", count printf "Общий объем данных %8d\n", size printf "Байт на файл %14.2f\n", size/count}'

Можно использовать следующие математические функции:

atan2(x,y) ---

арктангенс от x/y;

cos(x), sin(x)

--- косинус и синус от x;

exp(x), log(x)

--- экспоненциальная функция и натуральный логарифм от x;

sqrt(x)

--- квадратный корень от x;

int(x) ---

целая часть числа x;

rand() ---

случайное число из диапазона от 0 до 1;

srand() ---

инициализация генератора случайных чисел.

(П)awk 'BEGIN {for (i = 1; i <= 10; i++) printf "%2d %.2f\n", i, sin(i)}' #печать значений синусов чисел от 1 до 10

Для работы со строками можно использовать функции:

gsub(r, s, t) --- замена каждой подстроки в строке t, соответствующей регулярному выражению r, на строку s. Результат вызова --- количество произведенных замен. Знак & в s заменяется на нашедшую соответствие подстроку. Для использования знака & в s его надо предварять обратной косой чертой. Если t не указано, то берётся $0;

(П) t="aya"; gsub("a","b",t); print t #byb

sub(r, s, t) --- то же, что и gsub, но делает не более одной замены; index(s, t) --- позиция строки t в строке s или 0, если t в s не входит; length(s) --- длина строки s;

match(s, r) --- позиция подстроки, соответствующей регулярному выражению r, в строке s или 0, если такого соответствия нет. Устанавливает переменную RLENGTH равной длине найденной подстроки;

split(s, ar, r) --- создание и заполнение ассоциативного массива ar полями строки s, разделитель полей задается регулярным выражением r или FS, если r не указано. Возвращает число полей, элементов массива ar;

substr(s, i, n) --- подстрока s с позиции i либо длиной n, либо если n не указано, то до конца строки;

sprintf(fmt, e1, ..., en) --- строка-результат форматной печати выражений от e1 до en согласно строке формата fmt. Во всем кроме результата идентична printf;

strtonum(s) --- переводит строку s в число, в gawk десятичные числа переводятся автоматически, а 8-е и 16-е только c опцией -non-decimal-data,

другие варианты awk все числа переводят автоматически и такой функции не имеют;

tolower(s), toupper(s) --- строка s, в которой все буквы заменены на строчные или заглавные соответственно.

Строки в awk не являются массивами в отличие от Си.

(П) Печать первых 30 символов строк длины, большей 50 символов. Сопровождать вывод таких строк их номерами.

length($0)>50 {print NR, substr($0, 1, 30)}

Массивы awk --- ассоциативные, в них качестве индексов могут использоваться строки. Для проверки вхождения индекса в массив используется операция in. Для удаления всего массива или его компоненты используется операция delete.

(П) Рассмотрим фрагмент программы.

w["cat"] = 2 w["dog"] = 3 w["cow"] = 10 w["mouse"] = 1

for (i in w) print i, w[i] #распечатка массива w w["goat"] = 5

delete w["cow"] print "-----"

for (i in w) print i, w[i]

if ("goat" in w) print "ok."

s = "cat dog wolf tiger shark" n = split(s, w, " ")

for (i in w) print i, w[i] #неупорядоченно

for (i = 1; i <= n; i++) print i, w[i] #по порядку delete w #уничтожение всего массива w

(П) Программа составления частотного словаря.

BEGIN {FS = "[^A-Za-z]"} #установка разделителей полей

{

for (i = 1; i <= NF; i++) dict[toupper($i)]++

}

END {

delete dict[""] for (i in dict) print i, dict[i]

}

Если назвать программу fd.awk, то запустить ее можно так

awk -f fd.awk <файлы для обработки>.

Чтобы словарь получился отсортированным можно добавить | sort.

Если нужно, чтобы результаты печатались не в стандартный поток, а в заданый файл, то к команде печати добавляют перенаправления > или >>, например,

if (a<10)

print "Variant 1" > "file1" else

printf "Variant 2 (a=%d)\n", a > "file2"

выводит печатаемый текст либо в file1, либо в file2. При использовании > создается новый файл, а при использовании >> --- данные добавляются к

существующему файлу. Можно еще организовывать при помощи | трубопровод.

Для ввода можно использовать функцию getline, вызов которой без параметров читает строку в $0, устанавливает NF и т.п. Если вызвать getline с параметром-переменной, то строка читается в неё. Для этой функции естественно использовать перенаправление <.

Кроме конструкции шаблон---действие в awk можно определять новые функции конструкцией

function <имя функции> (<список формальных параметров>) {<операторы>}.

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

(П) function sqr (x) {return x*x}

BEGIN {printf "%d*%d=%d\n", 5, 5, sqr(5)} #5*5=25

Поточный редактор sed

Может рассматриваться как упрощенный awk. Основные команды: замена (s) и удаление (d). Например,

sed 's/abc/cba/g' ФАЙЛ

заменит все вхождения строки abc на cba в файле и выведет результат в поток вывода. Замена специфицируется командой s (seek), у которой два

аргумента, 1-й --- регулярное выражение, описывающее то, что надо заменить, и 2-й --- строка-замена. В замещаемом можно использовать цитированные бэкслэшем скобки для выделения подвыражений, а в замене --- & для указания на все замещаемое или ссылки от \1 до \9 на выделенные подвыражения, например, s/a+(b+)c/&-\1/ заменит aabbcd на aabbc-bbd. После аргументов может идти

опция g, означающая повторность замен в строке, --- без нее будет производиться не более одной замены на строку.

Пример. Вызов

sed 's/<[^>]*>//g' file.html > file.txt

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

Вместо / в s можно использовать любой символ, например, s:/://: заменит / на два.

Команды sed, как и awk, могут иметь предваряюший шаблон. Например, /r/s/b/d/ будет заменять первую b на d только в строках, содержащих r, а команда /r/!s/b/d/ будет осуществлять ту же замену, но в строках, r не содержащих.

Команда d (delete) используется с шаблоном, например, /[0-9]/d удаляет все

строки с десятичными цифрами, а 1~2d удаляет все нечетные строки. Запись 1~2 означает с 1 строки с шагом 2, шаг можно опускать. В sed можно использовать и другие шаблоны, например, подобные диапазонным awk.

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

Опция -r позволяет использовать расширенные регулярные выражения, а опция -f такая же как в awk или grep.

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

Пример. Удаление всех тегов HTML, включая многострочные, из документа без комментариев. Создадим файл nohtml.sed со следующей программой.

1 h 2~1 H

${

g s/<[^>]*>//g

p

}

Вызов

sed -nf nohtml.sed file.html >file1.txt

или

sed -n '1h;2~1H;${g;s/<[^>]*>//g;p}' file.html >file2.txt

Опция -n подавляет автоматическую печать каждой строки. В построчном режиме каждая строка печатается автоматически после обработки. Команда p (print, печать) используется обычно вместе с опцией -n, она печатает текущие данные.

Шаблон 1 - это первая строка. Шаблон 2~1 - это все строки, начиная со второй. Шаблон $ - это последняя строка. Команда h переносит текущие данные, входную строку, в буфер, а команда H добавляет к буферу маркер конца строки и затем текущие данные. Первые две команды sed-программы обеспечивают перенос всего входного текста в буфер. Команда g, обратная к h, переносит содержимое буфера в рабочую область, делает содержимое буфера текущими данными. Фигурные скобки используются для группировки. Знак ; используется как разделитель команд, конец строки ему эквивалентен (как в awk). Комментарии как в bash.

Основные особенности средств Tcl/Tk

Tcl --- это bash-подобный язык, имеющий разнообразные типы данных: числа, списки, ассоциативные массивы, файлы, строки, бинарные данные и др.

Поддерживаются пакеты (модули), пространства имён, исключения и др. В идентификаторах можно использовать не только буквы и цифры. В Tcl есть только несколько специальных символов, \{}"[]; . Например, число или круглая скобка может быть именем переменной.

Знаки \"{} используются для цитирования. {} соответствует по эффекту апострофам бэш. \" - как в бэш. [] - командная подстановка.

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

Поддерживается двусторонний интерфейс с языком си/си++: можно подключать функции си/си++ к tcl, а можно из программ на си/си++ вызывать средства Tcl/Tk.

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

buttons.tcl, face.tcl, furniture.tcl, moves.tcl, virus, virus2, xdisk.tcl, xcal.tcl,

shoot.tcl, sgserv (графики).

Разработка простого калькулятора. Создадим клавиши для ввода цифр и поле ввода.

#!/usr/bin/wish

wm title . "Easy Calculator" ;#

wm resizable . 0 0 ;#нельзя менять размер окна

entry .e -width 30 -textvariable data ;#поле ввода

frame .bl1 ;#собираем клавиши по три button .bl1.b1 -width 5 -text 1 -command {append data 1} button .bl1.b2 -width 5 -text 2 -command {append data 2} button .bl1.b3 -width 5 -text 3 -command {append data 3} pack .bl1.b1 .bl1.b2 .bl1.b3 -side left ;#пакуем клавиши

frame .bl2

button .bl2.b1 -width 5 -text 4 -command {append data 4} button .bl2.b2 -width 5 -text 5 -command {append data 5} button .bl2.b3 -width 5 -text 6 -command {append data 6} pack .bl2.b1 .bl2.b2 .bl2.b3 -side left

frame .bl3

button .bl3.b1 -width 5 -text 7 -command {append data 7} button .bl3.b2 -width 5 -text 8 -command {append data 8} button .bl3.b3 -width 5 -text 9 -command {append data 9} pack .bl3.b1 .bl3.b2 .bl3.b3 -side left

pack .e .bl1 .bl2 .bl3

Продолжим разработку, добавив дополнительные клавиши и новые возможности.

set mem "" set odata ""

proc = {} {

global data odata set odata $data

if $data=="" return

set data [expr 1.0*$data] ;#результат - вещественный

.e icursor end

}

proc ins {d} { global data append data $d

.e icursor end

}

entry .e -width 50 -textvariable data frame .bl1

button .bl1.b1 -width 5 -text 1 -command {ins 1} button .bl1.b2 -width 5 -text 2 -command {ins 2} button .bl1.b3 -width 5 -text 3 -command {ins 3}

button .bl1.b4 -width 5 -text BS -command {set data [string range $data 0 end-1]} button .bl1.b5 -width 5 -text CE -command {set data ""}

button .bl1.b6 -width 5 -text Exit -command exit

pack .bl1.b1 .bl1.b2 .bl1.b3 .bl1.b4 .bl1.b5 .bl1.b6 -side left

frame .bl2

button .bl2.b1 -width 5 -text 4 -command {ins 4} button .bl2.b2 -width 5 -text 5 -command {ins 5} button .bl2.b3 -width 5 -text 6 -command {ins 6} button .bl2.b4 -width 5 -text + -command {ins +} button .bl2.b5 -width 5 -text - -command {ins -} button .bl2.b6 -width 5 -text ( -command {ins (}

pack .bl2.b1 .bl2.b2 .bl2.b3 .bl2.b4 .bl2.b5 .bl2.b6 -side left

frame .bl3

button .bl3.b1 -width 5 -text 7 -command {ins 7} button .bl3.b2 -width 5 -text 8 -command {ins 8} button .bl3.b3 -width 5 -text 9 -command {ins 9} button .bl3.b4 -width 5 -text * -command {ins *} button .bl3.b5 -width 5 -text / -command {ins /} button .bl3.b6 -width 5 -text ) -command {ins )}

pack .bl3.b1 .bl3.b2 .bl3.b3 .bl3.b4 .bl3.b5 .bl3.b6 -side left

frame .bl4

button .bl4.b1 -width 5 -text 0 -command {ins 0} button .bl4.b2 -width 5 -text . -command {ins .} button .bl4.b3 -width 5 -text = -command =

button .bl4.b4 -width 5 -text prev -command {set data $odata; .e icursor end} button .bl4.b5 -width 5 -text store -command {set mem $data}

button .bl4.b6 -width 5 -text get -command {set data $mem; .e icursor end} pack .bl4.b1 .bl4.b2 .bl4.b3 .bl4.b4 .bl4.b5 .bl4.b6 -side left

pack .e .bl1 .bl2 .bl3 .bl4

focus .e

bind .e <Return> = bind . <Escape> exit

Некоторые системные вызовы Unix

Основное средство для организации многозадочности - это вызов безаргументной функции fork() из <unistd.h>, который создает копию вызвавшего ее процесса. Копия может быть отличена от оригинала по возвращаемому значению fork(), которое --- ноль в копии и номер процесса-копии в исходном, порождающем процессе. Если вызов не удался, например, из-за нехватки памяти, то fork() возвращает -1.

Вызовы процессов образуют дерево. Код возврата процесса возвращается порождающему процессу. Если порождающий процесс завершается раньше порождённого, то порожденный процесс превращается в зомби-процесс. Он не может полностью исчезнуть, так как его код возврата может быть востребован порождающим процессом. Начальный процесс в системе (корень в дереве процессов) называется init или systemd --- его номер обычно 1.

Собственно вызов новой задачи или, другими словами, установка нового содержимого для процесса осуществляется функциями семейства exec из <unistd.h>: execl(), execlp(), execle(), execv(), execvp(). Функции, заканчивающиеся

на p, не требуют точного указания местоположения загружаемого файла ---

они могут найти его по адресам, перечисленным в переменной среды PATH. Функции, содержащие l, получают параметры вызова через список аргументов неопределенной длины, а функции, содержащие v, получают такой список через массив, подобно main(). Последним элементом как списка, так и массива должен быть 0, а первым --- имя программы. Функция execle() позволяет задавать среду исполнения процесса.

Пример вызова программы date.

#include<iostream>

#include<unistd.h> main() {

execlp("date", "date", 0);

std::cerr << "Can't execute program 'date'\n";