Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Программирование на Shell. Скрипты.
1. Введение
Компьютер - не такая уж и "умная" машина, как это принято считать. Ему необходимо дать точные инструкции о том, что он должен сделать. Для взаимодействия с компьютером служат командные языки, управляющие всеми выполняемыми им операциями. В большинстве языков основные операции, такие как копирование или удаление файла, выполняются с помощью простых команд. Однако компьютер не в состоянии расшифровать команды, которые вы вводите с терминала. Для преобразования таких команд в вид, понятный для компьютера интерпретаторы команд. В разных операционных системах, служат интерпретаторы команд называются по-разному. В UNIX используется термин оболочка(shell). Оболочки предоставляют пользователям богатые возможности, но для эффективного использования системы необходимо точно знать оболочки, как задавать команды
В настоящее время в системе UNIX применяются различные оболочки, наиболее популярными из которых являются следующие.
- Bourne shell (sh), названная в честь своего создателя Стивена Борна из AT&T Bell Labs. С shell (csh), разработанная Биллом Джоем, первоначально была создана для BSD UNIX, сейчас входит в состав System V. Korn shell (ksh), созданная Дэвидом Корном на бозе оригинальной bsh, но также реализующая и некоторые возможности оболочки С.
Помимо перечисленных выше основных оболочек, встречаются некоторые другие. Поскольку в своей работе вы можете столкнуться с ними, ниже приводится их перечень.
- Обновлённый вариант Bourne shell - Bourne Again (bash) - созданный в рамках проекта GNU. Pd-ksh (pdksh) - общедоступная версия Korn shell компании AT&T. Несмотря на то, что Pd-ksh представляет собой клон Korn shell, она лишена ряда возможностей, которые делают Korn shell мощным инструментом для написания сценариев (script). TC shell (tcsh) - расширенная версия C shell. В этой версии реализованы несколько новых возможностей, отсутствующих в C shell, например редактирование командной строки и проверка орфографии. Z shell (zsh) - оболочка, объединяющая в себе многие возможности оболчки Bourne Again, TC shell, Korn shell и предлагающая ряд новых средств. Более всего Z shell похожа на Korn shell.
2. Основные понятия языка shell
2.1. Ввод-вывод
Три направления ввода-вывода являются выделенными - стандартный ввод, стандартный вывод и стандартный протокол. Как правило, команды берут исходные данные из стандартного ввода и помещают результаты в стандартный вывод.
Стандартный вывод - это монитор вашего терминала на который данные выводятся после выполнения команд, а стандартный ввод - клавиатура, с которой вы вводите данные, и с которой эти данные считываются программой.
Стандартные ввод, вывод и протокол можно переназначить. Обозначение
< <имя файла>
служит для переназначения стандартного ввода (дескриптор файла 0),
> <имя файла>
для стандартного вывода (дескриптор файла 1);
<< <строка>
ввод происходит со стандартного ввода, пока не встретится указанная <строка> или конец файла,
>> <имя файла>
для стандартного вывода; если файл существует, то выводимая информация добавляется к конец этого файла,
<& <цифра>
в качестве стандартного ввода объявляется файл, ассоциированный с дескриптором <цифра>; аналогично для стандартного вывода
>& <цифра>
<&- и >&-
закрывают соответственно стандартный ввод и вывод.
Если любой из этих конструкций предшествует цифра, то с указанным файлом будет ассоциирован дескриптор, равный указанной цифре, вместо 0 и 1 по умолчанию. Например,
2 > <имя файла>
для стандартного протокола используется дескриптор 2, а
2 >& 1
ассоциирует дескриптор 2 с файлом, ассоциированным с дескриптором 1.
... 2>protocol
переназначает стандартный протокол (дескриптор 2) в файл по имени protocol.
Чтобы переназначить стандартный протокол туда же, куда уже назначен стандартный вывод, следует употребить конструкцию
... 2>&1
Важен порядок переназначения: shell производит переназначение слева направо по указанному списку. Так,
1 > xxx 2 >& 1
сначала ассоциирует дескриптор 1 с файлом xxx, а затем дескриптор 2 с 1, т. е. тоже с xxx. А
2 >& 1 1 > xxx
ассоциирует дескриптор 2 с терминалом, а 1 - с файлом xxx.
Можно переназначить системный ввод на текущий файл:
isql - - <
Примеры использования перенозначения стандартного ввода-вывода:
· echo < my - данные из файла my выводятся на экран;
· echo "Error" > my. lst - запись строки "Error" в файл my. lst;
· "Any symbols you want" >> file - строка добавляется в конец файла file, если он существует
2.2. Синхронное и асинхронное выполнение команд
Обычно shell ждет завершения выполнения команды. Однако имеется возможность запустить задачу в асинхронном режиме, т. е. без ожидания ее завершения. Для этого после команды (после всех ее аргументов и указаний о переназначении ввода-вывода) надо поставить знак &. При этом по умолчанию стандартный ввод команды назначается на пустой файл /dev/null.
Пример: создать файл primer можно по команде
echo > primer
Еще пример: запустить программу prog в асинхронном режиме, чтобы не надо было дожидаться его завершения, засечь время выполнения, результаты программы направить в файл prog. res, данные о времени выполнения - в файл prog. tim.
time prog > prog. res 2> prog. tim &
2.3. Конвейер
Конвейер - последовательность команд, разделенных знаком |. Если после конвейера стоит ";" , shell ждет его завершения. Если "&" - то не ждет. Роль ";" может играть конец строки. Смысл конвейера в том, что стандартный вывод одной команды замыкается на стандартный ввод другой.
Примеры конвейеров команд:
ls *.o | wc - l - подсчитать число объектных файлов в текущем каталоге;
who | sort - печать отсортированного списка пользователей;
who | grep you - поиск определённого пользователя;
who | grep you | wc - l - подсчёт: сколько раз пользователь you входил в систему.
2.4 Метасимволы, генерация имен файлов
Метасимволы - символы, имеющие специальное значение для интерпретатора :
? * ; & ( ) | ^ < > <пробел> <табуляция> <возврат_каретки>
Однако каждый из этих символов может представлять самого себя, если перед ним стоит \. Все символы, заключенные между кавычками ' и ', представляют самих себя. Между двойными кавычками (") выполняются подстановки команд (см п. 2.2) и параметров (см. п. 2.3), а символы \, `," и $ могут экранироваться предшествующим символом \.
После всех подстановок в каждом слове команды ищутся символы *,?, и [. Если находится хотя бы один из них, то это слово рассматривается как шаблон имен файлов и заменяется именами файлов, удовлетворяющих данному шаблону (в алфавитном порядке). Если ни одно имя файла не удовлетворяет шаблону, то он остается неизменным. Значения указанных символов:
* | любая строка, включая и пустую |
? | один любой символ |
[...] | любой из указанных между ними символов. Пара символов, разделенных знаком -, означает любой символ, который находится между ними, включая и их самих. Если первым символом после "[" идет "!", то указанные символы не должны входить в имя файла |
Пример:
· echo a* - перечисляет имена всех файлов текущего каталога, начинающихся на а;
· sort a?? - cортирует все файлы, имя которых начинается на а и состоит из 3-х букв;
· cat [a-d]* - выдаст файлы, которые начинаются с "a", "b", "c", "d". Аналогичный эффект
· дадут и команды "cat [abcd]*" и "cat [bdac]*".
2.5. Командные файлы (script'ы)
Для того, чтобы текстовый файл можно было использовать как команду, существует несколько возможностей.
Пусть с помощью редактора создан файл с именем "cmd", содержащий одну строку следующего вида:
date; pwd; ls
Можно вызвать shell как команду (!), обозначаемую "sh", и передать ей файл "cmd", как аргумент или как перенаправленный вход, т. е.
$ sh cmd или $ sh <cmd
В результате выполнения любой из этих команд будет выдана дата, затем имя текущего каталога, а потом содержимое каталога.
Более интересный и удобный вариант работы с командным файлом - это превратить его в выполняемый, т. е. просто сделать его командой, что достигается изменением кода защиты. Для этого надо разрешить выполнение этого файла.
Например,
chmod 711 cmd
сделает код защиты "rwx__x__x". Тогда простой вызов
cmd
приведет к выполнению тех же трех команд.
Результат будет тот же, если файл с содержимым
date; pwd; ls
представлен в виде:
date
pwd
ls
так как переход на другую строку также является разделителем в последовательности команд.
Таким образом, выполняемыми файлами могут быть не только файлы, полученные в результате компиляции и сборки, но и файлы, написанные на языке shell. Их выполнение происходит в режиме интерпретации с помощью shell-интерпретатора
Еще раз отметим, что shell-интерпретатор, это всего лишь одна из сотен команд ОС UNIX, имеющая равные с прочими привилегии.
2.6. Рекурсивные скрипты
Shell позволяет использовать рекурсии в виде рекурсивных скриптов. Рекурсия - это вызов программой самой себя.
Пример:
Удалить файлы из каталога и всех его подкаталогов.
###
# my: Удаление файлов из каталога и всех его подкаталогов
cd $1
echo "directory $1"
set *
for i in *
do
if test - d $i
then
my $i
else
echo $i
while read a || exit
do
case $a in
n*)
break
;;
" ")
rm $i
break
;;
esac
done
fi
done
3. Синтаксис языка shell
3.1. Комментарии
Строки, начинающиеся с #, трактуются как комментарии.
3.2. Подстановка результатов выполнения команд
Выражения можно заключать в обратные кавычки (`). Такие выражения вычисляются в месте использования. Они могут быть, например, частью строк. Пример. Пусть параметром макрокоманды является имя файла с расширением. for. Требуется удалить одноименный файл с расширением. err.
name=`ena - n $1`
rm - f ${name}.err
Значение, полученное в результате выполнения команды
ena - n $1
присваивается переменной name. Фигурные скобки использованы для выделения аргумента операции перехода от имени к значению. Без них. err приклеилась бы к имени.
3.3. Переменные и подстановка их значений
Все переменные в языке shell - текстовые. Их имена должны начинаться с буквы и состоять из латинских букв, цифр и знака подчеркивания (_). Чтобы воспользоваться значением переменной, надо перед ней поставить символ $. Использование значения переменной называется подстановкой.
Различается два класса переменных: позиционные и с именем. Позиционные переменные - это аргументы командных файлов, их именами служат цифры: $0 - имя команды, $1 - первый аргумент и т. д. Значения позиционным переменным могут быть присвоены и командой set (см. Специальные команды). Пример. После вызова программы на shellе, хранящейся в файле ficofl:
ficofl - d / \*.for
значением $0 будет ficofl, $1 - - d, $2 - /, $3 - *.for, значения остальных позиционных переменных будут пустыми строками. Заметим, что если бы символ * при вызове ficofl не был экранирован, в качестве аргументов передались бы имена всех фортранных файлов текущей директории.
Еще две переменные хранят командную строку за исключением имени команды: $@ эквивалентно $1 $2 ..., а $* - "$1 $2 ...". Начальные значения переменным с именем могут быть установлены следующим образом:
<имя>=<значение> [ <имя>=<значение> ] ...
Не может быть одновременно функции (см. Управляющие конструкции) и переменной с одинаковыми именами. Для подстановки значений переменных возможны также следующие конструкции:
${<переменная>}
если значение <переменной> определено, то оно подставляется. Скобки применяются лишь если за <переменной> следует символ, который без скобок приклеится к имени.
${<переменная>:-<слово>}
если <переменная> определена и не является пустой строкой, то подставляется ее значение; иначе подставляется <слово>.
${<переменная>:=<слово>}
если <переменная> не определена или является пустой строкой, ей присваивается значение <слово>; после этого подставляется ее значение.
${<переменная>:?<слово>}
если <переменная> определена и не является пустой строкой, то подставляется ее значение; иначе на стандартный вывод выводится <слово> и выполнение shellа завершается. Если <слово> опущено, то выдается сообщение "parameter null or not set".
${<переменная>:+<слово>}
если <переменная> определена и не является пустой строкой, то подставляется <слово>; иначе подставляется пустая строка.
Пример: если переменная d не определена или является пустой строкой, то выполняется команда pwd
echo ${d:-`pwd`}
Следующие переменные автоматически устанавливаются shell'ом:
# | количество позиционных параметров (десятичное) |
- | флаги, указанные при запуске shellа или командой set |
? | десятичное значение, возвращенное предыдущей синхронно выполненной командой |
$ | номер текущего процесса |
! | номер последнего асинхронного процесса |
@ | эквивалентно $1 $2 $3 ... |
* | эквивалентно "$1 $2 $3 ..." |
Напомним: чтобы получить значения этих переменных, перед ними нужно поставить знак $. Пример: выдать номер текущего процесса:
echo $$
3.4. Специальные переменные
Shell'ом используются следующие специальные переменные:
HOME | директория, в которую пользователь попадает при входе в систему или при выполнении команды cd без аргументов |
PATH | список полных имен каталогов, в которых ищется файл при указании его неполного имени. |
PS1 | основная строка приглашения (по умолчанию $) |
PS2 | дополнительная строка приглашения (по умолчанию >); в интерактивном режиме перед вводом команды shell'ом выводится основная строка приглашения. |
IFS | последовательность символов, являющихся разделителями в командной строке (по умолчанию это <пробел>, <табуляция> и <возврат_каретки>) |
4. Управляющие конструкции
Простая команда - это последовательность слов, разделенная пробелами. Первое слово является именем команды, которая будет выполняться, а остальные будут переданы ей как аргументы. Имя команды передается ей как аргумент номер 0 (т. е. имя команды является значением $0). Значение, возвращаемое простой командой - это ее статус завершения, если она завершилась нормально, или (восьмеричное) 200+статус, если она завершилась аварийно.
Список - это последовательность одного или нескольких конвейеров, разделенных символами ;, &, && или || и быть может заканчивающаяся символом ; или &. Из четырех указанных операций ; и & имеют равные приоритеты, меньшие, чем у && и ||. Приоритеты последних также равны между собой. Символ ; означает, что конвейеры будут выполняться последовательно, а & - параллельно. Операция && (||) означает, что список, следующий за ней будет выполняться лишь в том случае, если код завершения предыдущего конвейера нулевой (ненулевой).
Команда - это либо простая команда, либо одна из управляющих конструкций. Кодом завершения команды является код завершения ее последней простой команды.
4.1 Цикл FOR
for <переменная> [ in <набор> ]
do
<список>
done
Если часть in <набор> опущена, то это означает in "$@" ( то есть in $1 $2 ... $n).
Пример 1.
Вывести на экран все фортранные файлы текущей библиотеки:
for f in *.for
do
cat $f
done
Пример 2.
Пусть команда "lsort" представлена командным файлом
for i in f1 f2 f3
do
proc-sort $i
done
В этом примере имя "i" играет роль параметра цикла. Это имя можно рассматривать как shell-переменную, которой последовательно присваиваются перечисленные значения (i=f1, i=f2, i=f3), и выполняется в цикле команда "procsort".
Пример 3.
Часто используется форма "for i in *", означающая "для всех файлов текущего каталога".
Пусть "proc-sort" в свою очередь представляется командным файлом
cat $1 | sort | tee /dev/lp > ${1}_sorted
т. е. последовательно сортируются указанные файлы, результаты сортировки выводятся на печать ("/dev/lp") и направляются в файлы f1_sorted f2_sorted и f3_sorted
Можно сделать более универсальной команду "lsort", если не фиксировать перечень файлов в команде, а передавать произвольное их число параметрами.
Тогда головная программа будет следующей:
for i
do
proc-sort $i
done
Здесь отсутствие после "i" служебного слова "in" с перечислением имен говорит о том, что список поступает через параметры команды. Результат предыдущего примера можно получить, набрав
lsort f1 f2 f3
Пример 4.
###
# subdir: Выдает имена всех поддиректориев
# директория с именем $dir
for i in $dir/*
do
if [ - d $i ]
then echo $i
fi
done
Пример 5.
Следующий расчет иллюстрирует полезный, хотя и с долей трюкачества, способ повторения одних и тех же действий несколько раз. Переменная "i" принимает здесь пять значений: 1, 2, 3, 4, 5, но внутри цикла эта переменная отсутствует и поэтому ее значение никакой роли не играет и ни чего не меняет. С таким же успехом переменная "i" могла принимать значения, скажем ф о к у с, а в результате точно также было бы пять раз повторено одно и то же вычисление содержимого цикла без изменений.
###
# print-5: Организации пятикратного выполнения команды
for i in
do
cat file-22 > /dev/lp
done
Пример 6.
Расчет "print-n" иллюстрирует еще одну полезную возможность в использовании цикла "for". Здесь, после "for i...", отсутствуют "in..." и перечень имен, т. е. перечнем имен для "i" становится перечень параметров, а следовательно количество печатаемых экземпляров можно менять.
###
# print-n: Задание числа копий
# через параметры
for i
do
cat file-22 > /dev/lp
done
Смысл не изменится, если первую строку расчета записать как
for i in $*
поскольку значение "$*" - есть список значений параметров.
Отметим различие в специальных переменных "$*" и "$@", представляющих перечень параметров. Первый представляет параметры, как строку, а второй, как совокупность слов.
Пример 7.
Пусть командный файл "cmp" имеет вид:
for i in "$*"
do
echo $i
done
echo
for i in "$@"
do
echo $i
done
При вызове
cmp aa bb cc
на экран будет выведено
aa bb cc
aa
bb
cc
4.2 Оператор выбора
case $<переменная> in
<шаблон> | <шаблон>... ) <список> ;;
. . .
esac
Оператор выбора выполняет <список>, соответствующий первому <шаблону>, которому удовлетворяет <переменная>. Форма шаблона та же, что и используемая для генерации имен файлов. Часть | шаблон... может отсутствовать.
Пример 1.
Определить флаги и откомпилировать все указанные файлы.
# инициализировать флаг
flag=
# повторять для каждого аргумента
for a
do
case $a in
# объединить флаги, разделив их пробелами
-[ocSO]) flag=$flag' ' $a ;;
-*) echo 'unknown flag $a' ;;
# компилировать каждый исходный файл и сбросить флаги
*.c) cc $flag $a; flag= ;;
*.s) as $flag $a; flag= ;;
*.f) f77 $flag $a; flag= ;;
# неверный аргумент
*) echo 'unexpected argument $a' ;;
esac
done
Пример 2.
echo - n " А какую оценку получил на экзамене?: "
read z
case $z in
5) echo Молодец! ;;
4) echo Все равно молодец! ;;
3) echo Все равно! ;;
2) echo Все! ;;
*) echo! ;;
esac
Непривычно выглядят в конце строк выбора ";;", но написать здесь ";" было бы ошибкой. Для каждой альтернативы может быть выполнено несколько команд. Если эти команды будут записаны в одну строку, то символ ";" будет использоваться как разделитель команд.
Обычно последняя строка выбора имеет шаблон "*", что в структуре "case" означает "любое значение". Эта строка выбирается, если не произошло совпадение значения переменной (здесь $z) ни с одним из ранее записанных шаблонов, ограниченных скобкой ")". Значения просматриваются в порядке записи.
Пример 3.
###
# case-3: Справочник.
# Для различных фирм по имени выдается
# название холдинга, в который она входит
case $1 in
ONE|TWO|THREE) echo Холдинг: ZERO ;;
MMM|WWW) echo Холдинг: Not-Net ;;
Hi|Hello|Howdoing) echo Холдинг: Привет! ;;
*) echo Нет такой фирмы ;;
esac
При вызове "case-3 Hello" на экран будет выведено:
Холдинг: Привет!
А при вызове "case-3 HELLO" на экран будет выведено:
Нет такой фирмы
Пример 4.
Коль скоро слово "case" переводится как "выбор", то это как бы намек на то, что можно эту структуру использовать для реализации простейших меню.
###
# case-4: Реализация меню с помощью команды "case"
echo "Назовите файл, а затем (через пробел)
наберите цифру, соответствующую требуемой
обработке:
1 - отсортировать
2 - выдать на экран
3 - определить число строк "
read x y # x - имя файла, y - что сделать
case $y in
1) sort < $x ;;
2) cat < $x ;;
3) wc - l < $x ;;
*) echo "
Мы не знаем
такой команды! " ;;
esac
Разумеется, желания могут быть более сложные и на месте отдельных команд могут быть последовательности команд или вызовы более сложных расчетов.
Пример 5.
Напишем команду "case-5", которая добавляет информацию к файлу, указанного первым параметром (если параметр один), со стандартного входа, либо (если 2 параметра) из файла, указанного в качестве первого параметра:
###
# case-5: Добавление в файл.
# Использование стандартной переменной.
# "$#" - число параметров при вводе расчета
# ">>" - перенаправление с добавлением в файл
case $# in
1) cat >> $1 ;;
2) cat >> $2 < $1 ;;
*) echo "Формат: case-4 [откуда] куда" ;;
esac
"$1" (при "$#=1") - это имя файла, в который происходит добавление со стандартного входа.
"$1" и "$2" (при $#=2) - это имена файлов, из которого ("$1") и в который ("$2") добавлять.
Во всех других случаях (*) выдается сообщение о том, каким должен быть правильный формат команды.
4.3. Условный оператор.
if <список1>
then
<список2>
[ elif <список3>
then
<список4> ]
. . .
[ else
<список5> ]
fi
Выполняется <список1> и, если код его завершения 0, то выполняется <список2>, иначе - <список3> и, если и его код завершения 0, то выполняется <список4>. Если же это не так, то выполняется <список5>. Части elif и else могут отсутствовать.
Примеры.
Пусть написан расчет "if-1"
if [ $1 - gt $2 ]
then pwd
else echo $0 : Hello!
Fi
Тогда вызов расчета
if-1 12 11
даст
/home/sae/STUDY/SHELL
а
if-1 12 13
даст
if-1 : Hello!
Возможно использовать в условии то свойство shell, что команды могут выдавать различный код завершения. Это напоминает приемы программирования на Си. Пусть расчет "if-2" будет
if a=`expr "$1" : "$2"`
then echo then a=$a code=$?
else echo else a=$a code=$?
Fi
тогда вызов
if-2 by by
даст
then a=2 code=0
а
if-2 by be
даст
else a=0 code=1
Еще пример на вложенность
###
# if-3: Оценка достижений
echo - n " А какую оценку получил на экзамене?: "
read z
if [ $z = 5 ]
then echo Молодец!
elif [ $z = 4 ]
then echo Все равно молодец!
elif [ $z = 3 ]
then echo Все равно!
elif [ $z = 2 ]
then echo Все!
else echo!
fi
Можно обратить внимание на то, что желательно использовать сдвиги при записи программ, чтобы лучше выделить вложенность структур.
4.4. Цикл WHILE
while <список1>
do
<список2>
done
До тех пор, пока код завершения последней команды <списка1> есть 0, выполняются команды <списка2>. При замене служебного слова while на until условие выхода из цикла меняется на противоположное.
В качестве одной из команд <списка1> может быть команда true (false). По этой команде не выполняется никаких действий, а код завершения устанавливается 0 (-1). Эти команды применяются для организации бесконечных циклов. Выход из такого цикла можно осуществить лишь по команде break (см. Специальные команды).
Пример 1.
###
# print-50: Структура "while"
# Расчет позволяет напечатать 50
# экземпляров файла "file-22"
n=0
while [ $n - lt 50 ] # пока n < 50
do
n=`expr $n + 1`
cat file-22 > /dev/lp
done
Обратим внимание на то, что переменной "n" вначале присваивается значение 0, а не пустая строка, так как команда "expr" работает с shell-переменными как с целыми числами, а не как со строками.
n=`expr $n + 1`
т. е. при каждом выполнении значение "n" увеличивается на 1.
Пример 2.
Как и вообще в жизни, можно реализовать то же самое и сложнее. Расчет "рr-br" приведен для иллюстрации бесконечного цикла и использования команды "break", которая обеспечивает прекращение цикла.
###
# рr-br: Структура "while" c "break"
# Расчет позволяет напечатать 50
# экземпляров файла "file-22"
n=0
while true
do
if [ $n - lt 50 ] # если n < 50
then n=`expr $n + 1`
else break
fi
cat file-22 > /dev/lp
done
4.5 Функции
<имя> () {
<список>;
}
Определяется функция с именем <имя>. Тело функции - <список>, заключенный между { и }.
Пример.
Вызов на выполнение файла "fun"
echo $$
fn() # описание функции
{
echo xx=$xx
echo $#
echo $0: $$ $1 $2
xx=yy ; echo xx=$xx
return 5
}
xx=xx ; echo xx=$xx
fn a b # вызов функции "fn" с параметрами
echo $?
echo xx=$xx
содержащего описание и вызов функции "fn", выдаст на экран:
749
xx=xx
xx=xx
2
fun: 749 a b
xx=yy
5
xx=yy
4.6. Зарезервированные слова
Следующие слова являются зарезервированными:
if then else elif fi
case in esac { }
for while until do done
4.7. Специальные команды
Как правило, для выполнения каждой команды shell порождает отдельный процесс. Специальные команды отличаются тем, что они встроены в shell и выполняются в рамках текущего процесса.
: | Пустая команда. Возвращает нулевой код завершения. | |
. file | Shell читает и выполняет команды из файла file, затем завершается; при поиске file используется список поиска $PATH. | |
break [n] | Выход из внутреннего for или while цикла; если указано n, то выход из n внутренних циклов. | |
continue [n] | Перейти к следующей итерации внутреннего for или while цикла; если указано n, то переход к следующей итерации n-ого цикла. | |
cd [ <аргумент> ] | Сменить текущую директорию на директорию <аргумент>. По умолчанию используется значение HOME. | |
echo [ <арг> ... ] | Выводит свои аргументы в стандартный вывод, разделяя их пробелами. | |
eval [ <арг> ... ] | Аргументы читаются, как если бы они поступали из стандартного ввода и рассматриваются как команды, которые тут же и выполняются. | |
exec [ <арг> ... ] | Аргументы рассматриваются как команды shell'а и тут же выполняются, но при этом не создается нового процесса. В качестве аргументов могут быть указаны направления ввода-вывода и, если нет никаких других аргументов, то будет изменено лишь направление ввода-вывода текущей программы. | |
exit [ n ] | Завершение выполнения shell'а с кодом завершения n. Если n опущено, то кодом завершения будет код завершения последней выполненной команды (конец файла также приводит к завершению выполнения). | |
export [ <переменная> ... ] | Данные переменные отмечаются для автоматического экспорта в окружение (см. Окружение) выполняемых команд. Если аргументы не указаны, то выводится список всех экспортируемых переменных. Имена функций не могут экспортироваться. | |
hash [ - r ] [ <команда> ... ] | Для каждой из указанных команд определяется и запоминается путь поиска. Опция - r удаляет все запомненные данные. Если не указан ни один аргумент, то выводится информация о запомненных командах: hits - количество обращений shell'а к данной команде; cost - объем работы для обнаружения команды в списке поиска; command - полное имя команды. В некоторых ситуациях происходит перевычисление запомненных данных, что отмечается значком * в поле hits. | |
pwd | Выводит имя текущей директории. | |
read [ <переменная> ... ] | Читается из стандартного ввода одна строка; первое ее слово присваивается первой переменной, второе - второй и т. д., причем все оставшиеся слова присваиваются последней переменной. | |
readonly [ <переменная> ... ] | Запрещается изменение значений указанных переменных. Если аргумент не указан, то выводится информация обо всех переменных типа readonly. | |
return [ n ] | Выход из функции с кодом завершения n. Если n опущено, то кодом завершения будет код завершения последней выполненной команды. | |
set [ --aefkntuvx [ <арг> ... ] ] | Команда устанавливает следующие режимы: | |
-a | отметить переменные, которые были изменены или созданы, как переменные окружения (см. Окружение) | |
-e | если код завершения команды ненулевой, то немедленно завершить выполнение shell'а | |
-f | запретить генерацию имен файлов | |
-k | все переменные с именем помещаются в окружение команды, а не только те, что предшествуют имени команды (см. Окружение) | |
-n | читать команды, но не выполнять их | |
-t | завершение shell'а после ввода и выполнения одной команды | |
-u | при подстановке рассматривать неустановленные переменные как ошибки | |
-v | вывести вводимые строки сразу после их ввода | |
-x | вывести команды и их аргументы перед их выполнением | |
-- | не изменяет флаги, полезен для присваивания позиционным переменным новых значений. | |
При указании + вместо - каждый из флагов устанавливает противоположный режим. Набор текущих флагов есть значение переменной $-. <арг> - это значения, которые будут присвоены позиционным переменным $1, $2 и т. д. Если все аргументы опущены, выводятся значения всех переменных. | ||
shift [ n ] | Позиционные переменные, начиная с $(n+1), переименовываются в $1 и т. д. По умолчанию n=1. | |
test | вычисляет условные выражения (см. Дополнительные сведения. Test ) | |
trap [ <арг> ] [ n ] ... | Команда <арг> будет выполнена, когда shell получит сигнал n (см. Сигналы). (Надо заметить, что <арг> проверяется при установке прерывания и при получении сигнала). Команды выполняются по порядку номеров сигналов. Любая попытка установить сигнал, игнорируемый данным процессом, не обрабатывается. Попытка прерывания по сигналу 11 (segmentation violation) приводит к ошибке. Если <арг> опущен, то все прерывания устанавливаются в их начальные значения. Если <арг> есть пустая строка, то этот сигнал игнорируется shell'ом и вызываемыми им программами. Если n=0, то <арг> выполняется при выходе из shell'а. Trap без аргументов выводит список команд, связанных с каждым сигналом. | |
type [ <имя> ... ] | Для каждого имени показывает, как оно будет интерпретироваться при использовании в качестве имени команды: как внутренняя команда shell'а, как имя файла или же такого файла нет вообще. | |
ulimit [ - f ] [ n ] | Устанавливает размер файла в n блоков; - f - устанавливает размер файла, который может быть записан процессом-потомком (читать можно любые файлы). Без аргументов - выводит текущий размер. | |
umask [ nnn ] | Пользовательская маска создания файлов изменяется на nnn. Если nnn опущено, то выводится текущее значение маски. Пример: после команды umask 755 будут создаваться файлы, которые владелец сможет читать, писать и выполнять, а все остальные - только читать и выполнять. | |
unset [ <имя> ... ] | Для каждого имени удаляет соответствующую переменную или функцию. Переменные PATH, PS1, PS2 и IFS не могут быть удалены. | |
wait [ n ] | Ждет завершения указанного процесса и выводит код его завершения. Если n не указано, то ожидается завершения всех активных процессов-потомков и возвращается код завершения 0. |
Примеры:
· for i in *
· do
· if test - d $i
· then
· break #если директория, то выходим из цикла
· else
· echo $i #иначе печатаем имя файла и начинаем следующую итерацию цикла
· continue
· fi
· done
· сменить текущую директорию на /usr/X11
· $ cd /usr/X11
· вывести на стандартные выход имена всех файлов текущей директории
· $ echo *
· завершить по условию работу программы и возвратить код -1
· & if <условие>
· > then exit -1
· >...
· экспортировать переменные var1 и var2 в окружение
· $ export var1 var2
· запомнить путь поиска команды sed
· $ hash sed
· записать имя текущей директории в файл dir
· $ pwd > dir
· прочитать из стандартного ввода значение переменной tr1
· $ read tr1
· просмотреть список переменных с аттрибутом "только для чтения" и установить этот аттрибут
· для переменной vvreadonly
· $ readonly; readonly vvreadonly
· вывести на экран все переменные окружения
· $ set
· проверить существует ли такая команда или файл sqwreg (т. е. как shell её интерпретирует)
· $ type sqwreg
· задать максимальный размер файла, который может создать процесс/поток, равный 10 блоков
· $ ulimit 10
· просмотреть текущее значение маски
· $ umask
· удалить из окружения переменную var1
· $ uset var1
· ожидать выполнение процесса 711
· wait 711
5. Выполнение shell-программ
5.1. Запуск shell'а
Программа, интерпретирующая shell-программы, находится в файле /bin/sh. При запуске ее первый аргумент является именем shell-программы, остальные передаются как позициональные параметры. Если файл, содержащий shell-программу, имеет право выполнения (x), то достаточно указания лишь его имени. Например, следующие две команды операционной системы эквивалентны (если файл ficofl обладает указанным правом и на самом деле содержит shell-программу):
sh ficofl - d. g\*
и
ficofl - d. g\*
5.2. Выполнение
При выполнении shell-программ выполняются все подстановки. Если имя команды совпадает с именем специальной команды, то она выполнается в рамках текущего процесса. Так же выполняются и определенные пользователем функции. Если имя команды не совпадает ни с именем специальной команды, ни с именем функции, то порождается новый процесс и осуществляется попытка выполнить указанную команду.
Переменная PATH определяет путь поиска директории, содержащей данную команду. По умолчанию это
::/bin:/usr/ bin:/util:/dss/rk
Директории поиска разделяются двоеточиями; :: означает текущую директорию. Если имя команды содержит символ /, значение $PATH не используется: имена, начинающиеся с / ищутся от корня, остальные - от текущей директории. Положение найденной команды запоминается shellом и может быть опрошено командой hash.
5.3. Подстановки shell-интерпретатора
Перед началом непосредственной интерпретации и выполнением команд, содержащихся в командных файлах, shell выполняет различные виды подстановок:
ПОДСТАНОВКА РЕЗУЛЬТАТОВ. Выполняются все команды, заключенные в обратные кавычки, и на их место подставляется результат. ПОДСТАНОВКА ЗНАЧЕНИЙ ПАРАМЕТРОВ И ПЕРЕМЕННЫХ. То есть слова, начинающиеся на "$", заменяются соответствующими значениями переменных и параметров. ИНТЕРПРЕТАЦИЯ ПРОБЕЛОВ. Заэкранированные пробелы игнорируются. ГЕНЕРАЦИЯ ИМЕН ФАЙЛОВ. Проверяются слова на наличие в них спецсимволов ("*", "?","[]") и выполняются соответствующие генерации.5.4. Окружение
Окружение - это набор пар имя-значение, которые передаются выполняемой программе. Shell взаимодействует с окружением несколькими способами. При запуске shell создает переменную для каждой указанной пары, придавая ей соответствующее значение. Если вы измените значение какой-либо из этих переменных или создадите новую переменную, то это не окажет никакого влияния на окружение, если не будет использована команда export для связи переменной shell'а с окружением (см. также set - a). Переменная может быть удалена из окружения командой unset (см.). Таким образом, окружение каждой из выполняемых shell'ом команд формируется из всех неизмененных пар имя-значение, первоначально полученных shell'ом, минус пары, удаленные командой unset, плюс все модифицированные и измененные пары, которые для этого должны быть указаны в команде export.
Окружение простых команд может быть сформировано указанием перед ней одного или нескольких присваиваний переменным. Так,
TERM=d460 <команда>
и
(export TERM; TERM=d460; <команда>)
эквивалентны. Переменные, участвующие в таких присваиваниях, назовем ключевыми параметрами.
Если установлен флаг - k (см. set), то все ключевые параметры помещаются в окружение команды, даже если они записаны после команды.
5.5. Сигналы
UNIX'ом поддерживаются следующие сигналы:
SIGHUP | - 1 - | отменить (hangup) |
SIGINT | - 2 - | прерывание (interrupt) |
SIGQUIT | - 3 - | нестандартный выход (quit) |
SIGILL | - 4 - | неверная команда (illegal instruction) |
SIGTRAP | - 5 - | ловушка (trace trap) |
SIGFPE | - 8 - | исключительная ситуация при выполнении операций с плавающей запятой (floating-point exception) |
SIGKILL | - 9 - | уничтожение процесса (kill) |
SIGBUS | - 10 - | ошибка шины (bus error) |
SIGSEGV | - 11 - | нарушение сегментации (segmentation violation) |
SIGSYS | - 12 - | неверный системный вызов (bad argument to system call) |
SIGPIPE | - 13 - | запись в канал без чтения из него (write on a pipe with no one to read it) |
SIGALRM | - 14 - | будильник (alarm clock) |
SIGTERM | - 15 - | программное завершение процесса (software termination signal) |
Сигналы SIGINT и SIGQUIT игнорируются, если команда была запущена асинхронно. Иначе сигналы обрабатываются так же, как в процессе-предке, за исключением сигнала SIGSEGV (см. также Специальные команды. Trap).
5.6. Замечания
При выполнении команд запоминается их местонахождение. Поэтому при создании команды с тем же именем, но находящейся в другой директории, все равно будет выполняться старая команда (если вызов происходит по короткому имени). Для исправления ситуации воспользуйтесь командой hash с ключом - r (см. Специальные команды).
Если вы переименовали текущую или вышележащую директорию, то команда pwd может давать неверную информацию. Для исправления ситуации воспользуйтесь командой cd с полным именем директории.
6. Дополнительные сведения
6.1. Команда test
Команда test проверяет выполнение некоторого условия. С использованием этой (встроенной) команды формируются операторы выбора и цикла языка shell. (См. Оператор выбора, Условный оператор, Цикл WHILE)
Два возможных формата команды:
test условие
или
[ условие ]
мы будем пользоваться вторым вариантом, т. е. вместо того, чтобы писать перед условием слово "test", будем заключать условие в скобки, что более привычно для программистов.
На самом деле shell будет распознавать эту команду по открывающей скобке "[", как слову(!), соответствующему команде "test". Уже этого достаточно, чтобы предупредить о распространенной ошибке начинающих: Между скобками и содержащимся в них условием обязательно должны быть пробелы.
Пробелы должны быть и между значениями и символом сравнения или операции (как, кстати, и в команде "expr"). Не путать с противоположным требованием для присваивания значений переменным.
В shell используются условия различных "типов".
УСЛОВИЯ ПРОВЕРКИ ФАЙЛОВ:
-f file | файл "file" является обычным файлом; |
-d file | файл "file" - каталог; |
-с file | файл "file" - специальный файл; |
-r file | имеется разрешение на чтение файла "file"; |
-w file | имеется разрешение на запись в файл "file"; |
-s file | файл "file" не пустой. |
Примеры. Вводя с клавиатуры командные строки в первом случае получим подтверждение (код завершения "0"), а во втором - опровержение (код завершения "1"). "specific" - имя существующего файла.
[ - f specific ] ; echo $?
0
[ - d specific ] ; echo $?
1
УСЛОВИЯ ПРОВЕРКИ СТРОК:
str1 = str2 | строки "str1" и "str2" совпадают; |
str1 != str2 | строки "str1" и "str2" не совпадают; |
-n str1 | строка "str1" существует (непустая); |
-z str1 | строка "str1" не существует (пустая). |
Примеры.
x="who is who"; export x; [ "who is who" = "$x" ]; echo $?
0
x=abc ; export x ; [ abc = "$x" ] ; echo $?
0
x=abc ; export x ; [ - n "$x" ] ; echo $?
0
x="" ; export x ; [ - n "$x" ] ; echo $?
1
Команда "test" дает значение "истина" (т. е. код завершения "0") и просто если в скобках стоит непустое слово.
Кроме того, существуют два стандартных значения условия, которые могут использоваться вместо условия (для этого не нужны скобки).
true ; echo $?
0
false ; echo $?
1
УСЛОВИЯ СРАВНЕНИЯ ЦЕЛЫХ ЧИСЕЛ:
x - eq y | "x" равно "y", |
x - ne y | "x" неравно "y", |
x - gt y | "x" больше "y", |
x - ge y | "x" больше или равно "y", |
x - lt y | "x" меньше "y", |
x - le y | "x" меньше или равно "y". |
То есть в данном случае команда "test" воспринимает строки символов как целые (!) числа. Поэтому во всех остальных случаях "нулевому" значению соответствует пустая строка. В данном же случае, если надо обнулить переменную, скажем, "x", то это достигается присваиванием "x=0".
Примеры.
x=abc ; export x ; [ abc - eq "$x" ] ; echo $?
"[": integer expression expected before - eq
x=321 ; export x ; [ 321 - eq "$x" ] ; echo $?
0
x=3.21 ; export x ; [ 3.21 - eq "$x" ] ; echo $?
"[": integer expression expected before - eq
x=321 ; export x ; [ 123 - lt "$x" ] ; echo $?
0
СЛОЖНЫЕ УСЛОВИЯ:
Реализуются с помощью типовых логических операций:
! | (not) инвертирует значение кода завершения. |
-o | (or) соответствует логическому "ИЛИ". |
-a | (and) соответствует логическому "И". |
ПРЕДУПРЕЖДЕНИЕ. Не забывайте о пробелах.
Примеры.
[ ! privet ] ; echo $?
1
x=privet; export x; [ "$x" - a - f specific ] ; echo $?
0
x="";export x; [ "$x" - a - f specific ] ; echo $?
1
x="";export x; [ "$x" - a - f specific - o privet ] ; echo $?
0
x="";export x; [ "$x" - a - f specific - o! privet ] ; echo $?
1
6.2. Команда expr
Команда expr применяется для вычисления выражений. Результат выводится на стандартный вывод. Операнды выражения должны быть разделены пробелами. Метасимволы должны быть экранированы. Надо заметить, что 0 возвращается в качестве числа, а не для индикации пустой строки. Строки, содержащие пробелы или другие специальные символы, должны быть заключены в кавычки. Целые рассматриваются как 32-битные числа.
Ниже приведен список операторов в порядке возрастания приоритета, операции с равным приоритетом заключены в фигурные скобки. Перед символами, которые должны быть экранированы, стоит \.
<выр> \| <выр> | если первое <выр> не пустое и не нулевое, то возвращает его, иначе возвращает второе <выр> |
<выр> \& <выр> | если оба <выр> не пустые и не нулевые, то возвращает первое <выр>, иначе возвращает 0 |
<выр> { =, \>, \>=, \<, \<=, != } <выр> | возвращает результат целочисленного сравнения если оба <выр> - целые; иначе возвращает результат лексического сравнения |
<выр> { +, - } <выр> | сложение и вычитание целочисленных аргументов |
<выр> { \*, /, % } <выр> | умножение, деление и получение остатка от деления целочисленных аргументов |
<выр> : <выр> | оператор сопоставления : сопоставляет первый аргумент со вторым, который должен быть регулярным выражением. Обычно оператор сравнения возвращает число символов, удовлетворяющих образцу (0 при неудачном сравнении). Однако символы \( и \) могут применяться для выделения части первого аргумента. |
Регулярное выражение строится следующим образом:
. | - обозначает любой символ |
* | - обозначает предыдущий символ, повторенный несколько раз |
[] | - обозначают любой один из указанных между ними символов; группа символов может обозначаться с помощью знака "-" (т. е. [0-9] эквивалентно []); если после [ стоит ^, то это эквивалентно любому символу, кроме указанных в скобках и <возврата_каретки>; для указания ] в качестве образца, надо поставить ее сразу за [ (т. е. []...]); . и * внутри квадратных скобок обозначают самих себя |
Более подробная информация о регулярных выражениях находится по адресу www. asu. pstu. *****/unix/regular_expression.
Все остальные символы (и ^, если стоит не в квадратных скобках) обозначают самих себя. Для указания символов., *,[ и ] надо экранировать их (т. е. писать \., \*, \[, \]).
Примеры.
1.
a=`expr $a + 1`
- увеличение на 1 переменной a
2.
expr $a : '.*/\(.*\)' \| $a
- выделяет из имени файла короткое имя (т. е. из /usr/util/ena выделяется ena). Внимание, одиночный символ / будет воспринят как знак операции деления.
3.
expr $VAR : '.*'
- получение количества символов переменной VAR.
В качестве побочного эффекта expr возвращает следующие коды завершения:
0 | - если выражение не нуль и не пустая строка |
1 | - если выражение нуль или пустая строка |
2 | - для некорректных выражений |
Команда expr также выдает следующие сообщения об ошибках:
syntax error | - для ошибок в операторах или операндах |
non-numeric argument | - для попыток применения арифметических операций к нечисловым строкам |
Замечание.
Допустим, что мы хотим сравнить значение переменной a с каким-либо символом, имеющим для expr особый смысл, например, со знаком равенства. Пусть $a на самом деле является знаком равенства. Так как аргументы предварительно обрабатываются shell'ом, то команда
expr $a = '='
будет воспринята как
expr = = =
что синтаксически некорректно. В подобных случаях надо пользоваться таким приемом:
expr X$a = X=
т. е. добавлением некоторого символа к обеим строкам, что никак не влияет на результат сравнения, однако позволяет избежать синтаксической ошибки.
7. Контрольные задания
Вопрос. | Ответ. |
Вывести содержимое переменной PATH без перехода на новую строку | echo - n $PATH |
C новой страницы выведите предложение, разделяя слова табуляцией | echo - e "\fслова\tиз\tкоторых\tcостоит\tпредложение" |
Вывести значения переменных PS1 и PS2 в файл, разделив их обратным слэшем | echo - e "$PS1\\$PS2" > filename |
Добавить строку "Hello, World!" в файл | echo "Hello, World!" >> filename |
Получить эхо имён файлов по одному в строке | for i in * |
Посылка письма адресатам из списка в файле | mail `cat mailinglist` < letter |
Удалить все файлы, оканчивающиеся на. bak | rm *.bak |
Вывести через пять минут сообщение о том, что чай готов. Процесс запустить в фоновом режиме. | (sleep 300; echo Чай готов) & |
Удалить из текущего каталога и его подкаталогов все файлы нулевого размера, запрашивая подтверждение | find. - size 0c - ok rm {} ';' |
Закройте свой домашний каталог (в директории home) для всех пользователей кроме себя | chmod o-xw /home/alex |
Вывести последние 100 строк файла с сортировкой и с возможностью постепенного просмотра | tail -100 filename | sort | more |
Написать фрагмет программы на shell, который при отсутствии почты, переадресовывает всю почту на другой адресат, например alex. | if [mail - e - eq 0]; then mail - F "alex"; fi. |
Выяснить, работает ли mary в системе | who | grep Mary |
Выполнить задание через неделю в 6 часов вечера | at 6pm today+week |


