Программирование в shell. Программирование на Shell

27.03.2019

Командный язык shell (в переводе - раковина, скорлупа) фактически есть язык программирования очень высокого уровня. На этом языке пользователь осуществляет управление компьютером. Обычно, после входа в систему вы начинаете взаимодействовать с командной оболочкой. Признаком того, что оболочка (shell) готова к приему команд служит выдаваемый ею на экран промптер. В простейшем случае это один доллар ("$"). Shell не является необходимым и единственным командным языком (хотя именно он стандартизован в рамках POSIX - стандарта мобильных систем). Например, немалой популярностью пользуется язык cshell, есть также kshell, bashell и другие. Более того, каждый пользователь может создать свой командный язык. Может одновременно на одном экземпляре операционной системы работать с разными командными языками. shell - это одна из многих команд UNIX. То есть в набор команд оболочки "shell" входит команда "sh" - вызов интерпретатора "shell". Первый "shell" вызывается автоматически при вашем входе в систему и выдает на экран промтер. После этого вы можете вызывать на выполнение любые команды, в том числе и снова сам "shell", который вам создаст новую оболочку внутри прежней. Так например, если вы подготовите в редакторе файл "file_1":

Echo Hello!

то это будет обычный текстовый файл, содержащий команду "echo", которая при выполнении выдает все написанное правее ее на экран. Можно сделать файл "file_1" выполняемым с помощью команды "chmod 755 file_1". Но его можно выполнить, вызвав явно команду "sh" ("shell"):

Sh file_1

Sh < file1

Файл можно выполнить и в текущем экземпляре "shell". Для этого существует специфическая команда "." (точка), т.е.

File_1

Поскольку UNIX - система многопользовательская, вы можете даже на персональном компьютере работать параллельно, скажем, на 12-ти экранах (переход с экрана на экран ALT/функциональная клавиша), имея на каждом экране нового (или одного и того же) пользователя со своей командной оболочкой. Можете и в графическом режиме X-Window также открыть большое число окон, а в каждом окне может быть свой пользователь со своей командной оболочкой... Стержневым элементом языка shell является команда.

Структуры команд:

Команды в shell обычно имеют следующий формат:

<имя команды> <флаги> <аргумент(ы)>

Например:

Ls -ls /usr/bin

