Основы использования командной строки
Перенаправление ввода вывода
Как уже упоминалось, любая программа имеет доступ к трем инициализированным перед ее запуском файловым дескрипторам: 0 (стандартный поток ввода, stdin), 1 (стандартный поток вывода, stdout) и 2(стандартный поток ошибок, stderr). Подготовкой этих файлов занимаются ОС и иногда запускающий процесс, программа получает уже готовые к использованию дескрипторы. По умолчанию все три дескриптора ассоциируются с терминалом. В качестве наглядной демонстрации удобства подобного подхода рассмотрим утилиту cat. Сама по себе она достаточно бессмысленна --- читает данные из stdin и выводит их в stdout.
$ cat Hello Hello
Но существует возможность при запуске программы изменить файлы, ассоциированные с стандартными потоками. Например, шелл позволяет сделать это при помощи операторов <, > и >>. "<" перенаправляет стандартный потока ввода, ">" --- стандартный потока вывода, затирая старое содержимое аргумента, ">>" перенаправляет стандартный поток вывода, добаввляя его содержимое в конец файла-аргумента.
$ cat >> File Hello $ cat < File Hello $ cat >> File I love you $ cat < File Hello I love you $ cat > File Hello? $ cat < File Hello? $ cat < File > .FileFile $ cat .FileFile Hello?
Перенаправление стандартного потока ошибок в шелле реализуется конструкцией "2> filename". Например, у утилиты cat нет ключа --l, и если попытатся вызвать ее с ним, она выведет диагностическое сообщение в стандартный поток ошибок.
$ cat --l < File > .FileFile 2>Error $ cat Error cat: нераспознанный ключ `--l'
Еще более интересным и многообещающим является возможность ассоциирования стандартного потока вывода одной программы с стандартным потоком ввода другой. В шелле это организуется оператором |. Обычно для реализации этой функциональности на системном уровне используются безымянные pipe.
Программа cal выводит календарь на месяц. Если с потоком вывода проассоциирован терминал, то cal раскрашивает текущий день. В противном случае выводится просто текст. Например, при вызове cal | cat выделения цветом не будет (так как потоком вывода для cal будет безымянный канал).
$ cal | cat Июль 2008 Вс Пн Вт Ср Чт Пт Сб 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Утилита wc выводит количество символов/слов/переводов строк в стандартном потоке ввода.
$ cal | wc 8 40 186
Можно делать длинные конвейеры: cal | tac | tac (утилита tac выводит поступившие ей строки в обратном порядке, так что, если применить её два раза, ничего не произойдёт):
$ cal | tac | tac Июль 2008 Вс Пн Вт Ср Чт Пт Сб 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
cal | head -2 | tail -1 (утилита head выводит заданное количество первых строк ввода, tail --- последних. Комбинируя эти утилиты, можно получить произвольный срез файла по строкам):
$ cal | head -2 | tail -1 Вс Пн Вт Ср Чт Пт Сб
Перенаправление --- очень эффективный интрумент, использующийся практически в любом шелл-сценарии.
Для чего нужен шелл?
Шелл выполняет 3 функции:
- Предоставляет удобные средства для работы с командной строкой. Например, историю команд и дополнение по tab.
- Предоставляет возможность комбинировать и интегрировать различные утилиты. Каждая утилита, сама по себе, обычно решает небольшую задачу, при этом получая данные и выдавая результат в текстовом виде. В такой схеме перенаправление ввода-вывода позволяет реализовать совместную работу нескольких утилит, и, таким образом, решить пользовательскую задачу. Подобное удобство манипулирования утилитами предоставляет только шелл, и именно это является его основной функцией.
- И, наконец, шелл --- это полноценный высокоуровневый язык программирования, оперирующий объектами файловой системы.
Переменные
Как в любом языке программирования, в шелле есть перменные. В силу особенностей назначения шелла все переменные в нем являются строковыми.
Пример инициализации переменной:
$ VAR="Value Value" $ echo $VAR Value Value
Переменные автоматически передаются процессам, запущенным из шелла, в качестве части окружения процесса. Окружение процесса --- это набор достаточно разнообразнй информации, связанный с процессом. Туда входят, например, текущий каталог, дескрипторы открытых файлов, и т. п. При fork окружение практически полностью наследуется. Некоторые переменные, например HOME или PATH определяются при входе пользователя в систему, в так называемом login shell, и от него наследуются всеми процессами, запущенными пользователем. Переменная PATH содержит список каталагов, в которых шелл ищет исполняемые файлы.
$ echo $PATH /home/george/bin:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/usr/games
Заметим, что в отличие от DOS, текущий каталог в PATH не включен.
Подстановки.
Чтобы дать пример того, насколько мощным интегратором является шелл, рассмотрим ещё одну вещь. Обратите внимание на то, каким образом переменной присваивается значение с пробелом. Закавычивание для параметра с пробелами сохраняет его в том виде, в котором он написан внутри кавычек. Если без кавычек, то будет иначе.
$ echo "$VAR" Value Value $ echo $VAR Value Value
Генерация список файлов по шаблону (FNG, FileName Generation). Что это такое? Когда вы хотите совершить групповую операцию над файлами, то для задания групп используются специальные символы: * --- любое количество символов, ? --- один символ, [abc] или [a-z] --- символ из диапазона, [^a-z] --- символ не из диапазона.
Например, echo F*.
$ echo F* FFFFF FFFile1 FFFile2 File File1 File2 File3 File4 File45
Примеры с диапазонами и вопросительным знаком:
$ echo File?? File45 $ echo File[2-4] File2 File3 File4 $ echo File[^2-4] File1 $ echo File[2-4F*] File2 File3 File4 $ echo File[2-4F]* File2 File3 File4 File45
Кто превратил F* в список файлов? Шелл. Когда шелл видит спецсимвол, то он применяет шаблон к именам файлов. Какие вещи не стоит забывать при использовании FNG: этим занимается шелл, и прграмма ничего об этом не знает. Второе --- файлы с точки не включаются в FNG по умолчанию. При этом .* включит файлы . и .., что не всегда хорошо. {{{$ echo .* . .. .FileFile .FileFileFile }}} Общего решения для этого нет, но в частных случаях можно попробовать исключения (.[^.]* ..?*):
$ echo .[^.]* .FileFile .FileFileFile
Сведения о ресурсах
Готовность (%) |
Продолжительность (ак. ч.) |
Подготовка (календ. ч.) |
Полный текст (раб. д.) |
Предварительные знания |
Level |
Maintainer |
Start date |
End date |
20 |
1 |
1 |
1 |
|
1 |
|
|