Любой универсальной ОС приходится много возиться с пользовательскими и своими собственными задачами. Лишь небольшая часть этой деятельности может быть запрограммирована раз и навсегда в ядре. Большая часть логики управления задачами и самой системой должна быть доступна администратору в виде проекта, иначе он просто не сможет ни понять происходящее в системе, ни тем более изменять ее. Стоит повнимательнее взглянуть на инструмент, используемый в UNIX для задания алгоритма работы многих частей системы, - на
Начнем с того, что shell - полноценный
С другой стороны, одной алгоритмической полнотой при решении задач в системе ограничиваться нельзя. Скажем, машина Тьюринга чрезвычайно проста и алгоритмически полна, однако мало кому придет в голову организовывать на основе ее модели диалог с пользователем или управление самой ОС. Здесь следует вспомнить, что shell - еще и исполнитель команд: он запросто общается с UNIX и утилитами. Значит, дополнив его механизмом управляемого взаимодействия команд с системой и друг с другом, мы получим неплохой
Самое приятное, что такая программируемая
Прежде чем рассмотреть возможности shell под двумя углами зрения, разрешим вот какое затруднение. Допустим, мы написали программу на языке какого-нибудь интерпретатора, например /bin/sh, и записали ее в некий файл, например /home/george/myscript (если /home/george - текущий каталог, можно использовать более короткий путь: myscript ). Как теперь выполнить этот man sh мы знаем, что для этого можно запустить
$ cat myscript echo "Hello, George!" $ /bin/sh myscript Hello, George!
Нельзя ли обойтись без имени программы, которая интерпретирует , потоковый текстовый редактор sed, универсальные python и perl и много чего еще. Во всех этих языках есть возможность вставлять в текст #!", любой из этих интерпретаторов проигнорирует всю первую строку как комментарий. Система же, увидев " #!" в начале файла, понимает, что это /home/george/myscript будет #!/bin/sh, его смело можно делать исполняемым (установить бит использования) и запускать:
$ chmod +x myscript $ cat myscript #!/bin/sh echo "Hello, $1!" $ ./myscript George Hello, George!
Строго говоря, после " #!" может стоять что угодно, например имя написанной нами программы с некоторыми обязательными параметрами; UNIX ее запустит и передаст ей в качестве George ). Если же после " #!" будет стоять несуществующий файл, система выдаст сообщение об ошибке:
$ cat myscript #!/bad/sh echo "Hello, $1!" $ ./myscript ./myscript: not found
Обратите, пожалуйста, внимание на то, что из этого сообщения якобы следует, что не найден сам файл
И еще одно немаловажное замечание. Сначала в UNIX был только один
Однако программировать командные оказалось... менее удобно, чем на sh. Во-первых, синтаксис языка Си в точности воспроизвести не удалось, возникла путаница; во-вторых, многие системные sh, либо с .
Долгое время бытовало мнение, что работать лучше в , а sh, хотя совмещать два разных языка в одной области деятельности неудобно. С тех пор было создано немало других, еще более мощных sh - и -образных оболочек. Они все время дорабатывались, попеременно обгоняя друг друга по охвату возможностей. Пальма первенства принадлежала то bash (Bourne-again shell, детище GNU), то tcsh (международный открытый проект, развивающий ), то zsh (также международный открытый проект, но с sh -совместимостью). На сегодня нельзя с уверенностью сказать, какой из них мощнее (хотя документации по zsh больше, чем по bash и tcsh, вместе взятых, раза в два), но устаревшее мнение о sh и стоит пересмотреть: теперь в какой
Как уже говорилось, многие абстракции
С одной стороны,
$ One=U; Three=Zzz $ echo Example 1: $One $Two $Three Example 1: U Zzz $ echo "Example 2: $One $Two $Three" Example 2: U Zzz $ echo 'Example 3: $One $Two $Three' Example 3: $One $Two $Three
Из первого примера видно, что сам факт присваивания объявляет переменную, а содержимое необъявленной переменной просто считается пустым (напомним, что команда echo выводит все $имя_переменной ) продолжает работать, если текст заключен в двойные кавычки, и не работает, если используются одинарные. По договоренности (см. главу 7) закавыченный текст передается как один echo выводит один пробел между U и Zzz: она получает четыре параметра ( Example 1: U и Zzz ), разделенные цепочками пробелов.
Несмотря на то что переменные в shell - строкового типа, легко организовать арифметические операции над ними: если содержимое переменной нельзя интерпретировать как число, арифметическая операция завершается с ошибкой. Арифметика встроена почти во все виды $((арифметическое выражение)). Есть надежда, что арифметическая sh или Linux- ash будет работать и в остальных
$ A=7; b=3; echo $(($A*$b)) 21
В примере, описывающем понятие 1 ( $1 ), второй - в переменную с именем 2 и т. д., пока есть $# (напомним, что по американской традиции этот символ используется вместо нашего No). Все $* или $@ (Какая между этими формами разница?
Столь простая схема передачи параметров - явная доработка языка в сторону средств интеграции: чаще всего небольшой
С другой стороны,
Например, утилита ls использует COLUMNS, в которой хранится наибольшая допустимая ширина текста. Можно обычным присваиванием изменить значение этой переменной, и ls примет его к сведению:
$ echo $COLUMNS $ ls Makefile myscript uzor.c fhs-2.2-source.tar.gz o.ps $ COLUMNS=60 $ ls Makefile o.ps fhs-2.2-source.tar.gz uzor.c myscript
Многие программы используют переменную ." не включен в список), в одном из приведенных выше примеров мы были вынуждены явно указывать его в виде ." в PATH небезопасно: кто может знать, не окажется ли в текущем каталоге исполняемый файл с именем, скажем, ls, и кто может знать, что на самом деле этот файл будет делать при запуске?
Список определяемых set. Желающих узнать, какими
Сам shell пользуется многими PS1 (Если есть PS1, то должно быть PS2, а может, и PS3, и PS4. Для чего они? $ " для обычного пользователя и " # " для суперпользователя. Потом решили использовать PS1 для вывода кое-какой полезной информации: имени компьютера, имени пользователя, даты входа в систему или прочей относительно статической информации. Это просто, достаточно написать что-то вроде:
$ echo $PS1 $ $ PS1="`logname`@`hostname`> " george@book.altlinux.ru> george@book.altlinux.ru>
Однако статическая информация - не самое полезное в работе. Гораздо интереснее держать в PS1, скажем, путь к текущему каталогу или точное время. PS1. Сам shell изменять PS1 не будет, значит, надо его доработать. Первый способ доработки - научить его выполнять определенную последовательность команд перед тем, как выводить очередную подсказку или при смене текущего каталога (так поступили разработчики tcsh: там можно задать специальные функции precmd, cwdcmd и некоторые другие). В эту последовательность команд можно вставить команды изменения PS1. Другой вариант - считать некоторые последовательности символов в PS1 специальными и при выводе подсказки заменять их соответствующими значениями - путем, временем и т. п. Вот, например, как это делается в bash:
bash$ pwd /usr/share/doc bash$ PS1="[\A]\u@\h:\w> " [17:30]george@book:/usr/share/doc> [17:30]george@book:/usr/share/doc>
Один init ). Остальные переменные будут считаться локальными и никуда не перейдут. Если мы хотим вызвать из одного
$ cat changeA A="NewA" $ A="" $ . changeA $ echo $A NewA
В алгоритмически полном if. Он, конечно, есть и в shell:
$ if [ 5 -gt 6 ]; then echo "Bug"; else echo "Good"; fi Good
Обратите внимание на ключ -gt, означающий greater than, и на fi в конце оператора - так в shell устроены if, then, необязательное else и fi ограничивают условие, условную часть и необязательную противоусловную часть; они могут находиться в одной строке, а могут и в разных).
Оказывается, эта простая конструкция очень неплохо доработана для связывания команд. Начать с того, что [ - это совсем не конструкция языка, а утилита:
$ ls -ial /bin/[ /bin/test 35 -r-xr-xr-x 2 root wheel 89992 5 июн 2003 /bin/[ 35 -r-xr-xr-x 2 root wheel 89992 5 июн 2003 /bin/test
Как мы видим, [ и test - имена одного и того же файла (с test, а не в руководстве по sh. Команда test принимает такие же точно параметры, что и [ (только ей не нужна завершающая квадратная скобка). Это значит, что [ 5 -gt 6 ] - на самом деле самая обычная команда, и после if может использоваться не только она, но и любая другая команда UNIX, и даже несколько. Все их if запустит и проверит if выполнит условную часть. Если неуспешно - ненулевым (тогда он равен номеру ошибки), и if выполнит противоусловную часть.
Это слегка расходится с распространенным (по вине языка Си) мнением, что в условных выражениях "ложь" представляется нулем, а "истина" - не нулем; зато в case $? ... esac, описанного в руководстве.
У команды test, помимо арифметических сравнений, есть немало других ключей для нужд test -z "$N" выполняется успешно, если переменная N пуста, test -f имя_файла - если существует файл с таким именем, test -x имя_файла - если файл существует и доступен для выполнения, test файл_1 -ot файл_2 - если первый файл старше второго и т. п. С помощью test можно создавать командные
Если необходимо выполнение одной команды поставить в зависимость от успешного выполнения другой, можно задействовать if. Однако легче воспользоваться конструкциями, перенесенными в shell из , логическое "и") и дизъюнкцией (операция ||, логическое "или") команд. В цепочке команда_1 команда_2 вторая команда выполнится только в случае успешного выполнения первой; в цепочке команда_1 || команда_2 - только в случае неуспешного выполнения. Связывание команд нередко позволяет избавиться от многоэтажных вложенных if.
В shell, как и в каждом процедурном while команды; do команды; done и цикл с перебором списка for переменная in список; do команды; done. Про первый из них можно сказать только, что истиной, как и в операторе if, считается успешное выполнение последней команды в секции условия. В цикле for списком называется последовательность слов и разделителей, которая обрабатывается по тем же правилам, что и командная строка. В результате цикл будет выполняться столько раз, сколько слов оказалось в списке, а переменная на каждом обороте цикла будет содержать очередное слово:
$ for N in 1 2 3 4 5; do echo -n "==$N=="; done ==1====2====3====4====5==$
Заметим, что, поскольку команда echo -n не печатает перевода строки в конце выдачи, результат вывелся в одну строчку; в конце этой же строки shell вывел и свою подсказку - $. Некоторые zsh ) очищают строку, в которой собираются вывести подсказку, что может слегка озадачить. В таком случае помогает echo без параметров, добавленная после всех команд, - она выводит дополнительный перевод строки:
zsh$ for N in 1 2 3 4 5; do echo -n "==$N=="; done #
выдачи мы не увидим :(
zsh$ for N in 1 2 3 4 5; do echo -n "==$N=="; done; echo #
вот она :)
==1====2====3====4====5==
Цикл вида for переменная; do команды; done в тексте for переменная in "$@".... Мелочь, а приятно: чаще всего приходится разбираться с именами файлов, которые возникают в командной строке в великом множестве на месте шаблонов. Если в таком разборе в начале командной строки были ключи, а потом уже шел список файлов, удобно пользоваться командой shift, которая выбрасывает первый (или с первого по N-ный) параметр, ставит на его место второй (N+1-й) и т. д., то есть "сдвигает" список параметров.
Операции ввода-вывода и работа с файлами, строго говоря, не вытекают из требований алгоритмической полноты, однако любой не совсем уж теоретический echo. Операция ввода имеет формат read список_переменных; она читает со
Работа с файлами устроена с наименьшим расходом символов. Для того чтобы перенаправить вывод команды в файл, достаточно написать после нее > файл, при этом старое содержимое файла (если он был) пропадет. Операция команда >> файл дописывает вывод команды в конец файла. Для того чтобы команда вводила из файла, а не с терминала, ее надо запустить так: команда < файл. Например, cat < fileIn > fileOut ничего не будет ни вводить с клавиатуры, ни выводить на экран - ничего, кроме диагностических сообщений вроде cannot open fileIn: No such file or directory.
Дело в том, что сообщения об ошибках направляются особым путем, на так называемый stderr ). Изначально и stdout ), и > перенаправляет именно команда 2> файл_с_ошибками. Если необходимо направить диагностические сообщения туда же, куда и стандартные, используйте явное указание номера дескриптора в правой части " > ": cat file1 > file2 2>1.
команда1 | команда2 (например, ls -l | less, направляет выдачу ls на вход less, которая показывает ее постранично). Работает это очень быстро (через буфер обмена в памяти системы), записывается просто, поэтому из команд, связанных по вводу/выводу, можно строить целые конвейеры:
$ ls -1 /bin | grep o | sort | tail -3 domainname echo hostname
Простота перенаправления ввода/вывода имеет свои корни. На самом деле в UNIX работа программ с файлами, с терминалом и другими устройствами, с | tee файл |, которая раздвоит поток данных и направит одну ветку в файл ( tee - английское название буквы "T", отражающей суть работы этой утилиты).
Сгруппировать потоки ввода/вывода нескольких команд (например, перенаправить весь вывод в один файл) можно, окружив их скобками - круглыми или фигурными. Для выполнения команд в круглых скобках запустится отдельная копия while ... do ... done ).
Мощный механизм связывания - ` ", этот символ еще зовется гравис ; во многих shell сработает и конструкция $(команда).
$ echo `ls -1s` total 64 56 fhs-2.2.ps.gz 4 myscript 4 o
Заметим, что, хотя ls -1 выдает список файлов в столбик, shell, передавая параметры команде echo, считает переводы строки такими же разделителями, как пробелы или символы табуляции, и echo уже не видит их.
В exec(). В shell тоже есть команда exec, запускающая процесс вместо текущей копии
В программе (например, на Си) первую половину неатомарной операции "запустить программу как новый процесс" выполняет системный вызов fork() ("вилка", "развилка"). В результате вызова fork появляется два совершенно одинаковых процесса ( fork возвращает ноль, а родительскому - PID дочернего. Разобравшись в родственных отношениях, процессы могут спокойно заниматься своими делами.
Чаще всего порожденный процесс немедленно выполняет exec, чем, собственно, и завершается упомянутая неатомарная операция. Обычный запуск команды в shell устроен именно так, причем родительский процесс дожидается завершения работы дочернего с помощью системного вызова wait(). Для того чтобы в shell запустить фоновый процесс, а самому продолжить работу, нужно всего лишь не вызывать wait, что и происходит, когда в конце командной строки стоит :
$ ( sleep 5; echo "Hi there!" ) $ # прошло пять секунд $ Hi there! [1] Done (sleep 5; echo Hi there!)
Заметим, что !.
Допустим, мы написали некоторый командный
Когда при входе в систему login запускает sh, а -sh. В результате shell начинает вести себя особенным образом, как стартовый командный интерпретатор (т. н. login shell ). В частности, он считывает и выполняет специальный /etc/profile ) и собственный sh это файл $HOME/.profile ), в который и стоит вписывать свои изменения в настройке /etc/ и .login соответственно).
Современные zsh выполняет общий, а затем - личный файл zshenv. Потом, если zprofile, а за неимением такового - profile ). Далее, если zshrc. Наконец, стартовый zsh выполняет общий и личный файлы zlogin (в нем можно пользоваться определенными в .zshrc функциями и сокращениями). По окончании сеанса работы пользователя, при завершении стартового zsh, выполнится сначала личный, а затем - общий zlogout.
В чем еще современные /bin/sh?
Многие полезные и часто используемые команды ( test, echo, kill, wait и т. п.) в современных shell делают
Во многих shell есть массивы, а в zsh предусмотрена поддержка ассоциативных массивов (по сути дела, индексированных списков). Использование ассоциативных массивов очень удобно при обработке текстов, но требует изрядного усложнения синтаксиса языка, в частности в плане
С zsh творится вообще непонятно что. Включая в язык разнообразные модификаторы, позволяющие по ходу zsh напрочь забывают об У! Мы насчитали более 50 (!) таких модификаторов, так что всякий раз, когда хочется ими воспользоваться, нужно заглядывать в руководство. Единственное, чего авторы zsh этим достигли, - вместо вызова специализированной внешней программы, вроде sed или , можно воспользоваться вложенными
Многие shell толкуют содержимое PS1 на свой лад. Впереди опять-таки zsh, в котором определено даже нечто вроде PS1 (используется для урезания длины подсказки).
Перенаправление ввода/вывода тоже со временем обогащается удобными сокращениями. Например, часто вместо > файл 2>1 вводится операция > файл, а в zsh есть еще и |, заталкивающая оба потока вывода (стандартный и ошибки) в
И наконец, по мере усложнения и распространения a* ', если файлов, начинающихся на " a ", вообще нет? Выдавать ошибку или передавать строку ' a* ' команде? В tcsh и bash подобные вопросы решались с помощью ключей самого shell, и в zsh тоже, но в нем-то таких неоднозначностей более сотни! Так что от ключей пришлось отказаться. Вместо этого для каждого модификатора поведения придумали осмысленное собственное имя и ввели команду setopt.
Любой универсальной ОС приходится много возиться с пользовательскими и своими собственными задачами. Лишь небольшая часть этой деятельности может быть запрограммирована раз и навсегда в ядре. Большая часть логики управления задачами и самой системой должна быть доступна администратору в виде проекта, иначе он просто не сможет ни понять происходящее в системе, ни тем более изменять ее. Стоит повнимательнее взглянуть на инструмент, используемый в UNIX для задания алгоритма работы многих частей системы, - на
Начнем с того, что shell - полноценный
С другой стороны, одной алгоритмической полнотой при решении задач в системе ограничиваться нельзя. Скажем, машина Тьюринга чрезвычайно проста и алгоритмически полна, однако мало кому придет в голову организовывать на основе ее модели диалог с пользователем или управление самой ОС. Здесь следует вспомнить, что shell - еще и исполнитель команд: он запросто общается с UNIX и утилитами. Значит, дополнив его механизмом управляемого взаимодействия команд с системой и друг с другом, мы получим неплохой
Самое приятное, что такая программируемая
Прежде чем рассмотреть возможности shell под двумя углами зрения, разрешим вот какое затруднение. Допустим, мы написали программу на языке какого-нибудь интерпретатора, например /bin/sh, и записали ее в некий файл, например /home/george/myscript (если /home/george - текущий каталог, можно использовать более короткий путь: myscript ). Как теперь выполнить этот man sh мы знаем, что для этого можно запустить
$ cat myscript echo "Hello, George!" $ /bin/sh myscript Hello, George!
Нельзя ли обойтись без имени программы, которая интерпретирует , потоковый текстовый редактор sed, универсальные python и perl и много чего еще. Во всех этих языках есть возможность вставлять в текст #!", любой из этих интерпретаторов проигнорирует всю первую строку как комментарий. Система же, увидев " #!" в начале файла, понимает, что это /home/george/myscript будет #!/bin/sh, его смело можно делать исполняемым (установить бит использования) и запускать:
$ chmod +x myscript $ cat myscript #!/bin/sh echo "Hello, $1!" $ ./myscript George Hello, George!
Строго говоря, после " #!" может стоять что угодно, например имя написанной нами программы с некоторыми обязательными параметрами; UNIX ее запустит и передаст ей в качестве George ). Если же после " #!" будет стоять несуществующий файл, система выдаст сообщение об ошибке:
$ cat myscript #!/bad/sh echo "Hello, $1!" $ ./myscript ./myscript: not found
Обратите, пожалуйста, внимание на то, что из этого сообщения якобы следует, что не найден сам файл
И еще одно немаловажное замечание. Сначала в UNIX был только один
Однако программировать командные оказалось... менее удобно, чем на sh. Во-первых, синтаксис языка Си в точности воспроизвести не удалось, возникла путаница; во-вторых, многие системные sh, либо с .
Долгое время бытовало мнение, что работать лучше в , а sh, хотя совмещать два разных языка в одной области деятельности неудобно. С тех пор было создано немало других, еще более мощных sh - и -образных оболочек. Они все время дорабатывались, попеременно обгоняя друг друга по охвату возможностей. Пальма первенства принадлежала то bash (Bourne-again shell, детище GNU), то tcsh (международный открытый проект, развивающий ), то zsh (также международный открытый проект, но с sh -совместимостью). На сегодня нельзя с уверенностью сказать, какой из них мощнее (хотя документации по zsh больше, чем по bash и tcsh, вместе взятых, раза в два), но устаревшее мнение о sh и стоит пересмотреть: теперь в какой
Как уже говорилось, многие абстракции
С одной стороны,
$ One=U; Three=Zzz $ echo Example 1: $One $Two $Three Example 1: U Zzz $ echo "Example 2: $One $Two $Three" Example 2: U Zzz $ echo 'Example 3: $One $Two $Three' Example 3: $One $Two $Three
Из первого примера видно, что сам факт присваивания объявляет переменную, а содержимое необъявленной переменной просто считается пустым (напомним, что команда echo выводит все $имя_переменной ) продолжает работать, если текст заключен в двойные кавычки, и не работает, если используются одинарные. По договоренности (см. главу 7) закавыченный текст передается как один echo выводит один пробел между U и Zzz: она получает четыре параметра ( Example 1: U и Zzz ), разделенные цепочками пробелов.
Несмотря на то что переменные в shell - строкового типа, легко организовать арифметические операции над ними: если содержимое переменной нельзя интерпретировать как число, арифметическая операция завершается с ошибкой. Арифметика встроена почти во все виды $((арифметическое выражение)). Есть надежда, что арифметическая sh или Linux- ash будет работать и в остальных
$ A=7; b=3; echo $(($A*$b)) 21
В примере, описывающем понятие 1 ( $1 ), второй - в переменную с именем 2 и т. д., пока есть $# (напомним, что по американской традиции этот символ используется вместо нашего No). Все $* или $@ (Какая между этими формами разница?
Столь простая схема передачи параметров - явная доработка языка в сторону средств интеграции: чаще всего небольшой
С другой стороны,
Например, утилита ls использует COLUMNS, в которой хранится наибольшая допустимая ширина текста. Можно обычным присваиванием изменить значение этой переменной, и ls примет его к сведению:
$ echo $COLUMNS $ ls Makefile myscript uzor.c fhs-2.2-source.tar.gz o.ps $ COLUMNS=60 $ ls Makefile o.ps fhs-2.2-source.tar.gz uzor.c myscript
Многие программы используют переменную ." не включен в список), в одном из приведенных выше примеров мы были вынуждены явно указывать его в виде ." в PATH небезопасно: кто может знать, не окажется ли в текущем каталоге исполняемый файл с именем, скажем, ls, и кто может знать, что на самом деле этот файл будет делать при запуске?
Список определяемых set. Желающих узнать, какими
Сам shell пользуется многими PS1 (Если есть PS1, то должно быть PS2, а может, и PS3, и PS4. Для чего они? $ " для обычного пользователя и " # " для суперпользователя. Потом решили использовать PS1 для вывода кое-какой полезной информации: имени компьютера, имени пользователя, даты входа в систему или прочей относительно статической информации. Это просто, достаточно написать что-то вроде:
$ echo $PS1 $ $ PS1="`logname`@`hostname`> " george@book.altlinux.ru> george@book.altlinux.ru>
Однако статическая информация - не самое полезное в работе. Гораздо интереснее держать в PS1, скажем, путь к текущему каталогу или точное время. PS1. Сам shell изменять PS1 не будет, значит, надо его доработать. Первый способ доработки - научить его выполнять определенную последовательность команд перед тем, как выводить очередную подсказку или при смене текущего каталога (так поступили разработчики tcsh: там можно задать специальные функции precmd, cwdcmd и некоторые другие). В эту последовательность команд можно вставить команды изменения PS1. Другой вариант - считать некоторые последовательности символов в PS1 специальными и при выводе подсказки заменять их соответствующими значениями - путем, временем и т. п. Вот, например, как это делается в bash:
bash$ pwd /usr/share/doc bash$ PS1="[\A]\u@\h:\w> " [17:30]george@book:/usr/share/doc> [17:30]george@book:/usr/share/doc>
Один init ). Остальные переменные будут считаться локальными и никуда не перейдут. Если мы хотим вызвать из одного
$ cat changeA A="NewA" $ A="" $ . changeA $ echo $A NewA
В алгоритмически полном if. Он, конечно, есть и в shell:
$ if [ 5 -gt 6 ]; then echo "Bug"; else echo "Good"; fi Good
Обратите внимание на ключ -gt, означающий greater than, и на fi в конце оператора - так в shell устроены if, then, необязательное else и fi ограничивают условие, условную часть и необязательную противоусловную часть; они могут находиться в одной строке, а могут и в разных).
Оказывается, эта простая конструкция очень неплохо доработана для связывания команд. Начать с того, что [ - это совсем не конструкция языка, а утилита:
$ ls -ial /bin/[ /bin/test 35 -r-xr-xr-x 2 root wheel 89992 5 июн 2003 /bin/[ 35 -r-xr-xr-x 2 root wheel 89992 5 июн 2003 /bin/test
Как мы видим, [ и test - имена одного и того же файла (с test, а не в руководстве по sh. Команда test принимает такие же точно параметры, что и [ (только ей не нужна завершающая квадратная скобка). Это значит, что [ 5 -gt 6 ] - на самом деле самая обычная команда, и после if может использоваться не только она, но и любая другая команда UNIX, и даже несколько. Все их if запустит и проверит if выполнит условную часть. Если неуспешно - ненулевым (тогда он равен номеру ошибки), и if выполнит противоусловную часть.
Это слегка расходится с распространенным (по вине языка Си) мнением, что в условных выражениях "ложь" представляется нулем, а "истина" - не нулем; зато в case $? ... esac, описанного в руководстве.
У команды test, помимо арифметических сравнений, есть немало других ключей для нужд test -z "$N" выполняется успешно, если переменная N пуста, test -f имя_файла - если существует файл с таким именем, test -x имя_файла - если файл существует и доступен для выполнения, test файл_1 -ot файл_2 - если первый файл старше второго и т. п. С помощью test можно создавать командные
Если необходимо выполнение одной команды поставить в зависимость от успешного выполнения другой, можно задействовать if. Однако легче воспользоваться конструкциями, перенесенными в shell из , логическое "и") и дизъюнкцией (операция ||, логическое "или") команд. В цепочке команда_1 команда_2 вторая команда выполнится только в случае успешного выполнения первой; в цепочке команда_1 || команда_2 - только в случае неуспешного выполнения. Связывание команд нередко позволяет избавиться от многоэтажных вложенных if.
В shell, как и в каждом процедурном while команды; do команды; done и цикл с перебором списка for переменная in список; do команды; done. Про первый из них можно сказать только, что истиной, как и в операторе if, считается успешное выполнение последней команды в секции условия. В цикле for списком называется последовательность слов и разделителей, которая обрабатывается по тем же правилам, что и командная строка. В результате цикл будет выполняться столько раз, сколько слов оказалось в списке, а переменная на каждом обороте цикла будет содержать очередное слово:
$ for N in 1 2 3 4 5; do echo -n "==$N=="; done ==1====2====3====4====5==$
Заметим, что, поскольку команда echo -n не печатает перевода строки в конце выдачи, результат вывелся в одну строчку; в конце этой же строки shell вывел и свою подсказку - $. Некоторые zsh ) очищают строку, в которой собираются вывести подсказку, что может слегка озадачить. В таком случае помогает echo без параметров, добавленная после всех команд, - она выводит дополнительный перевод строки:
zsh$ for N in 1 2 3 4 5; do echo -n "==$N=="; done #
выдачи мы не увидим :(
zsh$ for N in 1 2 3 4 5; do echo -n "==$N=="; done; echo #
вот она :)
==1====2====3====4====5==
Цикл вида for переменная; do команды; done в тексте for переменная in "$@".... Мелочь, а приятно: чаще всего приходится разбираться с именами файлов, которые возникают в командной строке в великом множестве на месте шаблонов. Если в таком разборе в начале командной строки были ключи, а потом уже шел список файлов, удобно пользоваться командой shift, которая выбрасывает первый (или с первого по N-ный) параметр, ставит на его место второй (N+1-й) и т. д., то есть "сдвигает" список параметров.
Операции ввода-вывода и работа с файлами, строго говоря, не вытекают из требований алгоритмической полноты, однако любой не совсем уж теоретический echo. Операция ввода имеет формат read список_переменных; она читает со
Работа с файлами устроена с наименьшим расходом символов. Для того чтобы перенаправить вывод команды в файл, достаточно написать после нее > файл, при этом старое содержимое файла (если он был) пропадет. Операция команда >> файл дописывает вывод команды в конец файла. Для того чтобы команда вводила из файла, а не с терминала, ее надо запустить так: команда < файл. Например, cat < fileIn > fileOut ничего не будет ни вводить с клавиатуры, ни выводить на экран - ничего, кроме диагностических сообщений вроде cannot open fileIn: No such file or directory.
Дело в том, что сообщения об ошибках направляются особым путем, на так называемый stderr ). Изначально и stdout ), и > перенаправляет именно команда 2> файл_с_ошибками. Если необходимо направить диагностические сообщения туда же, куда и стандартные, используйте явное указание номера дескриптора в правой части " > ": cat file1 > file2 2>1.
команда1 | команда2 (например, ls -l | less, направляет выдачу ls на вход less, которая показывает ее постранично). Работает это очень быстро (через буфер обмена в памяти системы), записывается просто, поэтому из команд, связанных по вводу/выводу, можно строить целые конвейеры:
$ ls -1 /bin | grep o | sort | tail -3 domainname echo hostname
Простота перенаправления ввода/вывода имеет свои корни. На самом деле в UNIX работа программ с файлами, с терминалом и другими устройствами, с | tee файл |, которая раздвоит поток данных и направит одну ветку в файл ( tee - английское название буквы "T", отражающей суть работы этой утилиты).
Сгруппировать потоки ввода/вывода нескольких команд (например, перенаправить весь вывод в один файл) можно, окружив их скобками - круглыми или фигурными. Для выполнения команд в круглых скобках запустится отдельная копия while ... do ... done ).
Мощный механизм связывания - ` ", этот символ еще зовется гравис ; во многих shell сработает и конструкция $(команда).
$ echo `ls -1s` total 64 56 fhs-2.2.ps.gz 4 myscript 4 o
Заметим, что, хотя ls -1 выдает список файлов в столбик, shell, передавая параметры команде echo, считает переводы строки такими же разделителями, как пробелы или символы табуляции, и echo уже не видит их.
В exec(). В shell тоже есть команда exec, запускающая процесс вместо текущей копии
В программе (например, на Си) первую половину неатомарной операции "запустить программу как новый процесс" выполняет системный вызов fork() ("вилка", "развилка"). В результате вызова fork появляется два совершенно одинаковых процесса ( fork возвращает ноль, а родительскому - PID дочернего. Разобравшись в родственных отношениях, процессы могут спокойно заниматься своими делами.
Чаще всего порожденный процесс немедленно выполняет exec, чем, собственно, и завершается упомянутая неатомарная операция. Обычный запуск команды в shell устроен именно так, причем родительский процесс дожидается завершения работы дочернего с помощью системного вызова wait(). Для того чтобы в shell запустить фоновый процесс, а самому продолжить работу, нужно всего лишь не вызывать wait, что и происходит, когда в конце командной строки стоит :
$ ( sleep 5; echo "Hi there!" ) $ # прошло пять секунд $ Hi there! [1] Done (sleep 5; echo Hi there!)
Заметим, что !.
Допустим, мы написали некоторый командный
Когда при входе в систему login запускает sh, а -sh. В результате shell начинает вести себя особенным образом, как стартовый командный интерпретатор (т. н. login shell ). В частности, он считывает и выполняет специальный /etc/profile ) и собственный sh это файл $HOME/.profile ), в который и стоит вписывать свои изменения в настройке /etc/ и .login соответственно).
Современные zsh выполняет общий, а затем - личный файл zshenv. Потом, если zprofile, а за неимением такового - profile ). Далее, если zshrc. Наконец, стартовый zsh выполняет общий и личный файлы zlogin (в нем можно пользоваться определенными в .zshrc функциями и сокращениями). По окончании сеанса работы пользователя, при завершении стартового zsh, выполнится сначала личный, а затем - общий zlogout.
В чем еще современные /bin/sh?
Многие полезные и часто используемые команды ( test, echo, kill, wait и т. п.) в современных shell делают
Во многих shell есть массивы, а в zsh предусмотрена поддержка ассоциативных массивов (по сути дела, индексированных списков). Использование ассоциативных массивов очень удобно при обработке текстов, но требует изрядного усложнения синтаксиса языка, в частности в плане
С zsh творится вообще непонятно что. Включая в язык разнообразные модификаторы, позволяющие по ходу zsh напрочь забывают об У! Мы насчитали более 50 (!) таких модификаторов, так что всякий раз, когда хочется ими воспользоваться, нужно заглядывать в руководство. Единственное, чего авторы zsh этим достигли, - вместо вызова специализированной внешней программы, вроде sed или , можно воспользоваться вложенными
Многие shell толкуют содержимое PS1 на свой лад. Впереди опять-таки zsh, в котором определено даже нечто вроде PS1 (используется для урезания длины подсказки).
Перенаправление ввода/вывода тоже со временем обогащается удобными сокращениями. Например, часто вместо > файл 2>1 вводится операция > файл, а в zsh есть еще и |, заталкивающая оба потока вывода (стандартный и ошибки) в
И наконец, по мере усложнения и распространения a* ', если файлов, начинающихся на " a ", вообще нет? Выдавать ошибку или передавать строку ' a* ' команде? В tcsh и bash подобные вопросы решались с помощью ключей самого shell, и в zsh тоже, но в нем-то таких неоднозначностей более сотни! Так что от ключей пришлось отказаться. Вместо этого для каждого модификатора поведения придумали осмысленное собственное имя и ввели команду setopt.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.