Где ls - имя команды выдачи содержимого директория, -ls - флаги ("-" - признак флагов, l - длинный формат, s - об"ем файлов в блоках), /usr/bin - директорий, для которого выполняется команда. Эта команда выдаст на экран в длинном формате содержимое директория /usr/bin, при этом добавит информацию о размере каждого файла в блоках. К сожалению, такая структура команды выдерживается далеко не всегда. Не всегда перед флагами ставится минус, не всегда флаги идут одним словом. Есть разнообразие и в представлении аргументов. К числу команд, имеющих экзотические форматы, относятся и такие "ходовые" команды, как сс - вызов компилятора языка С, tar - работа с архивами, dd - копирование файла с преобразованием, find - поиск файлов и ряд других. Как правило, первое слово shell воспринимает, как команду. Поэтому в командной строке

первое слово будет расшифровано shell, как команда (конкатенации), которая выдаст на экран файл с именем "cat" (второе слово), находящийся в текущем директории. Перенаправление команд Стандартный ввод (вход) - "stdin" в ОС UNIX осуществляется с клавиатуры терминала, а стандартный вывод (выход) - "stdout" направлен на экран терминала. Существует еще и стандартный файл диагностических сообщений - "stderr", о котором речь будет чуть позже. Команда, которая может работать со стандартным входом и выходом, называется ФИЛЬТРОМ. Пользователь имеет удобные средства перенаправления ввода и вывода на другие файлы (устройства). Символы ">" и ">>" обозначают перенаправление вывода. ls >file_1 команда "ls" сформирует список файлов текущего каталога и поместит его в файл "file_1" (вместо выдачи на экран). Если файл "file_1" до этого существовал, то он будет затерт новым.

Pwd >>file_1

команда pwd сформирует полное имя текущего каталога и поместит его в конец файла "file_1", т.е. ">>" добавляет в файл, если он непустой. Символы "<" и "<<" обозначают перенаправление ввода.

Wc -l

подсчитает и выдаст на экран число строк в файле file_1.

Ed file_2 <

создаст с использованием редактора файл "file_2", непосредственно с терминала. Окончание ввода определяется по символу, стоящему правее "<<" (т. е. "!"). То есть ввод будет закончен, когда первым в очередной строке будет "!". Можно сочетать перенаправления. Так

Wc -l file_4

Wc -l >file_4

выполняются одинаково: подсчитывается число строк файла "file_3" и результат помещается в файл "file_4". Средство, объединяющее стандартный выход одной команды со стандартным входом другой, называется КОНВЕЙЕРОМ и обозначается вертикальной чертой "|".

Ls | wc -l

список файлов текущего каталога будет направлен на вход команды "wc", которая на экран выведет число строк каталога. Конвейером можно объединять и более двух команд, когда все они, возможно кроме первой и последней - фильтры:

Cat file_1 | grep -h result | sort | cat -b > file_2

Данный конвейер из файла "file_1" ("cat") выберет все строки, содержащие слово "result" ("grep"), отсортирует ("sort") полученные строки, а затем пронумерует ("cat -b") и выведет результат в файл "file_2". Поскольку устройства в ОС UNIX представлены специальными файлами, их можно использовать при перенаправлениях. Специальные файлы находятся в каталоге "/dev". Например, "lp" - печать; "console" - консоль; "ttyi" - i-ый терминал; "null" - фиктивный (пустой) файл (устройство). Тогда, например,

Ls > /dev/lp

выведет содержимое текущего каталога на печать, а file_1 < /dev/null обнулит файл "file_1".

Sort file_1 | tee /dev/lp | tail -20

В этом случае будет отсортирован файл "file_1" и передан на печать, а 20 последних строк также будут выданы на экран. Вернемся к перенаправлению выхода. Стандартные файлы имеют номера:

0 - stdin, 1 - stdout 2 - stderr. Если вам не желательно иметь на экране сообщение об ошибке, вы можете перенаправить его с экрана в указанный вами файл (или вообще "выбросить", перенаправив в файл "пустого устройства" - /dev/null). Например при выполнении команды

Cat file_1 file_2

которая должна выдать на экран последовательно содержимое файлов "file_1" и "file_2", выдаст вам, например, следующее

111111 222222 cat: f2: No such file or directory

где 111111 222222 - содержимое файла "file_1", а файл "file_2" отсутствует, о чем команда "cat" выдала сообщение в стандартный файл диагностики, по умолчанию, как и стандартный выход, представленный экраном. Если вам не желательно такое сообщение на экране, его можно перенаправить в указанный вами файл:

Cat file_1 file_2 2>f-err

сообщения об ошибках будут направляться (об этом говорит перенаправление "2>") в файл "f-err". Кстати, вы можете всю информацию направлять в один файл "ff", использовав в данном случае конструкцию

Cat file_1 file_2 >>ff 2>ff

Можно указать не только какой из стандартных файлов перенаправлять, но и в какой стандартный файл осуществить перенаправление.

Cat file_1 file_2 2>>ff 1>&2

Здесь сначала "stderr" перенаправляется (в режиме добавления) в файл "ff", а затем стандартный выход перенаправляется на "stderr", которым к этому моменту является файл "ff". То есть результат будет аналогичен предыдущему. Конструкция "1>&2" - означает, что кроме номера стандартного файла, в который перенаправить, необходимо впереди ставить "&"; вся конструкция пишется без пробелов. <- закрывает стандартный ввод. >- закрывает стандартный вывод. Командные файлы. Для того, чтобы текстовый файл можно было использовать как команду, существует несколько возможностей. Пусть с помощью редактора создан файл с именем "cmd", содержащий одну строку следующего вида:

Date; pwd; ls

Можно вызвать shell как команду, обозначаемую "sh", и передать ей файл "cmd", как аргумент или как перенаправленный вход, т.е.

$ sh cmd

$ sh

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

Chmod 711 cmd

сделает код защиты "rwx__x__x". Тогда простой вызов

приведет к выполнению тех же трех команд. Результат будет тот же, если файл с содержимым

Date; pwd; ls

представлен в виде: date pwd ls так как переход на другую строку также является разделителем в последовательности команд. Таким образом, выполняемыми файлами могут быть не только файлы, полученные в результате компиляции и сборки, но и файлы, написанные на языке shell. Их выполнение происходит в режиме интерпретации с помощью shell-интерпретатора

Отладка командных файлов

В SHELL используются два механизма отладки командных файлов. Первый из них: set -v выводит строки командного файла по мере их чтения. Этот режим применяется при поиске синтаксических ошибок. Для его использования не требуется производить модификацию командного файла, например: sh -v proc... здесь proc - имя командного файла. Ключ -v может использоваться вместе с ключом -n, предотвращающим выполнение следующих за ним команд (команда set -n блокирует терминал до тех пор, пока не вводится признак конца файла EOF). Команда set -х выводит команды по мере их выполнения, причём на терминал выводятся строки программы и на место переменных подставляются их значения. Для отмены ключей -x и -v можно воспользоваться командой set - а для установки - присвоить соответствующее значение макропеременной. СРЕДА SHELL (ПЕРЕМЕННЫЕ И ПАРАМЕТРЫ) На языке shell можно писать командные файлы и с помощью команды "chmod" делать их выполняемыми. После этого они ни чем не отличаются от прочих команд ОС UNIX.

Shell-переменные

Имя shell-переменной - это начинающаяся с буквы последовательность букв, цифр и подчеркиваний. Значение shell-переменной - строка символов. То, что в shell всего два типа данных: строка символов и текстовый файл, с одной стороны, позволяет легко вовлекать в программирование конечных пользователей, никогда ранее программированием не занимавшихся, а с другой стороны, вызывает некий внутренний протест у многих программистов, привыкших к существенно большему разнообразию и большей гибкости языковых средств. Однако интересно наблюдать то, как высококлассные программисты, освоившись с "правилами игры" shell, пишут на нем программы во много раз быстрее, чем на Си, но, что особенно интересно, в ряде случаев эти программы работают даже быстрее, чем реализованные на Си. Имя переменной аналогично традиционному представлению об идентификаторе, т.е. именем может быть последовательность букв, цифр и подчеркиваний, начинающаяся с буквы или подчеркивания. Для присваивания значений переменным может использоваться оператор присваивания "=".

Var_1=13 - "13" - это не число, а строка из двух цифр. var_2="ОС UNIX" - здесь двойные кавычки (" ") необходимы, так как в строке есть пробел.

Возможны и иные способы присваивания значений shell-переменным. Так например запись,

DAT=`date`

приводит к тому, что сначала выполняется команда "date" (обратные кавычки говорят о том, что сначала должна быть выполнена заключенная в них команда), а результат ее выполнения, вместо выдачи на стандартный выход, приписывается в качестве значения переменной, в данном случае "DAT". Можно присвоить значение переменной и с помощью команды "read", которая обеспечивает прием значения переменной с (клавиатуры) дисплея в диалоговом режиме. Обычно команде "read" в командном файле предшествует команда "echo", которая позволяет предварительно выдать какое-то сообщение на экран. Например:

Echo -n "Введите трехзначное число:" read x

При выполнении этого фрагмента командного файла, после вывода на экран сообщения

Введите трехзначное число:

интерпретатор остановится и будет ждать ввода значения с клавиатуры. Если вы ввели, скажем, "753" то это и станет значением переменной "x". Одна команда "read" может прочитать (присвоить) значения сразу для нескольких переменных. Если переменных в "read" больше, чем их введено (через пробелы), оставшимся присваивается пустая строка. Если передаваемых значений больше, чем переменных в команде "read", то лишние игнорируются. При обращении к shell-переменной необходимо перед именем ставить символ "$". Так команды echo $var_2 echo var_2 выдадут на экран

ОС UNIX var_2 Экранирование

Рассмотрим более подробно приемы экранирования, используемые в shell. В качестве средств экранирования используются двойные кавычки (" "), одинарные кавычки (" ") и бэк-слэш (\). Из примеров очевидно их действие: Можно в одной строке записывать несколько приcваиваний.

X=22 y=33 z=$x A="$x" B="$x" C=\$x D="$x + $y + $z" E="$x + $y + $z" F=$x\ +\ $y\ +\ $z

(присваивание G=$x+$y не было бы выполнено из-за пробелов) Тогда

Echo A = $A B = $B C = $C echo D = $D E = $E F = $F eval echo evaluated A = $A eval echo evaluated B = $B eval echo evaluated C = $C

Выдадут на экран

A = 22 B = $x C = $x D = 22 + 33 + 22 E = $x + $y + $z F = 22 + 33 + 22 evaluated A = 22 evaluated B = 22 evaluated C = 22

Приведем еще примеры, связанные с экранированием перевода строки. Пусть переменной "string" присвоено значение "массива" 2x3: abc def Обратим внимание, что для избежания присваивания лишних пробелов вторая строка массива начата с первой позиции следующей строки: string="abc def" Тогда три варианта записи переменной в команде "echo" echo $string echo "$string" echo "$string" дадут соответственно три различных результата: abc def $string abc def а последовательность команд echo "str_1 str_2" > file_1 echo "str_1 str_2" > file_2 cat file_1 file_2 даст выдаст последовательно одинаковые файлы file_1 и file_2: str_1 str_2 str_1 str_2 Заметим также, что бэк-слэш (\) не только экранирует следующий за ним символ, что позволяет использовать специальные символы просто как символы, представляющие сами себя (он может экранировать и сам себя - \\), но в командном файле бэк-слэш позволяет об"единять строки в одну (экранировать конец строки). Например, приводившийся ранее пример командной строки:

Cat file_1 | grep -h result | sort | cat -b > file_2

может быть записан в командном файле, скажем, как

Cat file_1 | grep -h \ result | sort | cat -b > file_2

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

Cat file_1 | grep -h result | sort | cat -b > file_2

Манипуляции с shell-переменными Несмотря на то, что shell-переменные в общем случае воспринимаются как строки, т. е. "35" - это не число, а строка из двух символов "3" и "5", в раде случаев они могут интерпретироваться иначе, например, как целые числа. Разнообразные возможности имеет команда "expr". Проиллюстрируем некоторые на примерах: Выполнение командного файла:

X=7 y=2 a=`expr $x + $y` ; echo a=$a a=`expr $a + 1` ; echo a=$a b=`expr $y - $x` ; echo b=$b c=`expr $x "*" $y` ; echo c=$c d=`expr $x / $y` ; echo d=$d e=`expr $x % $y` ; echo e=$e

выдаст на экран

A=9 a=10 b=-5 c=14 d=3 e=1

Операция умножения ("*") обязательно должна быть заэкранирована, поскольку в shell этот значок воспринимается, как спецсимвол, означающий, что на это место может быть подставлена любая последовательность символов. С командой "expr" возможны не только (целочисленные) арифметические операции, но и строковые:

A=`expr "cocktail" : "cock"` ; echo $A B=`expr "cocktail" : "tail"` ; echo $B C=`expr "cocktail" : "cook"` ; echo $C D=`expr "cock" : "cocktail"` ; echo $D

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

4 0 0 0

Экспорт переменных В ОС UNIX существует понятие процесса. Процесс возникает тогда, когда запускается на выполнение какая-либо команда. Например, при наборе на клавиатуре "р " порождается процесс "р". В свою очередь "р" может породить другие процессы. Допустим, что "р" вызывает "р1" и "р2", которые последовательно порождают соответствующие процессы. У каждого процесса есть своя среда - множество доступных ему переменных. Например, до запуска "р" уже существовала среда, в которой уже были определены некоторые переменные. Запуск "р" порождает новую среду; уже в ней будут порождены "р1" и "р2". Переменные локальны в рамках процесса, в котором они объявлены, т.е. где им присвоены значения. Для того, чтобы они были доступны и другим порождаемым процессам, надо передать их явным образом. Для этого используется встроенная команда "export".

Параметры

В командный файл могут быть переданы параметры. В shell используются позиционные параметры (т.е. существенна очередность их следования). В командном файле соответствующие параметрам переменные (аналогично shell-переменным) начинаются с символа "$", а далее следует одна из цифр от 0 до 9: Пусть "examp-1" вызывается с параметрами "cock" и "tail". Эти параметры попадают в новую среду под стандартными именами "1" и "2". В (стандартной) переменной с именем "0" будет храниться имя вызванного расчета. При обращении к параметрам перед цифрой ставится символ доллара "$" (как и при обращении к переменным): $0 соответствует имени данного командного файла; $1 первый по порядку параметр; $2 второй параметр и т.д. Поскольку число переменных, в которые могут передаваться параметры, ограничено одной цифрой, т.е. 9-ю ("0", как уже отмечалось имеет особый смысл), то для передачи большего числа параметров используется специальная команда "shift". Своеобразный подход к параметрам дает команда "set". Например, фрагмент

Set a b с echo первый=$1 второй=$2 третий=$3

выдаст на экран

Первый=a второй=b третий=c

т.е. команда "set" устанавливает значения параметров. Это бывает очень удобно. Например, команда "date" выдает на экран текущую дату, скажем, "Mon May 01 12:15:10 2000", состоящую из пяти слов, тогда

Set `date` echo $1 $3 $5

выдаст на экран

Mon 01 2000

Команда "set" позволяет также осуществлять контроль выполнения программы, например: set -v на терминал выводятся строки, читаемые shell. set +v отменяет предыдущий режим. set -x на терминал выводятся команды перед выполнением. set +x отменяет предыдущий режим. Команда "set" без параметров выводит на терминал состояние программной среды.

Подстановки shell-интерпретатора

Перед началом непосредственной интерпретации и выполнением команд, содержащихся в командных файлах, shell выполняет различные виды подстановок: 1. ПОДСТАНОВКА РЕЗУЛЬТАТОВ. Выполняются все команды, заключенные в обратные кавычки, и на их место подставляется результат. 2. ПОДСТАНОВКА ЗНАЧЕНИЙ ПАРАМЕТРОВ И ПЕРЕМЕННЫХ. То есть слова, начинающиеся на "$", заменяются соответствующими значениями переменных и параметров. 3. ИНТЕРПРЕТАЦИЯ ПРОБЕЛОВ. Заэкранированные пробелы игнорируются. 4. ГЕНЕРАЦИЯ ИМЕН ФАЙЛОВ. Проверяются слова на наличие в них спецсимволов ("*", "?","") и выполняются соответствующие генерации. Программная среда Каждый процесс имеет среду, в которой он выполняется. Shell использует ряд переменных этой среды. Если вы наберете команду "set" без параметров, то на экран будет выдана информация о ряде стандартных переменных, созданных при входе в систему (и передаваемых далее всем вашим новым процессам "по наследству"), а также переменных, созданных и экспортируемых вашими процессами. Конкретный вид и содержание выдаваемой информации в немалой степени зависит от того, какая версия UNIX используется и как инсталлирована система.

Результат выполнения команды set без параметров (не полный):

HOME=/root PATH=/usr/local/bin:/usr/bin:/bin:.:/usr/bin/X11: IFS= LOGNAME=sae MAIL=/var/spool/mail/sae PWD=/home/sae/STUDY/SHELL PS1=${PWD}:" " PS2=> SHELL=/bin/bash

Прокомментируем значения переменных. HOME=/root - это имя домашнего директория, в котором пользователь оказывается после входа в систему. То есть, правильно набрав имя и пароль, я окажусь в директории "/root". PATH=/bin:/usr/bin:.:/usr/local/bin:/usr/bin/X11 - эта переменная задает последовательность файлов, которые просматривает "shell" в поисках команды. Имена файлов разделяются здесь двоеточиями. Последовательность просмотра соответствует очередности следования имен в тропе. Но первоначально поиск происходит среди так называемых встроенных команд. В число встроенных команд входят наиболее часто используемые команды, например "echo", "cd", "pwd", "date". После этого система просматривает директорий "/bin", в котором могут находиться команды "sh", "cp", "mv", "ls" и т.п. Затем директорий "/usr/bin" с командами "cat", "сс", "expr", "nroff", "man" и многими другими. Далее поиск происходит в текущем директории (".", или другое обозначение "пусто", т.е.""), где скорее всего находятся написанные вами команды. После набора командной строки и нажатия "shell" (после выполнения необходимых подстановок) распознает имя, соответствующее команде и осуществляет ее поиск в директориях, перечисленных в PATH. Если команда размещена вне этих директориев, она не будет найдена. Если присутствует несколько команд с одинаковым именем, то вызвана будет та, которая расположена в директории, просматриваемом первым. PATH, как и прочие переменные, можно легко менять, добавляя, переставляя или исключая директории. IFS= (Внутренний Разделитель Полей) перечисляет символы, которые служат для разделения слов (полей). Таковыми являются "пробел", "табуляция" и "перевод строки", поэтому здесь слева от присваивания ничего не видно и занято две строки. LOGNAME=root - имя входа ("имя" пользователя). MAIL=/var/spool/mail/root - имя файла, в который поступает (электронная) почта. PWD=/root - имя текущего директория PS1=${PWD}:" " - вид промтера. В данном случае в промптере будет выдаваться имя текущего директория двоеточие и пробел. То есть здесь будет "/root: ". PS2=> - этот промтер (здесь ">") используется как приглашение к продолжению ввода (в очередной строке) незаконченной команды. Например, наберите открывающую скобку "(" и после нажатия в следующей строке вы увидите этот промптер. Если пока не знаете, что дальше делать, наберите закрывающую скобку ")" и он исчезнет. SHELL=/bin/sh - эта переменная указывает оболочку, которую использует пользователь. В данном случае используется стандартный shell ("sh"). Исходная среда устанавливается автоматически при входе в систему с использованием файлов типа "/etc/rc" и "/etc/.profile". Один из способов просто изменит среду (например, тропу поиска команд, вид промтера, вид оболочки, цвет экрана и т.п.) можно, разместив эту информацию в своем домашнем директории в специализированном файле ".profile" (${HOME}/.profile), присвоив нужные значения переменным среды. То есть вызвать это файл в редактор и написать, что пожелаете). Тогда при каждом вашем входе в систему этот файл будет автоматически выполняться и устанавливать новую среду. Этот файл должен ОБЯЗАТЕЛЬНО размещаться в вашем ДОМАШНЕМ директории (директории входа). Следует иметь в виду, что имена файлов, начинающиеся с точки, вообще имеют особый статус. Так, они не выдаются на экран простой командой "ls" - необходимо вызывать эту команду с флагом "-a". Кстати, и не уничтожаются огульно командой "rm *". Сам интерпретатор shell автоматически присваивает значения следующим переменным (параметрам): ? значение, возвращенное последней командой; $ номер процесса; ! номер фонового процесса;

  1. число позиционных параметров, передаваемых в shell;
  • перечень параметров, как одна строка;

