Основы использования командной строки

Для чего нужен командный интерпретатор?

Командный интерпретатор (или, на сленге, шелл --- от англ. unix shell) выполняет 3 функции:

Переменные

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

Пример инициализации переменной. Заметьте, что при инициализации переменной до и после знака "=" не должно стоять пробелов, и что для получения значения переменной перед ее именем обязательно ставят символ "$", а имя может быть заключено в фигурные скобки для определенности.

$ VAR="Value Value"
$ echo $VAR
Value Value
$ echo VAR
VAR
$ echo "Переменная VAR : ${VAR} сейчас"
Переменная VAR : Value Value сейчас

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

Некоторые переменные, например HOME или PATH определяются при входе пользователя в систему в запускаемом при входе пользователя интерпретаторе (login shell), и от него наследуются всеми процессами, запущенными пользователем. Переменная PATH содержит список каталагов, в которых шелл ищет исполняемые файлы.

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Заметим, что в отличие от Windows, DOS и ранних версий UNIX, текущий каталог ("./") в PATH не включен по соображениям безопасности.

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

$ VAR="Value      Value"
$ echo "$VAR"
Value      Value
$ echo $VAR
Value Value

Как видно, при использовании кавычек значение сохраняется в первосданном виде. Без закавычивания несколько пробелов превращаются в один.

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

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

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

В качестве наглядной демонстрации удобства подобного подхода рассмотрим утилиту cat. Сама по себе она достаточно бессмысленна --- читает данные из stdin и выводит их в stdout. Поэтому, если пользователь при работе с ней наберет на клавиатуре "Hello" и Enter, то именно это слово и будет выведено на экран:

$ cat  
Hello                       
Hello                 

При работе с командной средой существует возможность при запуске каждой программы изменить поведение стандартных потоков, например, связав их с файлами. Например, позволяет сделать это при помощи символов "<" , ">" и ">>", записываемых после параметров команды:

Рассмотрим следующие примеры использования перенаправления ввода-вывода в файл.

$ # Здесь пользователь набирает "Hello" на клавиатуре:
$ cat >> File
Hello                       
$ # А здесь выводит созданный файл на экран:
$ cat < File1
Hello       
$ # Здесь пользователь набирает "Hello World" на клавиатуре:
$ cat >> File1
Hello World
$ # И еще раз выводит созданный файл на экран:
$ cat < File1
Hello                       
Hello World
$ # Записываем "Hello?" в файл, затирая старое содержимое:
$ echo "Hello?" > File1            
$ cat < File1
Hello?
$ # Копируем File1 в File2 через перенаправления ввода-вывода:
$ cat < File1 > File2
$ cat File2
Hello?                      

Перед символами можно указать номер дескриптора для перенаправления. Таким образом, перенаправление стандартного потока ошибок в файл реализуется конструкцией "2>", например:

$ script -t my_script 2> my_script.time

Например, у утилиты cat нет ключа --l, и если попытаться вызвать ее с ним, она выведет диагностическое сообщение в стандартный поток ошибок.

$ cat --l < File1 > File3 2> Error
$ cat Error
cat: нераспознанный ключ `--l'

Если мы хотим поместить в один файл и сообщения об ошибках, и стандартный вывод программы, то можно использовать конструкцию "&>". Следующая команда поместит в файл File3 сообщение о невозможности прочитать файл /etc/shadow и содержимое файла /etc/passwd.

$ cat /etc/shadow /etc/passwd &> File3

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

Программа 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           

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

$ cal | head -2 | tail -1
Вс Пн Вт Ср Чт Пт Сб 

Перенаправление --- очень эффективный интрумент, использующийся практически в любом сценарии на языке Shell.

Генерация списка файлов по шаблону

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

Примеры:

$ # Файлы, начинающиеся с "F": 
$ ls F*
File1 File2 File3 File4 File45 File678
$ # Файлы с именами из "File" и двумя символами после:
$ ls File??
File45                      
$ # "[2-4]" означает диапазон из 2, 3, 4:
$ ls File[2-4]
File2 File3 File4           
$ # ^ означает инверсию, "[^2-4]" --- один символ не из диапазона 2-4:
$ ls File[^2-4]
File1    
$ # "[2-46*]" --- символ 2, 3, 4, 6 или "*":
$ ls File[2-46*]
File2 File3 File4           
$ # "[2-46]*" --- 2, 3, 4 или 6, после которых может идти что угодно:
$ ls File[2-46]*
File2 File3 File4 File45 File678   

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

Так же надо обратить внимание, что файлы, имя которых начинается с точки (".") по умолчанию не включаются в генерируемые списки, соответствующие шаблону "*", а под ".*" попадают далеко не всегда нужные каталоги "." и "..": {{{$ ls .* . .. .FileFile .FileFileFile }}} Общего удобного решения этой проблемы не существует. В частных случаях можно попробовать воспользоваться исключением:

$ ls .[^.]*
.FileFile .FileFileFile
$ ls .[^.]* *
.FileFile .FileFileFile File1 File2 File3 File4 File45 File678

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

$ # Cоздаем файл c именем -l
$ echo 1 > -l
$ ls
File1  File2  File3  File4  File45  File678 -l
$ # А здесь ls "думает", что ее вызвали с ключом -l:
$ ls *
-rw-r--r-- 1 user user 1 2008-08-01 08:14 File1
-rw-r--r-- 1 user user 1 2008-08-01 08:15 File2
-rw-r--r-- 1 user user 1 2008-08-01 08:15 File3
-rw-r--r-- 1 user user 1 2008-08-01 08:15 File4
-rw-r--r-- 1 user user 1 2008-08-01 08:15 File45
-rw-r--r-- 1 user user 1 2008-08-01 08:16 File678


Сведения о ресурсах

Готовность (%)

Продолжительность (ак. ч.)

Подготовка (календ. ч.)

Полный текст (раб. д.)

Предварительные знания

Level

Maintainer

Start date

End date

70

1

1

1

1

MaximByshevskiKonopko, Allena, VsevolodKrishchenko


CategoryLectures CategoryPspo CategoryMpgu CategoryUneex