Психология командной строки

Feb 21, 2009 18:52

Оригинал здесь: Command line psychology 101
вольный пересказ мой

Одно из главных чудес Юникс (кроме самой системы) - это командная строка, полная этих странных и загадочных символов. Вот, что тут надо вставить, точку между двумя обратными косыми, или левую кавычку с минусом?

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

Командная строка передается для обработки программе-оболочке (ака шелл). Оболочка (sh, ksh, csh или любая другая) читает строку и "распутывает" то, что вы там понаписали, до того как попытается выполнить команду. Последовательность шагов по "распутыванию" командной строки весьма поучительна. Поняв, как это работает, вы освоите новые для себя приемы и способы эффективной работы.

Сейчас мы всё это изучим, но для начала посмотрим на последовательность шагов обработки командной строки:

1. Подстановка истории (кроме Bourne shell)
2. Разделение на слова, включая спецзнаки
3. Обновление истории (кроме Bourne shell)
4. Обработка одинарных и двойных кавычек
5. Подстановка псевдонимов (alias) (кроме Bourne shell)
6. Перенаправление ввода/вывода (< > и |)
7. Подстановка значений переменных (переменные начинаются со знака $)
8. Подстановка результатов выполнения команд (команда это то, что в левых кавычках)
9. Разворачивание имён файлов по шаблонам

Как вы уже, наверное, заметили, Bourne shell не поддерживает историю и псевдонимы (bash, Bourne again shell, поддерживает).

Подстановка истории

Если в вашей оболочке включена поддержка истории, отдаваемые команды перед выполнением сохраняются в файле. Вы можете просмотреть его содержимое набрав:

$ history

Список команд пронумерован, как здесь:

13 ls *.txt
14 cd $HOME
15 ls *.log

В оболочке Корна вы можете восстановить команду, набрав r и её номер через пробел. Набрав r 13 из предыдущего примера мы получим команду la *.txt.

В csh (и в zsh) вместо r используется восклицательный знак без пробела: !13.

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

Разделение на слова

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

ls -l|grep mjb

В этой команде имеем следующие слова: ls, -l, |, grep, mjb. Закавыченная строка может также являться отдельным словом. В следующей команде будем искать файл созданный "Sep 07".

ls -l|grep "Sep 07"

В этом случае словами будут: ls, -l, |, grep и "Sep 07". "Sep 07" трактуется как одно слово только потому, что эта строка закавычена.

Обновление истории

Как только строка разобрана на слова, она добавляется в конец файла истории. (Надеюсь, что поддержка истории у вас включена).

Одинарные и двойные кавычки

Когда интерпретатор встречает слово, заключённое в одинарные или двойные кавычки, он помечает его чтобы в дальнейшем подвергнуть обработке или наоборот, оставить как есть. Переменные, встречающиеся внутри строки, заключённой в одинарные кавычки, оставляются не тронутыми. Переменные внутри двойных кавычек заменяются на их значения. Чтобы посмотреть как это работает, введём следующие команды:

echo $PATH
echo '$PATH'
echo "$PATH"

Первая команда выведет значение переменной PATH. Вторая отобразит $PATH. Третья опять выведет значение:

echo $PATH
/bin:/usr/bin:/my/bin:.

echo '$PATH'
$PATH

echo "$PATH"
/bin:/usr/bin:/my/bin:.

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

echo $PATH
/bin:/usr/bin:/my/bin:.

echo '"$PATH"'
"$PATH"

echo "'$PATH'"
'/bin:/usr/bin:/my/bin:.'

Подстановка псевдонимов (alias)

Теперь оболочка берет первое слово в команде и сверяет его со списком псевдонимов. В примере, которому мы будем следовать, со списком будут сверены слова ls и grep. Если совпадение обнаруживается, то выполняется соответствующая подстановка. Я не уделял достаточного внимания псевдонимам в предыдущих статьях, поэтому попытаюсь тут рассказать поподробнее. Псевдонимы позволяют заменять одни команды на другие. Так, следующая команда:

alias ll 'ls -l'

создаст новую команду. И если вы наберёте

ll *.txt

, это будет эквивалентно

ls -l *.txt

Прим. перев.
Наверное этот этап происходит всё-таки позднее, после обработки перенаправлений. Иначе как оболочка узнает, что наша строка состоит из нескольких команд? Ей ведь надо выполнить подстановку для первого слова в каждой команде.

Перенаправление ввода/вывода (< > и |)

На этом этапе оболочка ищет среди слов знаки пренаправления ввода/вывода: >, <, >>, | и некоторые другие. Найдя, организует требуемые пайпы и перенаправления.

Подстановка значений переменных

Вот тут наконец, доходит дело и до пременных. Все переменные, встреченные вне одинарных кавычек, заменяются на их значения. Главное, про знак $ не забывать.

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

Интерпретатор берет строку, заключённую в левые кавычки, и выполняет как команду. Вывод, получившийся в результате выполнения этой команды, подставляется обратно в исходную командную строку.

Попробуйте выполнить:

ls -l `ls -p|grep /`|more

Команда ls -p выведет список файлов, в котором директории будут отмечены косой чертой (слешем) после имени. Например, так:

ls -p

STARTUP
file.txt
file2.txt
mystuff/
xdir/

Затем этот список будет передан команде grep /, которая оставит от него только строки с символом /.

ls -p|grep /

mystuff/
xdir/

Заключив эту последовательность в левые кавычки, мы заставляем интерпретатор выполнить её как команду, а результат использовать в качестве аргумента команды ls. Таким образом, команда

ls -l `ls -p|grep /`|more

будет эквивалентна команде

ls -l mystuff/ xdir/|more

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

Разворачивание имён файлов по шаблонам

Командный процессор ищет символы-джокеры в именах файлов и производит расширение таких конструкций в список. Стандартно используются символы *, ? и квадратные скобки []. Звёздочка может быть заменена на любое количество знаков. Вопросительный знак заменяется на один и только один любой знак. Скобки заменяются на один из знаков, перечисленных внутри скобок.

ls -l [abc]*

приведет к перечислению всех файлов и директорий, имя которых начинается на a, b или c.

Выполнение

Завершает всю эту длинную цепь действий выполнение получившейся команды.

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

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

echo files in /chosen/directory are ; echo `cd /chosen/directory; ls *`

В результате получаем список файлов в /chosen/directory. Звёздочка будет преобразована в список файлов только после того, как будет выполнена команда смены директории. В противном случае мы получили бы список файлов текущей директории.

Таким образом, команды в левых кавычках обрабатываются и выполняются так, как если бы они были отдельными командами (все девять шагов). Это же справедливо и для нескольких команд в строке, разделённых точками с запятой.

Unix Insider

linux, шелл, линукс, shell, команды

Next post
Up