@ перечень параметров, как совокупность слов; - флаги, передаваемые в shell. При обращении к этим переменным (т.е при использовании их в командном файле - shell-программе) следует впереди ставить "$". Важную роль при создании уникальных файлов играет специальная переменная "$$", значение которой соответствует номеру процесса, выполняющего данный расчет. Каждый новый расчет, выполняемый компьютером, инициирует один или несколько процессов, автоматически получающих номера по порядку. Поэтому, используя номер процесса в качестве имени файла, можно быть уверенным, что каждый новый файл будет иметь новое имя (не запишется на место уже существующего). Достоинство является и главным недостатком такого способа именования файлов. Неизвестно, какие имена будут присвоены файлам. И, если в рамках данного процесса можно найти файл "не глядя", т.е., обратившись к нему, используя $$, то потом такие файлы можно легко потерять. Это создает дополнительные проблемы при отладке программ. Вызов интерпритатора Вслед за регистрацией пользователя в системе (с помощью команды login) вызывается интерпретатор языка SHELL. Если регистрационный справочник пользователя содержит файл.profile, то прежде чем с терминала будет принята хотя бы одна команда, интерпретатор выполняет этот файл (подразумевается, что файл.profile содержит команды). При вызове могут указываться следующие ключи: -c строка Команды считываются из заданной строки. -s Команды читаются из стандартного файла ввода. Сообщения интерпретатора записываются в стандартный файл диагностик. -i Интерактивный режим работы. Если первым символом параметра "0" является знак -, то команды считываются из файла.profile.

ПРОГРАММНЫЕ СТРУКТУРЫ===

Как во всяком языке программирования в тексте на языке shell могут быть комментарии. Для этого используется символ "#". Все, что находится в строке (в командном файле) левее этого символа, воспринимается интерпретатором как комментарий. Например,

# Это комментарий.

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

Команда test ("")

Команда test проверяет выполнение некоторого условия. С использованием этой (встроенной) команды формируются операторы выбора и цикла языка shell. Два возможных формата команды:

Test условие

[ условие ]

мы будем пользоваться вторым вариантом, т.е. вместо того, чтобы писать перед условием слово "test", будем заключать условие в скобки, что более привычно для программистов. На самом деле shell будет распознавать эту команду по открывающей скобке "[", как слову, соответствующему команде "test". Между скобками и содержащимся в них условием обязательно должны быть пробелы. Пробелы должны быть и между значениями и символом сравнения или операции В shell используются условия различных "типов". УСЛОВИЯ ПРОВЕРКИ ФАЙЛОВ: -f file файл "file" является обычным файлом; -d file файл "file" - каталог; -с file файл "file" - специальный файл; -r file имеется разрешение на чтение файла "file"; -w file имеется разрешение на запись в файл "file"; -s file файл "file" не пустой.

УСЛОВИЯ ПРОВЕРКИ СТРОК: 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

Кроме того, существуют два стандартных значения условия, которые могут использоваться вместо условия (для этого не нужны скобки). УСЛОВИЯ СРАВНЕНИЯ ЦЕЛЫХ ЧИСЕЛ: 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". СЛОЖНЫЕ УСЛОВИЯ: Реализуются с помощью типовых логических операций: ! (not) инвертирует значение кода завершения. -o (or) соответствует логическому "ИЛИ". -a (and) соответствует логическому "И".

Условный оператор "if"

В общем случае оператор "if" имеет структуру

If условие then список

Здесь "elif" сокращенный вариант от "else if" может быть использован наряду с полным, т.е. допускается вложение произвольного числа операторов "if" (как и других операторов). Разумеется "список" в каждом случае должен быть осмысленный и допустимый в данном контексте. Самая усеченная структура этого оператора

If условие then список fi

если выполнено условие (как правило это ком получен код завершения "0", то выполняется "список", иначе он пропускается. Примеры. Пусть написан "if-1"

If [ $1 -gt $2 ]

then pwd else echo $0: Hello!

Тогда вызов if-1 12 11 даст /home/sae/STUDY/SHELL а if-1 12 13 даст if-1: Hello!

Оператор вызова ("case")

Оператор выбора "case" имеет структуру:

Case строка in

шаблон) список команд;; шаблон) список команд;; ... шаблон) список команд;;

Здесь "case" "in" и "esac" - служебные слова. "Строка" (это может быть и один символ) сравнивается с "шаблоном". Затем выполняется "список команд" выбранной строки. Непривычно выглядят в конце строк выбора ";;", но написать здесь ";" было бы ошибкой. Для каждой альтернативы может быть выполнено несколько команд. Если эти команды будут записаны в одну строку, то символ ";" будет использоваться как разделитель команд. Обычно последняя строка выбора имеет шаблон "*", что в структуре "case" означает "любое значение". Эта строка выбирается, если не произошло совпадение значения переменной (здесь $z) ни с одним из ранее записанных шаблонов, ограниченных скобкой ")". Значения просматриваются в порядке записи.

Оператор цикла с перечислением ("for")

Оператор цикла "for" имеет структуру:

For имя

do список команд done где "for" - служебное слово определяющее тип цикла, "do" и "done" - служебные слова, выделяющие тело цикла. Пусть команда "lsort" представлена командным файлом

For i in file_1 file_2 file_3 do proc_sort $i done

В этом примере имя "i" играет роль параметра цикла. Это имя можно рассматривать как shell-переменную, которой последовательно присваиваются перечисленные значения (i=file_1, i=file_2, i=file_3), и выполняется в цикле команда "proc_sort". Часто используется форма "for i in *", означающая "для всех файлов текущего каталога". Пусть "proc_sort" в свою очередь представляется командным файлом

Cat $1 | sort | tee /dev/lp > ${1}_sorted

т.е. последовательно сортируются указанные файлы, результаты сортировки выводятся на печать ("/dev/lp") и направляются в файлы file_1_sorted file_2_sorted и file_3_sorted

Оператор цикла с истинным условием ("while")

Структура "while", также обеспечивающая выполнение расчетов, предпочтительнее тогда, когда неизвестен заранее точный список значений параметров или этот список должен быть получен в результате вычислений в цикле. Оператор цикла "while" имеет структуру:

While условие

do список команд done где "while" - служебное слово определяющее тип цикла с истинным условием. Список команд в теле цикла (между "do" и "done") повторяется до тех пор, пока сохраняется истинность условия (т.е. код завершения последней команды в теле цикла равен "0") или цикл не будет прерван изнутри специальными командами ("break", "continue" или "exit"). При первом входе в цикл условие должно выполняться. Команда "break [n]" позволяет выходить из цикла. Если "n" отсутствует, то это эквивалентно "break 1". "n" указывает число вложенных циклов, из которых надо выйти, например, "break 3" - выход из трех вложенных циклов. В отличие от команды "break" команда "continue [n]" лишь прекращает выполнение текущего цикла и возвращает на НАЧАЛО цикла. Она также может быть с параметром. Например, "continue 2" означает выход на начало второго (если считать из глубины) вложенного цикла. Команда "exit [n]" позволяет выйти вообще из процедуры с кодом возврата "0" или "n" (если параметр "n" указан). Эта команда может использоваться не только в циклах. Даже в линейной последовательности команд она может быть полезна при отладке, чтобы прекратит выполнение (текущего) расчета в заданной точке.

Оператор цикла с ложным условием ("until")

Оператор цикла "until" имеет структуру:

Until условие

do список команд done где "until" - служебное слово определяющее тип цикла с ложным условием. Список команд в теле цикла (между "do" и "done") повторяется до тех пор, пока сохраняется ложность условия или цикл не будет прерван изнутри специальными командами ("break", "continue" или "exit"). При первом входе в цикл условие не должно выполняться. Отличие от оператора "while" состоит в том, что условие цикла проверяется на ложность (на ненулевой код завершения последней команды тела цикла) проверяется ПОСЛЕ каждого (в том числе и первого!) выполнения команд тела цикла. Пример.

Until false do

read x if [ $x = 5 ] then echo enough ; break else echo some more fi

Здесь программа с бесконечным циклом ждет ввода слов (повторяя на экране фразу "some more"), пока не будет введено "5". После этого выдается "enough" и команда "break" прекращает выполнение цикла.

Пустой оператор

Пустой оператор имеет формат

:

Ничего не делает. Возвращает значение "0".".

Функции в shell

Функция позволяет подготовить список команд shell для последующего выполнения. Описание функции имеет вид:

Имя() { список команд }

после чего обращение к функции происходит по имени. При выполнении функции не создается нового процесса. Она выполняется в среде соответствующего процесса. Аргументы функции становятся ее позиционными параметрами; имя функции - ее нулевой параметр. Прервать выполнение функции можно оператором "return [n]", где (необязательное) "n" - код возврата.

Обработка прерываний ("trap")

Бывает необходимо защитить выполнение программы от прерывания. Наиболее часто приходится встречаться со следующими прерываниями, соответствующими сигналам: 0 выход из интерпретатора, 1 отбой (отключение удаленного абонента), 2 прерывание от , 9 уничтожение (не перехватывается), 15 окончание выполнения. Для защиты от прерываний существует команда "trap", имеющая формат:

Trap "список команд" сигналы

Если в системе возникнут прерывания, чьи сигналы перечислены через пробел в "сигналы", то будет выполнен "список команд", после чего (если в списке команд не была выполнена команда "exit") управление вернется в точку прерывания и продолжится выполнение командного файла. Например, если перед прекращением по прерываниям выполнения какого то командного файла необходимо удалить файлы в "/tmp", то это может быть выполнено командой "trap":

Trap "rm /tmp/* ; exit 1" 1 2 15

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

Компьютер - не такая уж и "умная" машина, как это принято считать. Ему необходимо дать точные инструкции о том, что он должен сделать. Для взаимодействия с компьютером служат командные языки, управляющие всеми выполняемыми им операциями. В большинстве языков основные операции, такие как копирование или удаление файла, выполняются с помощью простых команд. Однако компьютер не в состоянии расшифровать команды, которые вы вводите с терминала. Для преобразования таких команд в вид, понятный для компьютера интерпретаторы команд. В разных операционных системах, служат интерпретаторы команд называются по-разному. В 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>protocol

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

Чтобы переназначить стандартный протокол туда же, куда уже назначен стандартный вывод, следует употребить конструкцию

Важен порядок переназначения: shell производит переназначение слева направо по указанному списку. Так,

1 > xxx 2 >& 1

сначала ассоциирует дескриптор 1 с файлом xxx, а затем дескриптор 2 с 1, т. е. тоже с xxx. А

2 >& 1 1 > xxx

ассоциирует дескриптор 2 с терминалом, а 1 - с файлом xxx.

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

Примеры использования перенозначения стандартного ввода-вывода:

· 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 ждет его завершения. Если "&" - то не ждет. Роль ";" может играть конец строки. Смысл конвейера в том, что стандартный вывод одной команды замыкается на стандартный ввод другой.

