|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
4. СРЕДА SHELL (ПЕРЕМЕННЫЕ И ПАРАМЕТРЫ)
На языке shell можно писать командные файлы и с помощью команды "chmod" делать их выполняемыми. После этого они ни чем не отличаются от прочих команд ОС UNIX. 4.1. 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
И еще один пример. Фрагмент командного файла:
echo "var_2 = $var_2"
выдаст на экран
var_2 = ОС UNIX
В команде "echo" первое использование "var_2" - это просто текст, а второе ("$var_2") - это значение соответствующей переменной. То что здесь присутствуют пробелы между именем переменной и символом присваивания, а также между символом присваивания и значением, так это потому, что здесь мы имеем дело лишь с текстом, куда подставлены значения переменных. Там, где действительно выполняется присваивание, пробелы в этих местах НЕДОПУСТИМЫ. Присваивание, скажем, w= означает присваивание переменной "w" пустой строки. Но и пустую строку лучше присваивать аккуратно, например w="". Для того, чтобы имя переменной не сливалось со строкой, следующей за именем переменной, используются фигурные скобки. Пусть a=/mnt/lab/asu/
cat /mnt/lab/asu/prim
и
cat ${a}prim
равноценны (т.е. "cat" выдаст на экран содержимое одного и того же файла). Если также предположить, что в системе есть переменная "prim" и "prim=dir" , то команда
echo ${a}$prim
выдаст на экран
/mnt/lab/asu/dir
4.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
Еще один пример на "eval". Пусть
w=\$v v=\$u u=5
В результате выполнения команд
echo $w
eval echo $w
eval eval echo $w
на экран будет выведено
$v
$u
5
Приведем еще примеры, связанные с экранированием перевода строки. Пусть переменной "string" присвоено значение "массива" 2x3: abc def Обратим внимание, что для избежания присваивания лишних пробелов вторая строка массива начата с первой позиции следующей строки: string="abc def"Тогда три варианта записи переменной в команде "echo" echo $string echo '$string' echo "$string"дадут соответственно три различных результата: abc def $string abc defа последовательность команд echo "строка первая строка вторая" > f1 echo 'строка первая строка вторая' > f2 cat f1 f2даст выдаст последовательно одинаковые файлы f1 и f2: строка первая строка вторая строка первая строка вторая Заметим также, что бэк-слэш (\) не только экранирует следующий за ним символ, что позволяет использовать специальные символы просто как символы, представляющие сами себя (он может экранировать и сам себя - \\), но в командном файле бэк-слэш позволяет об'единять строки в одну (экранировать конец строки). Например, приводившийся ранее пример командной строки:
cat f1 | grep -h result | sort | cat -b > f2
может быть записан в командном файле, скажем, как
cat f1 | grep -h \
result | sort | cat -b > f2
Кстати, эффект продолжения командной строки обеспечивает и символ конвейера. В данном случае это может дать более симпатичный результат, например:
cat f1 |
grep -h result |
sort |
cat -b > f2
4.3. Манипуляции с 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
С командой "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
И наконец, об условной замене переменных. Если переменные, скажем "х", "y", "z", не определены, то при обращении к переменным
Во всех этих случаях, если переменная была к этому времени определена, то ее значение используется обычным образом. А в следующем случае наоборот, пусть переменная "v" имеет какое-то значение, тогда
4.4. Экспорт переменных В ОС UNIX существует понятие процесса. Процесс возникает тогда, когда запускается на выполнение какая-либо команда (расчет). Например, при наборе на клавиатуре "р <Enter>" порождается процесс расчета "р". В свою очередь "р" может породить другие процессы. Допустим, что "р" вызывает расчеты "р1" и "р2", которые последовательно порождают соответствующие процессы. У каждого процесса есть своя среда - множество доступных ему переменных. Например, до запуска расчета "р" уже существовала среда, в которой уже были определены некоторые переменные (о стандартных переменных речь пойдет несколько позже). Запуск "р" порождает новую среду; уже в ней будут порождены расчеты "р1" и "р2". Переменные локальны в рамках процесса, в котором они объявлены, т.е. где им присвоены значения (описание переменных отсутствует - они все одного типа). Для того, чтобы они были доступны и другим порождаемым процессам, надо передать их явным образом. Для этого используется встроенная команда "export". Пример. Пусть расчет (командный файл) "p", имеющий вид:
# расчет p
echo Расчет p
varX=0 varY=1
echo varX=$varX varY=$varY
export varY
p1 # вызов расчета p1
p2 # вызов расчета p2
echo Снова расчет p: varX=$varX varY=$varY
вызывает командные файлы "p1" и "p2", имеющие вид:
# расчет p1
echo Расчет p1
echo varX=$varX varY=$varY
varX=a varY=b
echo varX=$varX varY=$varY
export varX
# расчет p2
echo Расчет p2
echo varX=$varX varY=$varY
varX=A varY=B
echo varX=$varX varY=$varY
export varY
На экран будут выданы следующая информация:
Расчет p
varX=0 varY=1
Расчет p1
varX= varY=1
varX=a varY=b
Расчет p2
varX= varY=1
varX=A varY=B
Снова расчет p: varX=0 varY=1
Из примера видно, что значения переменных экспортируются только в вызываемые расчеты (и не передаются "вверх" и "вбок"). Экспортировать переменные можно и командой "set" с флагом "-a".
4.5. Параметры В командный файл могут быть переданы параметры. В shell используются позиционные параметры (т.е. существенна очередность их следования). В командном файле соответствующие параметрам переменные (аналогично shell-переменным) начинаются с символа "$", а далее следует одна из цифр от 0 до 9: Пусть расчет "examp-1" вызывается с параметрами "cock" и "tail". Эти параметры попадают в новую среду под стандартными именами "1" и "2". В (стандартной) переменной с именем "0" будет храниться имя вызванного расчета. При обращении к параметрам перед цифрой ставится символ доллара "$" (как и при обращении к переменным):
Пусть командный файл с именем "examp-1" имеет вид
echo Это расчет $0:
sort $2 >> $1
cat $1
а файлы "cock" и "tail" содержат соответственно
cock:Это отсортированный файл:
tail:
1
3
2
Тогда после вызова команды
examp-1 cock tail
на экране будет
Это расчет examp-1:
Это отсортированный файл:
1
2
3
Поскольку число переменных, в которые могут передаваться параметры, ограничено одной цифрой, т.е. 9-ю ("0", как уже отмечалось имеет особый смысл), то для передачи большего числа параметров используется специальная команда "shift". Рассмотрим ее действие на примере. Пусть командный файл "many" вызывается с 13-ю параметрами
many 10 20 30 40 50 60 70 80 90 100 110 120 130
И имеет вид
###
# many: Передача большого числа параметров.
echo "$0: Много параметров"
echo " Общее число параметров = $#
Исходное состояние: $1 $5 $9 "
shift
echo "1 сдвиг: первый=$1 пятый=$5 девятый=$9"
shift 2
echo "1 + 2 = 3 сдвига: первый=$1 пятый=$5 девятый=$9"
perem=`expr $1 + $2 + $3`
echo $perem
В результате первого применения команды "shift" второй параметр расчета вызывается как $1, третий параметр вызывается как $2, ... десятый параметр, который был исходно недоступен, вызывается как $9. Но стал недоступным первый параметр! После выполнения этого расчета на экране будет:
many: Много параметров
Общее число параметров = 13
Исходное состояние: 10 50 90
1 сдвиг: первый=20 пятый=60 девятый=100
1 + 2 = 3 сдвиг: первый=40 пятый=80 девятый=120
150
Своеобразный подход к параметрам дает команда "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" без параметров выводит на терминал состояние программной среды (см далее). 4.6. Подстановки shell-интерпретатора Перед началом непосредственной интерпретации и выполнением команд, содержащихся в командных файлах, shell выполняет различные виды подстановок:
4.7. Программная среда Каждый процесс имеет среду, в которой он выполняется. Shell использует ряд переменных этой среды. Если вы наберете команду "set" без параметров, то на экран будет выдана информация о ряде стандартных переменных, созданных при входе в систему (и передаваемых далее всем вашим новым процессам "по наследству"), а также переменных, созданных и экспортируемых вашими процессами. Конкретный вид и содержание выдаваемой информации в немалой степени зависит от того, какая версия UNIX используется и как инсталлирована система. Вот лишь часть того, что выдала мне команда "set":
HOME=/home/sae
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
TERM=linux
TERMCAP=console|con80x25|dumb|linux:li#25:co#80::
UID=501
perem=stroka
x=5
Прокомментируем эти присваивания значений переменным.
Исходная среда устанавливается автоматически при входе в систему с использованием файлов типа "/etc/rc" и "/etc/.profile".
Если вы внесли изменения в ".profile", то для переноса этих изменений в среду необходимо выполнить этот файл. Для этого можно выйти и заново войти в систему, а можно воспользоваться (специально для этого случая созданной) командой "." без выхода из системы, т.е.
. .profile
Следует иметь в виду, что имена файлов, начинающиеся с точки, вообще имеют особый статус. Так, они не выдаются на экран простой командой "ls" - необходимо вызывать эту команду с флагом "-a". Кстати, и не уничтожаются огульно командой "rm *". Дописать новый свой директорий "my" в тропу команд можно, записав в ".profile", например
PATH=${PATH}:/home/sae/my
или
PATH=${PATH}:${HOME}/my
Как правило, устанавливаемые переменные среды следует экспортировать. Например,
export TERM PATH REDKEYS MAIL
Кроме определения переменных в ".profile" можно выполнить команды, например команда
stty -lcase
установит терминал в режим "большие и маленькие буквы"; а команда
cat заставка
выдаст на экран заставку , которую вы сами подготовите в файле "заставка" с учетом ваших эстетических пристрастий и художественных способностей. Сам интерпретатор shell автоматически присваивает значения следующим переменным (параметрам):
При обращении к этим переменным (т.е при использовании их в командном файле - shell-программе) следует впереди ставить "$". Пример. Вызов расчета
specific par1 par2 par3
имеющего вид
###
# specific: Специальные параметры (переменные)
echo $0 - имя расчета
echo $? - код завершения
echo $$ - идентификатор последнего процесса
echo $! - идентификатор последнего фонового процесса
echo
echo $* - значения параметров, как строки
echo $@ - значения параметров, как слов
echo
set -au
echo $- - режимы работы интерпретатора
Выдаст на экран
specific - имя расчета
0 - код завершения
499 - идентификатор последнего процесса
98 - идентификатор последнего фонового процесса
par1 par2 par3 - значения параметров, как строки
par1 par2 par3 - значения параметров, как слов
au - режимы работы интерпретатора
Код "0" соответствует нормальному завершению процесса. Важную роль при создании уникальных файлов играет специальная переменная "$$", значение которой соответствует номеру процесса, выполняющего данный расчет. Каждый новый расчет, выполняемый компьютером, инициирует один или несколько процессов, автоматически получающих номера по порядку. Поэтому, используя номер процесса в качестве имени файла, можно быть уверенным, что каждый новый файл будет иметь новое имя (не запишется на место уже существующего). Достоинство является и главным недостатком такого способа именования файлов. Неизвестно, какие имена будут присвоены файлам. И, если в рамках данного процесса можно найти файл "не глядя", т.е., обратившись к нему, используя $$, то потом такие файлы можно легко потерять. Это создает дополнительные проблемы при отладке программ. "echo" без параметров выводит пустую строку. Различия $* и $@ состоит в том, что первая переменная может быть представлена как
"par1 par2 par3"
а вторая как
"par1" "par2" "par3"
Пример, иллюстрирующий различия "$*" и "$@" будет рассмотрен в связи с оператором "for". Для иллюстрации мы установили командой "set" режимы интерпретатора ("a" - все последующие переменные экспортируются; "u" - отсутствие параметра считать ошибкой), что и отразилось в специальной переменной "$-". |
|
CITForum © 1997–2025