Примеры конвейеров команд:

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", "b", "c", "d". Аналогичный эффект

· дадут и команды "cat *" и "cat *".

2.5. Командные файлы (script"ы)

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

Пусть с помощью редактора создан файл с именем "cmd", содержащий одну строку следующего вида:

Можно вызвать shell как команду (!), обозначаемую "sh", и передать ей файл "cmd", как аргумент или как перенаправленный вход, т. е.

$ sh cmd или $ sh

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

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

Например,

сделает код защиты "rwx__x__x". Тогда простой вызов

приведет к выполнению тех же трех команд.

Результат будет тот же, если файл с содержимым

представлен в виде:

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

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

Еще раз отметим, что shell-интерпретатор, это всего лишь одна из сотен команд ОС UNIX, имеющая равные с прочими привилегии.

2.6. Рекурсивные скрипты

Shell позволяет использовать рекурсии в виде рекурсивных скриптов. Рекурсия - это вызов программой самой себя.

Пример:

Удалить файлы из каталога и всех его подкаталогов.

# my: Удаление файлов из каталога и всех его подкаталогов

echo "directory $1"

while read a || exit

3. Синтаксис языка shell

3.1. Комментарии

Строки, начинающиеся с #, трактуются как комментарии.

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

Выражения можно заключать в обратные кавычки (`). Такие выражения вычисляются в месте использования. Они могут быть, например, частью строк. Пример. Пусть параметром макрокоманды является имя файла с расширением. for. Требуется удалить одноименный файл с расширением. err.

name=`ena - n $1`

rm - f ${name}.err

Значение, полученное в результате выполнения команды

присваивается переменной 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 ..."

Напомним: чтобы получить значения этих переменных, перед ними нужно поставить знак $. Пример: выдать номер текущего процесса:

3.4. Специальные переменные

Shell"ом используются следующие специальные переменные:

директория, в которую пользователь попадает при входе в систему или при выполнении команды cd без аргументов

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

основная строка приглашения (по умолчанию $)

дополнительная строка приглашения (по умолчанию >); в интерактивном режиме перед вводом команды shell"ом выводится основная строка приглашения.
Если нажата клавиша new_line, но для завершения команды требуется дальнейший ввод, то выводится дополнительная строка приглашения

последовательность символов, являющихся разделителями в командной строке (по умолчанию это <пробел>, <табуляция> и <возврат_каретки>)

4. Управляющие конструкции

Простая команда - это последовательность слов, разделенная пробелами. Первое слово является именем команды, которая будет выполняться, а остальные будут переданы ей как аргументы. Имя команды передается ей как аргумент номер 0 (т. е. имя команды является значением $0). Значение, возвращаемое простой командой - это ее статус завершения, если она завершилась нормально, или (восьмеричное) 200+статус, если она завершилась аварийно.

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

Команда - это либо простая команда, либо одна из управляющих конструкций. Кодом завершения команды является код завершения ее последней простой команды.

4.1 Цикл FOR

for <переменная> [ in <набор> ]

<список>

Если часть in <набор> опущена, то это означает in "$@" (то есть in $1 $2 ... $n).

Пример 1.

Вывести на экран все фортранные файлы текущей библиотеки:

Пример 2.

Пусть команда "lsort" представлена командным файлом

for i in f1 f2 f3

В этом примере имя "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", если не фиксировать перечень файлов в команде, а передавать произвольное их число параметрами.

Тогда головная программа будет следующей:

Здесь отсутствие после "i" служебного слова "in" с перечислением имен говорит о том, что список поступает через параметры команды. Результат предыдущего примера можно получить, набрав

Пример 4.

# subdir: Выдает имена всех поддиректориев

# директория с именем $dir

Пример 5.

Следующий расчет иллюстрирует полезный, хотя и с долей трюкачества, способ повторения одних и тех же действий несколько раз. Переменная "i" принимает здесь пять значений: 1, 2, 3, 4, 5, но внутри цикла эта переменная отсутствует и поэтому ее значение никакой роли не играет и ни чего не меняет. С таким же успехом переменная "i" могла принимать значения, скажем ф о к у с, а в результате точно также было бы пять раз повторено одно и то же вычисление содержимого цикла без изменений.

# print-5: Организации пятикратного выполнения команды

cat file-22 > /dev/lp

Пример 6.

Расчет "print-n" иллюстрирует еще одну полезную возможность в использовании цикла "for". Здесь, после "for i...", отсутствуют "in..." и перечень имен, т. е. перечнем имен для "i" становится перечень параметров, а следовательно количество печатаемых экземпляров можно менять.

# print-n: Задание числа копий

# через параметры

cat file-22 > /dev/lp

Смысл не изменится, если первую строку расчета записать как

поскольку значение "$*" - есть список значений параметров.

Отметим различие в специальных переменных "$*" и "$@", представляющих перечень параметров. Первый представляет параметры, как строку, а второй, как совокупность слов.

Пример 7.

Пусть командный файл "cmp" имеет вид:

При вызове

на экран будет выведено

4.2 Оператор выбора

case $<переменная> in

<шаблон> | <шаблон>...) <список> ;;

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

Пример 1.

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

# инициализировать флаг

# повторять для каждого аргумента

# объединить флаги, разделив их пробелами

-) 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" ;;

Пример 2.

5) echo Молодец! ;;

4) echo Все равно молодец! ;;

3) echo Все равно! ;;

2) echo Все! ;;

Непривычно выглядят в конце строк выбора ";;", но написать здесь ";" было бы ошибкой. Для каждой альтернативы может быть выполнено несколько команд. Если эти команды будут записаны в одну строку, то символ ";" будет использоваться как разделитель команд.

Обычно последняя строка выбора имеет шаблон "*", что в структуре "case" означает "любое значение". Эта строка выбирается, если не произошло совпадение значения переменной (здесь $z) ни с одним из ранее записанных шаблонов, ограниченных скобкой ")". Значения просматриваются в порядке записи.

Пример 3.

# case-3: Справочник.

# Для различных фирм по имени выдается

# название холдинга, в который она входит

ONE|TWO|THREE) echo Холдинг: ZERO ;;

MMM|WWW) echo Холдинг: Not-Net ;;

Hi|Hello|Howdoing) echo Холдинг: Привет! ;;

*) echo Нет такой фирмы;;

При вызове "case-3 Hello" на экран будет выведено:

Холдинг: Привет!

А при вызове "case-3 HELLO" на экран будет выведено:

Нет такой фирмы

Пример 4.

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

# case-4: Реализация меню с помощью команды "case"

echo "Назовите файл, а затем (через пробел)

наберите цифру, соответствующую требуемой

обработке:

1 - отсортировать

2 - выдать на экран

3 - определить число строк "

read x y # x - имя файла, y - что сделать

1) sort < $x ;;

2) cat < $x ;;

3) wc - l < $x ;;

Мы не знаем

такой команды! " ;;

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

Пример 5.

Напишем команду "case-5", которая добавляет информацию к файлу, указанного первым параметром (если параметр один), со стандартного входа, либо (если 2 параметра) из файла, указанного в качестве первого параметра:

# case-5: Добавление в файл.

# Использование стандартной переменной.

# "$#" - число параметров при вводе расчета

# ">>" - перенаправление с добавлением в файл

1) cat >> $1 ;;

2) cat >> $2 < $1 ;;

*) echo "Формат: case-4 [откуда] куда" ;;

"$1" (при "$#=1") - это имя файла, в который происходит добавление со стандартного входа.

"$1" и "$2" (при $#=2) - это имена файлов, из которого ("$1") и в который ("$2") добавлять.

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

4.3. Условный оператор.

if <список1>

<список2>

[ elif <список3>

<список4> ]

<список5> ]

Выполняется <список1> и, если код его завершения 0, то выполняется <список2>, иначе - <список3> и, если и его код завершения 0, то выполняется <список4>. Если же это не так, то выполняется <список5>. Части elif и else могут отсутствовать.

Примеры.

Пусть написан расчет "if-1"

if [ $1 - gt $2 ]

else echo $0: Hello!

Тогда вызов расчета

/home/sae/STUDY/SHELL

Возможно использовать в условии то свойство shell, что команды могут выдавать различный код завершения. Это напоминает приемы программирования на Си. Пусть расчет "if-2" будет

if a=`expr "$1" : "$2"`

then echo then a=$a code=$?

else echo else a=$a code=$?

тогда вызов

Еще пример на вложенность

# if-3: Оценка достижений

echo - n " А какую оценку получил на экзамене?: "

then echo Молодец!

then echo Все равно молодец!

then echo Все равно!

then echo Все!

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

4.4. Цикл WHILE

while <список1>

<список2>

До тех пор, пока код завершения последней команды <списка1> есть 0, выполняются команды <списка2>. При замене служебного слова while на until условие выхода из цикла меняется на противоположное.

В качестве одной из команд <списка1> может быть команда true (false). По этой команде не выполняется никаких действий, а код завершения устанавливается 0 (-1). Эти команды применяются для организации бесконечных циклов. Выход из такого цикла можно осуществить лишь по команде break (см. Специальные команды).

Пример 1.

# print-50: Структура "while"

# экземпляров файла "file-22"

while [ $n - lt 50 ] # пока n < 50

cat file-22 > /dev/lp

Обратим внимание на то, что переменной "n" вначале присваивается значение 0, а не пустая строка, так как команда "expr" работает с shell-переменными как с целыми числами, а не как со строками.

т. е. при каждом выполнении значение "n" увеличивается на 1.

Пример 2.

Как и вообще в жизни, можно реализовать то же самое и сложнее. Расчет "рr-br" приведен для иллюстрации бесконечного цикла и использования команды "break", которая обеспечивает прекращение цикла.

# рr-br: Структура "while" c "break"

# Расчет позволяет напечатать 50

# экземпляров файла "file-22"

if [ $n - lt 50 ] # если n < 50

then n=`expr $n + 1`

cat file-22 > /dev/lp

4.5 Функции

<имя> () {

<список>;

Определяется функция с именем <имя>. Тело функции - <список>, заключенный между { и }.

Пример.

Вызов на выполнение файла "fun"

fn() # описание функции

echo $0: $$ $1 $2

xx=yy ; echo xx=$xx

xx=xx ; echo xx=$xx

fn a b # вызов функции "fn" с параметрами

4.6. Зарезервированные слова

Следующие слова являются зарезервированными:

if then else elif fi

case in esac { }

for while until do done

4.7. Специальные команды

Как правило, для выполнения каждой команды shell порождает отдельный процесс. Специальные команды отличаются тем, что они встроены в shell и выполняются в рамках текущего процесса.

Пустая команда. Возвращает нулевой код завершения.

Shell читает и выполняет команды из файла file, затем завершается; при поиске file используется список поиска $PATH.

Выход из внутреннего for или while цикла; если указано n, то выход из n внутренних циклов.

Перейти к следующей итерации внутреннего for или while цикла; если указано n, то переход к следующей итерации n-ого цикла.

cd [ <аргумент> ]

Сменить текущую директорию на директорию <аргумент>. По умолчанию используется значение HOME.

echo [ <арг> ... ]

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

eval [ <арг> ... ]

Аргументы читаются, как если бы они поступали из стандартного ввода и рассматриваются как команды, которые тут же и выполняются.

exec [ <арг> ... ]

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

Завершение выполнения shell"а с кодом завершения n. Если n опущено, то кодом завершения будет код завершения последней выполненной команды (конец файла также приводит к завершению выполнения).

export [ <переменная> ... ]

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

hash [ - r ] [ <команда> ... ]

Для каждой из указанных команд определяется и запоминается путь поиска. Опция - r удаляет все запомненные данные. Если не указан ни один аргумент, то выводится информация о запомненных командах: hits - количество обращений shell"а к данной команде; cost - объем работы для обнаружения команды в списке поиска; command - полное имя команды. В некоторых ситуациях происходит перевычисление запомненных данных, что отмечается значком * в поле hits.

Выводит имя текущей директории.

read [ <переменная> ... ]

Читается из стандартного ввода одна строка; первое ее слово присваивается первой переменной, второе - второй и т. д., причем все оставшиеся слова присваиваются последней переменной.

readonly [ <переменная> ... ]

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

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

set [ --aefkntuvx [ <арг> ... ] ]

Команда устанавливает следующие режимы:

отметить переменные, которые были изменены или созданы, как переменные окружения (см. Окружение)

если код завершения команды ненулевой, то немедленно завершить выполнение shell"а

запретить генерацию имен файлов

все переменные с именем помещаются в окружение команды, а не только те, что предшествуют имени команды (см. Окружение)

завершение shell"а после ввода и выполнения одной команды

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

вывести вводимые строки сразу после их ввода

вывести команды и их аргументы перед их выполнением

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

При указании + вместо - каждый из флагов устанавливает противоположный режим. Набор текущих флагов есть значение переменной $-. <арг> - это значения, которые будут присвоены позиционным переменным $1, $2 и т. д. Если все аргументы опущены, выводятся значения всех переменных.

Позиционные переменные, начиная с $(n+1), переименовываются в $1 и т. д. По умолчанию n=1.

вычисляет условные выражения (см. Дополнительные сведения. Test)

trap [ <арг> ] [ n ] ...

Команда <арг> будет выполнена, когда shell получит сигнал n (см. Сигналы). (Надо заметить, что <арг> проверяется при установке прерывания и при получении сигнала). Команды выполняются по порядку номеров сигналов. Любая попытка установить сигнал, игнорируемый данным процессом, не обрабатывается. Попытка прерывания по сигналу 11 (segmentation violation) приводит к ошибке. Если <арг> опущен, то все прерывания устанавливаются в их начальные значения. Если <арг> есть пустая строка, то этот сигнал игнорируется shell"ом и вызываемыми им программами. Если n=0, то <арг> выполняется при выходе из shell"а. Trap без аргументов выводит список команд, связанных с каждым сигналом.

type [ <имя> ... ]

Для каждого имени показывает, как оно будет интерпретироваться при использовании в качестве имени команды: как внутренняя команда shell"а, как имя файла или же такого файла нет вообще.

ulimit [ - f ] [ n ]

Устанавливает размер файла в n блоков; - f - устанавливает размер файла, который может быть записан процессом-потомком (читать можно любые файлы). Без аргументов - выводит текущий размер.

Пользовательская маска создания файлов изменяется на nnn. Если nnn опущено, то выводится текущее значение маски. Пример: после команды umask 755 будут создаваться файлы, которые владелец сможет читать, писать и выполнять, а все остальные - только читать и выполнять.

unset [ <имя> ... ]

Для каждого имени удаляет соответствующую переменную или функцию. Переменные PATH, PS1, PS2 и IFS не могут быть удалены.

Ждет завершения указанного процесса и выводит код его завершения. Если n не указано, то ожидается завершения всех активных процессов-потомков и возвращается код завершения 0.

Примеры:

· if test - d $i

· break #если директория, то выходим из цикла

· echo $i #иначе печатаем имя файла и начинаем следующую итерацию цикла

· сменить текущую директорию на /usr/X11

· $ cd /usr/X11

· вывести на стандартные выход имена всех файлов текущей директории

· завершить по условию работу программы и возвратить код -1

· & if <условие>

· > then exit -1

· экспортировать переменные var1 и var2 в окружение

· $ export var1 var2

· запомнить путь поиска команды sed

· записать имя текущей директории в файл dir

· просмотреть список переменных с аттрибутом "только для чтения" и установить этот аттрибут

· для переменной vvreadonly

· $ readonly; readonly vvreadonly

· вывести на экран все переменные окружения

· проверить существует ли такая команда или файл sqwreg (т. е. как shell её интерпретирует)

· $ type sqwreg

· задать максимальный размер файла, который может создать процесс/поток, равный 10 блоков

· просмотреть текущее значение маски

· удалить из окружения переменную var1

· ожидать выполнение процесса 711

5. Выполнение shell-программ

5.1. Запуск shell"а

Программа, интерпретирующая shell-программы, находится в файле /bin/sh. При запуске ее первый аргумент является именем shell-программы, остальные передаются как позициональные параметры. Если файл, содержащий shell-программу, имеет право выполнения (x), то достаточно указания лишь его имени. Например, следующие две команды операционной системы эквивалентны (если файл ficofl обладает указанным правом и на самом деле содержит shell-программу):

sh 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"ом поддерживаются следующие сигналы:

отменить (hangup)

прерывание (interrupt)

нестандартный выход (quit)

неверная команда (illegal instruction)

ловушка (trace trap)

исключительная ситуация при выполнении операций с плавающей запятой (floating-point exception)

уничтожение процесса (kill)

ошибка шины (bus error)

нарушение сегментации (segmentation violation)

неверный системный вызов (bad argument to system call)

запись в канал без чтения из него (write on a pipe with no one to read it)

будильник (alarm clock)

программное завершение процесса (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 используются условия различных "типов".

УСЛОВИЯ ПРОВЕРКИ ФАЙЛОВ:

файл "file" является обычным файлом;

файл "file" - каталог;

-с file

файл "file" - специальный файл;

имеется разрешение на чтение файла "file";

имеется разрешение на запись в файл "file";

файл "file" не пустой.

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

[ - f specific ] ; echo $?

[ - d specific ] ; echo $?

УСЛОВИЯ ПРОВЕРКИ СТРОК:

str1 = str2

строки "str1" и "str2" совпадают;

str1 != str2

строки "str1" и "str2" не совпадают;

строка "str1" существует (непустая);

строка "str1" не существует (пустая).

x="who is who"; export x; [ "who is who" = "$x" ]; echo $?

x=abc ; export x ; [ abc = "$x" ] ; echo $?

x=abc ; export x ; [ - n "$x" ] ; echo $?

x="" ; export x ; [ - n "$x" ] ; echo $?

Команда "test" дает значение "истина" (т. е. код завершения "0") и просто если в скобках стоит непустое слово.

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

УСЛОВИЯ СРАВНЕНИЯ ЦЕЛЫХ ЧИСЕЛ:

То есть в данном случае команда "test" воспринимает строки символов как целые (!) числа. Поэтому во всех остальных случаях "нулевому" значению соответствует пустая строка. В данном же случае, если надо обнулить переменную, скажем, "x", то это достигается присваиванием "x=0".

x=abc ; export x ; [ abc - eq "$x" ] ; echo $?

x=321 ; export x ; [ 321 - eq "$x" ] ; echo $?

x=3.21 ; export x ; [ 3.21 - eq "$x" ] ; echo $?

"[": integer expression expected before - eq

x=321 ; export x ; [ 123 - lt "$x" ] ; echo $?

СЛОЖНЫЕ УСЛОВИЯ:

Реализуются с помощью типовых логических операций:

ПРЕДУПРЕЖДЕНИЕ. Не забывайте о пробелах.

[ ! privet ] ; echo $?

x=privet; export x; [ "$x" - a - f specific ] ; echo $?

x="";export x; [ "$x" - a - f specific ] ; echo $?

x="";export x; [ "$x" - a - f specific - o privet ] ; echo $?

x="";export x; [ "$x" - a - f specific - o! privet ] ; echo $?

6.2. Команда expr

Команда expr применяется для вычисления выражений. Результат выводится на стандартный вывод. Операнды выражения должны быть разделены пробелами. Метасимволы должны быть экранированы. Надо заметить, что 0 возвращается в качестве числа, а не для индикации пустой строки. Строки, содержащие пробелы или другие специальные символы, должны быть заключены в кавычки. Целые рассматриваются как 32-битные числа.

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

<выр> \| <выр>

если первое <выр> не пустое и не нулевое, то возвращает его, иначе возвращает второе <выр>

<выр> \& <выр>

если оба <выр> не пустые и не нулевые, то возвращает первое <выр>, иначе возвращает 0

<выр> { =, \>, \>=, \<, \<=, != } <выр>

возвращает результат целочисленного сравнения если оба <выр> - целые; иначе возвращает результат лексического сравнения

<выр> { +, - } <выр>

сложение и вычитание целочисленных аргументов

<выр> { \*, /, % } <выр>

умножение, деление и получение остатка от деления целочисленных аргументов

<выр> : <выр>

оператор сопоставления: сопоставляет первый аргумент со вторым, который должен быть регулярным выражением. Обычно оператор сравнения возвращает число символов, удовлетворяющих образцу (0 при неудачном сравнении). Однако символы \(и \) могут применяться для выделения части первого аргумента.

Регулярное выражение строится следующим образом:

Более подробная информация о регулярных выражениях находится по адресу www. asu. pstu. *****/unix/regular_expression.

Все остальные символы (и ^, если стоит не в квадратных скобках) обозначают самих себя. Для указания символов., *,[ и ] надо экранировать их (т. е. писать \., \*, \[, \]).

Примеры.

Увеличение на 1 переменной a

expr $a: ".*/\(.*\)" \| $a

Выделяет из имени файла короткое имя (т. е. из /usr/util/ena выделяется ena). Внимание, одиночный символ / будет воспринят как знак операции деления.

Получение количества символов переменной VAR.

В качестве побочного эффекта expr возвращает следующие коды завершения:

Команда expr также выдает следующие сообщения об ошибках:

Замечание.

Допустим, что мы хотим сравнить значение переменной a с каким-либо символом, имеющим для expr особый смысл, например, со знаком равенства. Пусть $a на самом деле является знаком равенства. Так как аргументы предварительно обрабатываются shell"ом, то команда

будет воспринята как

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

7. Контрольные задания

Вопрос.

Ответ.

Вывести содержимое переменной 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 *
do
echo $i
done

mail `cat mailinglist` < letter

Удалить все файлы, оканчивающиеся на. bak

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

(sleep 300; echo Чай готов) &

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

find. - size 0c - ok rm {} ";"

Закройте свой домашний каталог (в директории home) для всех пользователей кроме себя

chmod o-xw /home/alex

Вывести последние 100 строк файла с сортировкой и с возможностью постепенного просмотра

tail -100 filename | sort | more

Написать фрагмет программы на shell, который при отсутствии почты, переадресовывает всю почту на другой адресат, например alex.

if ; then mail - F "alex"; fi.

Выяснить, работает ли mary в системе

Выполнить задание через неделю в 6 часов вечера

МОСКВА 2007

Лабораторный практикум по курсу: “Операционная система Red Hat Linux

Лабораторная работа №5

Программирование в SHELL

Цель работы : на основе ранее полученных навыков работы с командным интерпретатором BASH овладеть начальными навыками программирования в командном интерпретаторе BASH для создания файлов сценария – SHELL скриптов.

Теоретические сведения

Выполнение отдельных команд в командном интерпретаторе не всегда является эффективным средством работы с SHELL оболочкой. Довольно часто требуется выполнять одни и те же последовательности действий при работе с операционной системой Linux каждый месяц, каждую неделю, каждый день и иногда и несколько раз в день. Например, предположим, вы работаете на фирме тестером программного обеспечения (Test Manager). Каждый день вам требуется в командной оболочке Linux выполнять один тот набор действий, а именно: монтирование устройства CD-ROM; копирование всей информации с него в папку, скажем, /opt/program на жестком диске; демонтирование CD-ROM; чтение файла readme из этой папки; установка программы с жесткого диска из папки /opt/program; создания нового файла отчета в директории /home/user/report_program удаление всего содержимого дистрибутива с жесткого диска. И это притом, что основная ваша работа заключается в тестировании программного обеспечения на предмет выявления недоработок (bags). Задача на первый взгляд простая, но выполнять подобные действия по несколько раз в день, притом, что вы занимаетесь и другими делами, неудобно. Или, например, вы работаете в фирме системным администратором и обслуживаете около 50 компьютеров. Каждый день вам требуется раскопировать на все компьютеры один и тот же файл с инструкциями на текущий день директора фирмы для всех подчиненных. Кроме того, в ваши задачи также входит в конце рабочего дня сохранить все данные каждого пользователя на общем сервере фирмы с персональных компьютеров подчиненных. Задача также на первый взгляд простая, но работа по набору команд в командном интерпретаторе для 50 компьютеров займет много времени. А если к тому же вы при наборе будите ошибаться, например, от усталости? Данные для директора и их владельца очень важны, и потерять их Вам никак нельзя. Но это еще простые действия. А представьте, что названия файлов отчетов, название папок с данными, имена компьютеров каждый раз будут меняться? Что тогда делать? Выход один – написать файл-сценария , т.е. создать текстовый файл, в котором требуется описать всю последовательность команд с путями, опциями, аргументами, выражениями, действиями и так далее для выполнения определенного сценария. Например, резервирования данных. После ввода команд в текстовый файл-сценария, данный файл делают исполняемым или выполняют его специальных операторов выполнения командного интерпретатора. Использование файлов сценария является особенно эффективным, если вам очень часто требуется выполнять последовательность из большого числа команд. Также является эффективным средством, если в зависимости от результатов выполнения предыдущих команд зависит выполнение следующих. С помощью файлов-сценариев можно также использовать арифметические и логические выражения, создавать циклы, обеспечивающие многократное выполнение группы команд Linux.

Создание файлов-сценария. Создания сценариев представляет собой последовательный набор команд, операторов командного интерпретатора и некоторых других символов в текстовом файле. Файлы-сценария также называют скриптами, а командные интерпретаторы латинским названием SHELL. В связи с тем, что на сегодняшний день существуют разные командные интерпретаторы, написание файла-сценария с использованием дополнительных символов, например, метасимволов, совместно с командами не должно противоречить правилам синтаксиса выбранного командного интерпретатора, в котором предполагается выполнять данный скрипт. Процесс написания таких файлов называют SHELL программированием. Рассмотрим процесс программирования на примере интерпретатора BASH. Таким образом, скрипты и правила написания скриптов в данной лабораторной работе могут быть не переносимы на другие интерпретаторы, например, такие как С Shell или TC Shell.

Последовательность #!. Написание любого скрипта начинается с принадлежности его к одному из командных интерпретаторов. В первой строке скрипта обычно пишут последовательность #! , которая указывает системе, какой интерпретатор должен выполнить команды из данного сценария. Если первый символ пробел, считается, что сценарий написан для BASH или PDKSH. Если сценарий начинается только с символа # , то для его выполнения необходим TC Shell. Если же за символом # следует символ!, ядро запустит интерпретатор, путь которого указан далее в этой строке. Например, для BASH будет следующая запись: #!/bin/sh . Пробела или одиночного символа # в начале сценария достаточно для интерпретаторов BASH Shell и TC Shell только при условии, что они будут считывать свой сценарий. Чтобы один интерпретатор распознал сценарии другого, необходимо включать в сценарий символы #! , после чего указывается путь интерпретирующей программы. Тогда при вызове сценария будет прекращена работа текущего интерпретатора, вместо него будет загружен сценарий другого типа, а затем выполнен сценарий. Рекомендуется всегда начинать все сценарии с последовательности #! . Также строки, начинающиеся с символа # можно использовать для комментариев действий пользователя в скрипте. Встретив символ #, интерпретатор shell игнорирует эту строку. Каждый комментарий должен завершаться символом окончания строки. Использование комментариев является признаком хорошего тона.

Расширение и запуск скриптов. Обычно файлы-сценариев имеют не только имена, но также и расширения. Чаще всего в качестве расширений используют комбинацию букв sh от латинского слова shell. По такому расширению, не открывая файл, сразу понятно, что это shell скрипт, так как нам опять же понятно, что файл с расширением . c скорее всего является входным файлом языков высокого уровня С и С++. После набора содержимого файла, файл сохраняется. Запустить файл можно двумя способами либо сделать его исполняемым с помощью команды chmod, либо запускать его с помощью специальных операторов командного интерпретатора: sh и. Обычно пользователи задают для файл-сценария восьмеричные значения 750 или 550. В следующем примере сделаем скрипт script.sh выполняемым с помощью команды chmod и запустим его на выполнение из текущей директории в фоновом режиме.

chmod u+x script.sh

./ script.sh &

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

chmod u-x script.sh

sh script.sh&

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

echo “Добрый день!”

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

echo “Введите ваше имя: ”

read your _ name

echo “ Добрый день ,” your_name “!”

Данный скрипт усложнен по отношению к предыдущему. Здесь используется переменная your_name , значение которой потом применяется совместно с текстом.

Использование переменных. Как и языках программирования, в shell Вы также можете использовать переменные, присваивать значения переменным можно через оператор присваивания равно «=». Сначала вводится имя переменной, потом без пробела знак «=», затем без пробела значение переменной. Имя переменной может состоять из любого количества буквенных символов, включая символ подчеркивания. Имя может содержать и цифры, однако не должно начинаться с цифры. Все остальные символы (в частности, восклицательный знак, амперсанд и пробел) в имя входить не должны. Такие символы зарезервированы интерпретатором для специальных целей. Как следствие, имя может состоять только из одного слова, поскольку при синтаксическом анализе команд интерпретатор рассматривает пробел как разделитель имен команд и аргументов. Значение переменной может состоять из любой последовательности символов. В следующем примере присвоим переменной «ppp» значение «www123yyy».

ppp =” www 123 yyy

Если вы используете в качестве значения переменной строковое значение, используйте двойные кавычки. После присвоения значения вы можете пользоваться именем переменной для ссылки на это значение, например использовать его в качестве аргумента команд сценария. На значение переменной можно ссылаться посредством ее имени, которое предваряется оператором $. Знак доллара - это специальный оператор, который использует имя переменной для ссылки на ее значение, то есть фактически для ее вычисления. Теперь с помощью уже знакомой команды echo и переменной «ppp» можно отображать значение этой переменной.

echo $ppp

www123yyy

Аргументы командной строки. В сценарии, как и в командах Linux, можно использовать аргументы. Аргумент в сценарии обозначается оператором $ с указанием номера позиции в командной строке. Нумерация параметров начинается с единицы, а заканчивается девятью. Первый параметр задается переменной $1, второй - $2 и т. д. Аргумент $0 резерви­руется для имени shell-сценария, в качестве которого выступает первое слово, находя­щееся в командной строке. По умолчанию имеется возможность устанавливать 9 переменных с $1 до $9 . Если вво­дится несколько аргументов, можно отдельно обращаться к каждому из них по его номеру. В следующем примере в командной строке вводятся три аргумента. Предварительно создадим скрипт arguments с аргументами, а потом его выполним.

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

Переменная export. Иногда для разных файлов-сценария требуется воспользоваться определенной переменной, которая уже была определена. Переменные, которые вы определяете в интерпретаторе shell, являются локальными для него. В некотором смысле такая пе­ременная принадлежит своему интерпретатору. Непосредственно определить переменную для другого интерпретатора нельзя, однако можно экспортировать определение переменной из одного интерпретатора в другой с помощью команды export. Команда export содержит инструкцию для системы, в соответствии с которой для каждого вновь образованного shell будет определяться копия этой переменной. Каждый новый интерпретатор shell будет иметь собственную копию экспортированной переменной. В следующем примере определим переменную «rrr» и экспортируем ее для других интерпретаторов с помощью команды export.

Арифметические операции – команда let . Команда let - это команда интерпретатора BASH shell, обеспечивающая выпол­нение операций над арифметическими величинами. С помощью этой команды можно сравнивать числовые значения или выполнять над ними арифметические операции, такие как сложение или умножение. Формат команды: let значение1 оператор значение2. Приведем пример.

$ let 2*5

10

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

$ let “total=2*5”

$ echo $total

10

$

Операторы сравнения часто используются для сравнения числовых значений в управ­ляющих конструкциях, таких как циклы и условные переходы. В следующем примере команды сценария file1 четырежды выводят на экран слово "Привет!". В данном случае для управления выходом из цикла используется оператор let "ttt <= 4", а для увеличения переменной цикла again на единицу - оператор let "ttt = ttt + 1". Обратите внимание на то, что при изменении переменной again ее вычислять не требуется.

File1

ttt=l

while let "ttt<= 4"

do

echo $ttt Привет!

let "ttt = ttt + 1"

done

Выполнение скрипта:

$ file1

Привет!

Привет!

Привет!

Кроме того, вы также можете использовать и другие арифметические операторы. В таблице 1 приведены арифметические операторы и операторы сравнения Bash Shell.

Таблица 1 - Операторы BASH shell

Арифметические операторы

Функции

Умножение

Сложение

Вычитание

Деление с остатком

Операторы сравнения

Функции

Больше чем

Меньше чем

Больше либо равно

Меньше либо равно

Равенство в выражениях

Равенство в команде let

Не равно

Логическое И

Логическое ИЛИ

Логическое НЕ

Управляющие конструкции. Управляющие конструкции предназначены для управления ходом выполнения команд shell-сценария. Эти конструкции позволяют организовать повторное выполнение определенной последовательности команд или выбирать для выполнения команды, необходимые в конкретной ситуации. Управляющая конструкция состоит из двух основ­ных компонентов: операции проверки и команд. В результате выполнения сравнения (проверки условия) возвращается значение «истина» или «ложь», а затем на основании полученного результата выполняются определенные команды. Существует два вида управляющих конструкций: циклические (циклы) и условные (ус ловия). Циклическая конструкция используется для повторного выполнения команд, тогда как условная - для выполнения последовательности команд., которая удовлетво­ряет определенным условиям. В интерпретаторе BASH shell можно использовать три циклические конструкции, while, for и for-in, и две условные - if и case.

Управляющие конструкции while и if - это конструкции общего назначения, которые обычно используются при решении таких задач, как итерационные вычисления и проверка различных условий. Управляющие конструкции case и for ориентированы на более узкий круг задач. Конструкция case является многовариантным оператором и представляет собой частный случай условного оператора if. Эта конструкция часто используется при создании меню. Конструкция for представляет собой цикл, однократно обрабатывающий всю информацию для каждого значения, включенного в список, до тех пор, пока не встретится окончание списка.

Кроме сравнения значений или переменных, управляющие конструкции if и while можно применять для проверки того, успешно или неудачно была выполнена системная команда Linux. Напомним, что в Linux каждая выполняемая команда возвращает код завершения. Если выполнение команды было успешным, ее код завершения равен 0. Если по какой-либо причине команда не была выполнена успешно, кодом завершения будет некоторое положительное значение, указывающее тип ошибки. Управляющие кон­струкции if и while позволяют проверить, чему был равен код завершения: 0 или некоторому другому значению. Если код завершения равен нулю, значит, выполнение команды было успешным и управляющая конструкция if или while будет завершена.

Команда test . Сравнивать значения можно не только с помощью условных управляющих конструкций, но также с помощью команды test. При сравнении двух значений test возвращает 0 в том случае, если сравнение будет успешным. Команда test позволяет сравнивать целые числа, строки и даже выполнять логи­ческие операции. Совместно с командой test применяют опции, которые задают тип сравнения. Полный перечень опций приведен в таблице 2.

Таблица 2. Операции, выполняемые командой test интерпретатора BASH shell

Сравнение целых чисел

Функция

Больше чем

Меньше чем

Больше чем либо равно

Меньше чем либо равно

Не равно

Сравнение строк

Функция

Проверка на наличие пустой строки

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

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

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

Проверка на наличие строки, состоящей из нулей

Логические операции

Функция

Логическое И

Логическое ИЛИ

Логическое НЕ

Проверка файлов

Функция

Установка факта существования файла и его регулярности

Проверяется, не является ли файл пустым

Проверка возможности считывания из файла

Проверка возможности записи в файл, а также его изменения

Проверяется, является ли файл исполнимым

Проверяется, является ли имя файла именем каталога

Проверяется, является ли имя файла символической ссылкой

Проверяется, обозначает ли имя файла байт-ориентированное устройство

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

Команда test имеет следующий синтаксис:

test значение -опция значение

test строка = строка

В следующем примере покажем пример использования команды test. Сравним целочисленных значения, для этого используем опцию равенства –eq. Для проверки результата выполнения операции сравнения используем код завершения последней выполненной командыtest, который храниться в переменной $? интерпретатораshell.

$ tot = 4

$ test $ tot -eq 7

$ echo $?

1

Также команда test $tot –eq 7 может быть записана и в другом виде:

$ [ $tot –eq 7 ]

Условные конструкции: if, if-else, elif, case . Интерпретатор BASH shell включает несколько условных управляющих конструкций (табл. 3), которые позволяют выбирать для выполнения определенные команды Linux. Многие из этих конструкций напоминают условные управляющие конструкции в языках программирования, но имеются и некоторые отличия.

Таблица 3 – Управляющие конструкции интерпретаторов bash Shell

Условные управляющие конструкции

Функция

if команда then команда fi

Конструкция if вызывает выполнение действия в случае, если результат проверки истинен

if команда then команда else команда fi

Конструкция if-else вызывает выполнение действия в случае, если код завершения проверяемой команды paвен значению «истина», в противном случае выполняется действие else

if команда then команда elif команда then команда else команда fi

Конструкция elif дает возможность вкладывать конструкции if, что позволяет выбрать один из многих вариантов; если истинно условие, проверяемое первой конструкцией if, выполняются предусмотренные в ней команды и следующей конструкции elif управление не передается

case строка in шаблон) команда;; еsас

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

команда && команда

Логическая операция И возвращает значение 0 («истина»), если обе команды возвращают значение 0; если же одна из команд возвращает ненулевое значение, резуль­тат операции И равен «ложь» и данная операция воз­вращает ненулевое значение

команда | | команда

Логическая операция ИЛИ, возвращающая значение 0 («истина») в случае, если одна или обе команды возвра­щают значение 0 («истина»); если обе команды возвра­щают ненулевое значение, то результат операции ИЛИ - «ложь» и операция возвращает ненулевое значение

Команда

Логическая операция НЕ, инвертирует код завершения команды

while команда do команды done

Конструкция while выполняет действие до тех пор, пока команда проверки возвращает значение «истина»

until команда do команды done

Конструкция until выполняет действие до тех пор, пока команда проверки возвращает значение «ложь»

Циклические управляющие конструкции

Функция while, until, for, for-in, select

for переменная in список-значений do команды done

Конструкция for-in предназначена для обработки списка значений. Переменной последовательно присваиваются значения из списка

for переменная do команды done

Конструкция for предназначена для последовательной обработки аргументов сценария. Переменной последовательно присваивается значение каждого аргумента

select строка in перечень-элементов do команды done

Конструкция select создает меню на основе элементов заданного списка, а затем выполняется указанная команда (обычно это команда case)

Условная конструкция if - then . Условная конструкция if ставит условие на выполнение команды. Этим условием является код завершения какой-то конкретной команды Linux. Если команда выполнена успешно (то есть код завершения равен 0), то команды внутри конструкции if выполняются. Если код завершения отличен от 0, то команды внутри конструкции if выполняться не будут. Иногда требуется выбрать один из двух вариантов, в зависимости от того как была выполнены команда Linux. Ключевое слово else конструкции if позволяет выбрать один из двух вариантов. Приведем синтаксис команды if-then-else.

  • Tutorial

Зачем и для кого статья?

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

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

Статья касается полноценных unix-подобных окружений, с полнофункциональным шеллом (предпочтительно zsh или bash)и достаточно широким набором стандартных программ.

Что такое шелл

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

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

Типичный вид шелла:

Шелл - это основной способ для взаимодействия со всеми Unix-подобными серверными системами.

Где встречаются системы с командной строкой?

Где вас может поджидать unix-овый шелл, популярные варианты:
  • MacOS (bash);
  • удаленный доступ на сервер по работе или для личного веб-проекта;
  • домашний файл-сервер с удаленным доступом;
  • Ubuntu, PC-BSD на ноутбуке/десктопе - unix-подобные системы сегодня просты в установке и использовании.

Какие задачи разумно решать шеллом?

Естественные задачи, для которых шелл пригоден, полезен и незаменим:
  • интерактивная работа в терминале:
    • выполнение компиляции, запуск заданий через make;
    • сравнение текстовых файлов;
    • быстрый ad-hoc анализ данных (количество уникальных ip в логе, распределение записей по часам/минутам и т.п.);
    • разовые массовые действия (прибить много процессов; если работаете с системой контроля версий - ревертнуть или зарезолвить кучу файлов);
    • диагностика происходящего в системе (семафоры, локи, процессы, дескрипторы, место на диске и т.п.);
  • скриптование:
    • установочные скрипты, для выполнения которых нельзя рассчитывать на наличие других интерпретаторов - это не для новичков;
    • функции для кастомизации интерактивного шелла (влияющие на приглашение, меняющие каталог, устанавливающие переменные окружения) - тоже не совсем для новичков;
    • одноразовые скрипты типа массового перекодирования файлов;
    • makefile-ы.

Абсолютно первые шаги

Начинаем работу: войти и выйти

Убедитесь, что точно знаете, как запустить шелл и как из него выйти.

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

На MacOS - тоже запустить Terminal.

Для доступа к удаленному серверу - воспользоваться ssh (если локально у вас MacOS, Ubuntu или другая unix-like система) или putty (если у вас Windows).

Кто я, где я?

Выполните следующие команды:
  • hostname - выводит имя машины (сервера), на которой вы сейчас находитесь;
  • whoami - выводит ваш логин (ваше имя в системе);
  • tree -d / |less - псевдографическое изображение дерева каталогов на машине; выход из пролистывания - q ;
  • pwd - выводит каталог, в котором вы сейчас находитесь; в командной строке вы не можете быть «просто так», вы обязательно находитесь в каком-то каталоге (=текущий каталог, рабочий каталог). Вероятно, текущий рабочий каталог выводится у вас в приглашении (prompt).
  • ls - список файлов в текущем каталоге; ls /home - список файлов в указанном каталоге;

История команд (history)

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

Выполните несколько команд: hostname , ls , pwd , whoami . Теперь нажмите клавишу «вверх». В строке ввода появилась предыдущая команда. Клавишами «вверх» и «вниз» можно перемещаться вперед и назад по истории. Когда долистаете до hostname , нажмите Enter - команда выполнится еще раз.

Команды из истории можно не просто выполнять повторно, а еще и редактировать. Долистайте историю до команды ls , добавьте к ней ключ -l (получилось ls -l , перед минусом пробел есть, а после - нет). Нажмите Enter - выполнится модифицированная команда.

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

Copy-paste

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

Прекрасной особенностью текста является то, что его можно копировать и вставлять, это верно и для командной строки.

Попробуйте выполнить команду date +"%y-%m-%d, %A"
Вводили ли вы ее целиком руками или скопировали из статьи? Убедитесь, что вы можете ее скопировать, вставить в терминал и выполнить.

После того, как научитесь пользоваться man "ом, убедитесь, что можете скопировать и выполнить примеры команд из справки. Для проверки найдите в справке по программе date раздел EXAMPLES , скопируйте и выполните первый приведенный пример (на всякий случай: знак доллара не является частью команды, это условное изображение приглашения к вводу).

Как именно копировать текст из терминала и вставлять его в терминал - зависит от вашей системы и от ее настроек, поэтому дать универсальную инструкцию, к сожалению, не получится. На Ubuntu попробуйте так: копирование - просто выделение мышью, вставка - средняя кнопка мыши. Если не работает, или если у вас другая система - поищите в Интернете или спросите более опытных знакомых.

Ключи и опции

При исследовании истории команд вы уже столкнулись с тем, что у команды ls есть по крайней мере два варианта. Если вызвать ее просто так, она выводит простой список:

Akira@latitude-e7240: ~/shell-survival-quide> ls Makefile shell-first-steps.md shell-first-steps.pdf shell-survival-quide.md shell-survival-quide.pdf
Если же добавить ключ -l , к каждому файлу выводится подробная информация:

Akira@latitude-e7240: ~/shell-survival-quide> ls -l total 332 -rw-rw-r-- 1 akira akira 198 Feb 13 11:48 Makefile -rw-rw-r-- 1 akira akira 15107 Feb 14 22:26 shell-first-steps.md -rw-rw-r-- 1 akira akira 146226 Feb 13 11:49 shell-first-steps.pdf -rw-rw-r-- 1 akira akira 16626 Feb 13 11:45 shell-survival-quide.md -rw-rw-r-- 1 akira akira 146203 Feb 13 11:35 shell-survival-quide.pdf
Это очень типичная ситуация: если к вызову команды добавлять специальные модификаторы (ключи, опции, параметры), поведение команды меняется. Сравните: tree / и tree -d / , hostname и hostname -f .

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

Ls -ld /home ls -l /home grep root /etc/passwd

man

man - справка по командам и программам, доступным на вашей машине, а также по системным вызовам и стандартной библиотеке C.

Попробуйте: man grep , man atoi , man chdir , man man .

Пролистывание вперед и назад делается кнопками «вверх», «вниз», «PageUp», «PageDown», выход из просмотра справки - кнопкой q . Поиск определенного текста в справочной статье: нажимите / (прямой слеш), введите текст для поиска, нажимите Enter. Перемещение к следующим вхождениям - клавиша n .

Все справочные статьи делятся на категории. Самые важные:

  • 1 - исполняемые программы и шелльные команды (wc , ls , pwd и т.п.);
  • 2 - системные вызовы (fork , dup2 и т.п.)
  • 3 - библиотечные функции (printf , scanf , cos , exec).
Указывать, из какой именно категории надо показать справку, нужно в случаях совпадений имен. Например, man 3 printf описывает функцию из стандартной библиотеки C, а man 1 printf - консольную программу с таким же именем.

Посмотреть список всех доступных на машине справочных статей можно с помощью команды man -k . (точка - тоже часть комады).

less

Когда в небольшом окне терминала надо просмотреть очень длинный текст (содержимое какого-то файла, длинный man и т.п.), используют специальные программы-«пейджеры» (от слова page/страница, то есть постраничные листатели). Самый популярный листатель - less , и именно он обеспечивает вам пролистывание, когда вы читаете man-ы.

Попробуйте и сравните поведение:

Cat /etc/bash.bashrc cat /etc/bash.bashrc |less

Можно передать файл в пролистыватель сразу в параметрах:

Less /etc/bash.bashrc

Пролистывание вверхи и вниз - кнопки «вверх», «вниз», «PageUp», «PageDown», выход - кнопка q . Поиск определенного текста: нажимите / (прямой слеш), введите текст для поиска, нажимите Enter. Перемещение к следующим вхождениям - клавиша n . (Узнаете инструкцию про man ? Ничего удивительного, для вывода справки тоже используется less .)

Права

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

Посмотреть права на файл можно с помощью ls -l . Например:

> ls -l Makefile -rw-r--r-- 1 akira students 198 Feb 13 11:48 Makefile
Этот вывод означает, что владельцу (akira) можно читать и писать файл, группе (students) - только читать, всем прочим пользователя - тоже только читать.

Если при работе вы получаете сообщение permission denied , это значит, что у вас недостаточно правна объект, с которым вы хотели работать.

Подробнее читайте в man chmod .

STDIN, STDOUT, конвейеры (пайпы)

С каждой исполняющейся программой связаны 3 стандартных потока данных: поток входных данных STDIN , поток выходных данных STDOUT , поток для вывода ошибок STDERR .

Запустите программу wc , введите текст Good day today , нажмите Enter, введтие текст good day , нажмите Enter, нажмите Ctrl+d. Программа wc покажет статистику по количеству букв, слов и строк в вашем тексте и завершится:

> wc good day today good day 2 5 24
В данном случае вы подали в STDIN программы двухстрочный текст, а в STDOUT получили три числа.

Теперь запустите команду head -n3 /etc/passwd , должно получиться примерно так:

> head -n3 /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin
В этом случае программа head ничего не читала из STDIN , а в STDOUT написала три строки.

Можно представить себе так: программа - это труба, в которую втекает STDIN , а вытекает STDOUT .

Важнейшее свойство юниксовой командной строки состоит в том, что программы-«трубы» можно соединять между собой: выход (STDOUT) одной программы передавать в качестве входных данных (STDIN) другой программе.

Такая конструкция из соединенных программ называется по-английски pipe (труба), по-русски - конвейер или пайп.

Объединение программ в конвейер делается символом | (вертикальная черта)

Выполните команду head -n3 /etc/passwd |wc , получится примерно следующее:

> head -n3 /etc/passwd |wc 3 3 117
Произошло вот что: программа head выдала в STDOUT три строки текста, которые сразу же попали на вход программе wc , которая в свою очередь подсчитала количество символов, слов и строк в полученном тексте.

В конвейер можно объединять сколько угодно программ. Например, можно добавить к предыдущему конвейеру еще одну программу wc , которая подсчитает, сколько слов и букв было в выводе первой wc:

> head -n3 /etc/passwd |wc |wc 1 3 24

Составление конвейеров (пайпов) - очень частое дело при работе в командной строке. Пример того, как это делается на практике, читайте в разделе «Составление конвейера-однострочника».

Перенаправление ввода-вывода

Вывод (STDOUT) програмы можно не только передать другой программе по конвейеру, но и просто записать в файл. Такое перенаправление делается с помощью > (знак «больше»):

Date > /tmp/today.txt
В результате выполнения этой команды на диске появится файл /tmp/today.txt . Посмотрите его содержимое с помощью cat /tmp/today.txt

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

Если надо не перезаписать файл, а добавить вывод в его конец, используйте >> :

Date >> /tmp/today.txt
Проверьте, что теперь записано в файле.

Кроме того, программе можно вместо STDIN передать любой файл. Попробуйте:

Wc

Что делать, когда что-то непонятно

Если вы сталкиваетесь с поведением системы, которое не понимаете, или хотите добиться определенного результата, но не знаете, как именно, советую действовать в следующем порядке (кстати, это относится не только к шеллам):
  • насколько возможно четко сформулируйте вопрос или задачу - нет ничего сложнее, чем решать «то, не знаю что»;
  • вспомните, сталкивались ли вы уже с такой же или подобной проблемой - в этом случае стоит попробовать решение, которое сработало в прошлый раз;
  • почитайте подходящие man-ы (если понимаете, какие man-ы подходят в вашем случае) - возможно, вы найдете подходящие примеры использования команд, нужные опции или ссылки на другие команды;
  • подумайте: нельзя ли немного поменять задачу? - возможно, чуть-чуть изменив условия, вы получите задачу, которую уже умеете решать;
  • задайте свой четко сформулированный вопрос в поисковой системе - возможно, ответ найдется на Stack Overflow или других сайтах;
Если ничего из перечисленного не помогло - обратитесь за советом к преподавателю, опытному коллеге или товарищу. И не бойтесь задавать «глупые» вопросы - не стыдно не знать, стыдно не спрашивать.

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

Методы работы

Скопировать-и-вставить - из man-ов, из статей на StackOverflow и т.п.Командная строка состоит из текста, пользуйтесь этим: копируйте и используйте примеры команд,записывайте удачные находки на память, публикуйте их в твиттерах и блогах.

Вытащить из истории предыдущую команду, добавить в конвейер еще одну команду, запустить, повторить .См. также раздел «Составление конвейера-однострочника».

Базовые команды

  • переход в другой каталог: cd ;
  • просмотр содержимого файлов: саt , less , head , tail ;
  • манипуляции с файлами: cp , mv , rm ;
  • просмотр содержимого каталогов: ls , ls -l , ls -lS ;
  • структура каталогов: tree , tree -d (можно передать в качестве параметра каталог);
  • поиск файлов: find . -name ... ;

Аналитика

  • wc , wc -l ;
  • sort -k - сортировка по указанному полю;
  • sort -n - числовая соритровка;
  • diff - сравнение файлов;
  • grep , grep -v , grep -w , grep "\" , grep -E - поиск текста;
  • uniq , uniq -c - уникализация строк;
  • awk - в варианте awk "{print $1}" , чтобы оставить только первое поле из каждой строки, $1 можно менять на $2 , $3 и т.д.;

Диагностика системы

  • ps axuww - информация о процессах (запущенных программах), работающих на машине;
  • top - интерактивный просмотр самых ресурсоемких процессов;
  • df - занятое и свободное место на диске;
  • du - суммарный размер файлов в каталоге (рекурсивно с подкаталогами);
  • strace , ktrace - какие системные вызовы выполняет процесс;
  • lsof - какие файлы использует процесс;
  • netstat -na , netstat -nap - какие порты и сокеты открыты в системе.

Некоторых программ у вас может не быть, их надо установить дополнительно. Кроме того, некоторые опции этих программ доступны только привилегированным пользователям (root "у).

Массовое и полуавтоматическое выполнение

На первых порах пропускайте этот раздел, эти команды и конструкции понадобятся вам тогда, когда доберетесь до несложного шелльного скриптинга.
  • test - проврека условий;
  • while read - цикл по строчкам STDIN ;
  • xargs - подстановка строк из STDIN в параметры указанной программе;
  • seq - генерация последовательностей натуральных чисел;
  • () - объединить вывод нескольких команд;
  • ; - выполнить одно за другим;
  • && - выполнить при условии успешного завершения первой команды;
  • || - выполнить при условии неудачного завершения первой команды;
  • tee - продублировать вывод программы в STDOUT и в файл на диске.

Разное

  • date - текущая дата;
  • curl - скачивает документ по указаному url и пишет результат на STDOUT ;
  • touch - обновить дату модификации файла;
  • kill - послать процессу сигнал;
  • true - ничего не делает, возвращает истину, полезна для организации вечных циклов;
  • sudo - выполнить команду от имени root "а.

Составление конвейера-однострочника

Давайте рассмотрим пример реальной задачи: требуется прибить все процессы task-6-server , запущенные от имени текущего пользователя.

Шаг 1.
Понять, какая программа выдает примерно нужные данные, хотя бы и не в чистом виде. Для нашей задачи стоит получить список всех процессов в системе: ps axuww . Запустить.

Шаг 2.
Посмотреть на полученные данные глазами, придумать фильтр, который выкинет часть ненужных данных. Часто это grep или grep -v . Клавишей «Вверх» вытащить из истории предыдущую команду, приписать к ней придуманный фильтр, запустить.

Ps axuww |grep `whoami`
- только процессы текущего пользователя.

Шаг 3.
Повторять пункт 2, пока не получатся чистые нужные данные.

"
- все процессы с нужным именем (плюс, может быть, лишние вроде vim task-6-server.c и т.п.),

Ps axuww |grep `whoami` | grep "\" | grep -v vim ps axuww |grep `whoami` | grep "\" | grep -v vim |grep -v less
- только процессы с нужным именем

Ps axuww |grep `whoami` | grep "\" | grep -v vim |grep -v less |awk "{print $2}"

Pid-ы нужных процессов, п. 3 выполнен

Шаг 4.
Применить подходящий финальный обработчик. Клавишей «Вверх» вытаскиваем из истории предыдущую команду и добавляем обработку, которая завершит решение задачи:

  • |wc -l чтобы посчитать количество процессов;
  • >pids чтобы записать pid-ы в файл;
  • |xargs kill -9 убить процессы.

Задания для тренировки

Хотите попрактиковаться в новых умениях? Попробуйте выполнить следующие задания:
  • получите список всех файлов и каталогов в вашем домашнем каталоге;
  • получите список всех man -статей из категории 2 (системные вызовы);
  • посчитайте, сколько раз в man-е по программе grep встречается слово grep;
  • посчитайте, сколько процессов запущено в данный момент от имени пользователя root ;
  • найдите, какая команда встречается в максимальном количестве категорий справки (man);
  • подсчитайте, сколько раз встречается слово var на странице ya.ru .
Подсказка: вам понадобится find , grep -o , awk "{print $1}" , регулярные выражения в grep , curl -s .

Что изучать дальше?

Если командная строка начинает вам нравиться, не останавливайтесь, продолжайте совершенствовать свои навыки.

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

  • find со сложными опциями
  • apropos
  • locate
  • telnet
  • netcat
  • tcpdump
  • rsync
  • screen
  • zgrep , zless
  • visudo
  • crontab -e
  • sendmail
Кроме того, со временем стоит освоить какой-нибудь скриптовый язык,например, perl или python , или даже их оба.

Кому это надо?

А стоит ли вообще изучать сегодня командную строку и шелльный скриптинг? Определенно стоит. Приведу только несколько примеров из требований Facebook к кандидатам, которые хотят поступить на работу в FB.