Говорим на UNIX, часть 2: больше работы головой - меньше руками

Mar 01, 2009 22:34

Говорим на UNIX, часть 2: больше работы головой - меньше руками
сокращения оболочки помогают экономить усилия и время

Уровень: средний
Оригинал здесь: Speaking UNIX, Part 2: Working smarter, not harder
Перевод мой, весьма вольный, с сокращениями и добавлениями

Не ломай пальцы, дай им отдохнуть

Если вы ознакомились с первой частью статьи, вы уже должны были проникнуться уважением к той мощи и гибкости, которую предоставляет в ваше распоряжение командная строка оболочки. Рассмотрим команду, которая находит все текстовые документы в вашей домашней директории, содержащие фразу "Montly Report" (ежемесячный отчёт):

$ find /home/joe -type f -name '*.txt' -print | xargs grep -l "Monthly Report"

Команда "find /home/joe" просматривает вашу домашнюю директорию в поисках обычных файлов (-type f) оканчивающихся на ".txt". Всё найденное передаётся на вход утилите xargs, которая для каждого из полученных имён файлов запускает утилиту grep, выполняющую поиск упоминания в документе месячного отчёта.

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

Поддержка облегчения ввода и экономии нажатий клавиш со стороны современных командных оболочек реализована многими механизмами:

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

Например, вы можете ссылаться на свою домашнюю директорию с помощью спецсимвола "~" (тильда). Другой способ сослаться на дом.дир. - использовать переменную окружения $HOME:

$ whoami
strike
$ echo ~
/Users/strike
$ echo $HOME
/Users/strike
$ !!
echo $HOME
/Users/strike

Последняя команда - два восклицательных знака - выглядит несколько непривычно. Это спец. сокращение для работы с историей команд (в zsh), вызывает последнюю из выполненных команд. Многие оболочки позволяют прокручивать историю используя клавиши-стрелки или комбинации типа Ctrl+P.

Сейчас мы рассмотрим каждый из этих механизмов ускорения работы поподробнее. Примеры в статье используют Z shell, которая обычно устанавливается по адресу /bin/zsh (пр.пер.: а у меня в /usr/bin/zsh). Свои особенности у zsh конечно есть, но примеры должны работать в большинстве современных оболочек.

Спецсимволы (sigils)

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

Как уже упоминалось выше, тильда (~) ссылается на вашу домашнюю директорию. Похожее сокращение, ~username, ссылается на домашнюю директорию пользователя username. И, чтобы скопировать файл из дом.дир. joe в свою (в поддиректорию info) вы можете использовать такую запись:

$ cp ~joe/doc/report.txt ~/info

===== врезка: проверка =====
Если вы решите посмотреть как и на что спецсимволы будут заменены перед выполнением команды, используйте echo:

$ echo ~joe/doc/report.txt ~/info
/guests/joe/doc/report.txt /staff/bobr/info
$ echo $SHELL
/bin/zsh
$ ls
architecture.txt Services.pdf
services.txt Schema.pdf
$ echo *.txt
architecture.txt services.txt

echo просто выдаёт свой аргумент на stdout. Однако оболочка производит большинство своих манипуляций с командной строкой ещё до запуска команды на выполнение. Таким образом все подстановки становятся видны.
===== конец врезки =====

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

Например, вы сейчас в директории ~/jane/projects/lambda, сокращение "../.." укажет на два уровня выше, т.е. ~/jane. Чтобы указать на директорию, в которой расположена ~/jane, надо использовать "../../../" ("тремя уровнями выше") или так: "~jane/../". Последний путь начинает отсчёт с ~jane, а затем поднимается на один уровень вверх.

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

$ cp -pr /path/to/lots/of/stuff .

Если путь начинается с точки или двух, он считается относительным. И наоборот, если путь начинается с косой черты (/) или с тильды (~), он считается абсолютным, поскольку точно определяет положение файла в системе независимо от того, где вы сейчас находитесь.

Метасимволы и шаблоны

Подобно тому как спецсимволы облегчают работу по указанию путей в конкретные директории, метасимволы и шаблоны облегчают работу с содержимым этих директорий.

Пусть у вас есть директория, и в ней 100 файлов. Там есть исходники на языке Си (.c), объектные файлы (.o), текстовые (.txt), скрипты (.sh), а также исполняемые файлы (без расширения в имени но имеюшие разрешение на выполнение). Чтобы просто перечислить Си-файлы, набираем:

$ ls *.c

Метасимвол * обозначает соответствие любому количеству любых символов. Таким образом, оболочка будет выбирать файлы, имена которых состоят из любого количества сиволов, но оканчивающиеся обязательно на ".c". Найдя все такие файлы в текущей директории, оболочка передаст список команде ls и запустит её на выполнение.

Следующий листинг иллюстрирует работу шаблона на примере директории с исходными текстами wget, cli-утилиты для скачивания файлов:

$ ls *.c
alloca.c
ansi2knr.c
cmpt.c
connect.c
convert.c
...

Процесс замены шаблона на список соответствующих этому шаблону файлов называется глоббингом (globbing) или просто подстановкой. Обычно оболочки имеют набор операторов (метасимволов) для осуществления глоббинга, так называемых глобов (globs):
- глоб * соответствует любому набору символов, включая пустое множество.
- глоб ? соответствует любому одному символу.
- глоб [] соответствует любому одному символу из числа находящихся внутри этих квадратных скобок. Также внутри скобок вы можете задать некоторый диапазон символов. Для этого нужно использовать знак минус (-). [a-z] будет соответствовать любой букве английского алфавита в нижнем регистре.

Z shell имеет несколько уникальных глобов, о которых рассказано во врезке ниже.

===== врезка: глобы Z shell =====
Глоб **/ соответствует списку всех директорий ниже текущей и включает текущую директорию. Если мы вернемся в каталог с текстами wget, то найти все файлы по имени Makefile можно так:

$ echo **/Makefile
Makefile doc/Makefile po/Makefile
src/Makefile util/Makefile
windows/Makefile

Если вы не хотите включать текущую директорию в список обработки, попробуйте так:

$ echo */**/Makefile
doc/Makefile po/Makefile
src/Makefile util/Makefile
windows/Makefile

Ещё один удобный глоб позволяет задавать соответствие типа файла:
*(.) - обычные файлы
*(/) - директории
*(*) - исполняемые файлы
*(@) - символьные ссылки

$ ls -d -F *(/)
ChangeLog-branches/ doc/ po/ src/ util/ windows/

Z shell умудрился придумать сокращение даже для глоба (/). Вы можете заменять это выражение на единственный слеш:

$ ls -d -F */
ChangeLog-branches/ doc/ po/ src/ util/ windows/
===== конец врезки =====

Глобы в командной строке могут при необходимости повторяться. Несколько дополнительных примеров приведено в листинге ниже:

1) $ ls -1 -a -F
./libs
ChangeLog
ChangeLog-branches/
Makefile
Makefile.in
alloca.c
ansi2knr.c
cmpt.c
cmpt.o
config.h
config.h.in
connect.c
connect.h
connect.o
convert.c
convert.h
convert.o
...
wget*

2) $ ls -a -F .*
./lib

3) $ ls -1 *.?
alloca.c
ansi2knr.c
cmpt.c
cmpt.o
config.h
connect.c
connect.h
connect.o
convert.c
convert.h
convert.o
...

4) $ ls -1 ????.?
cmpt.c
cmpt.o

5) $ ls [a-c]?*.*
alloca.c
ansi2knr.c
cmpt.c
cmpt.o
config.h
config.h.in
connect.c
connect.h
connect.o
convert.c
convert.h
convert.o
cookies.c
cookies.h
cookies.o

Первая команда показывает все файлы в директории, включая скрытые, т.е. те чьи имена начинаются с точки (опция -a). Список выводится в одну колонку (опция -1). Директории отмечаются слешем в конце имени, а исполнимые файлы - звёздочкой (опция -F).

Вторая команда ищет файлы, чьё имя начинается с точки (.*).

Третья команда находит файлы, имеющие однобуквенное расширение имени.

Четвёртая команда отыскивает файлы, чьё имя состоит из четырёх символов, точки и ещё одного символа.

И, наконец, пятая команда ищет файлы, чьё имя начинается на a, b или c, затем должен быть по крайней мере один символ (или больше), затем точка и любое расширение.

Как вы могли видеть, комбинации из нескольких глобов способны на многое.

А что произойдёт, если выполнить "ls *.z" (в предположении, что таких файлов в директории нет)? Вы увидите весьма полезное сообщение об ошибке:

$ ls *.z
zsh: no matches found: *.z

Урок истории (команд)

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

Работа с историей в Z shell настраивается так:

$ HISTSIZE=500
$ SAVEHIST=500

Эти переменные окружения определяют, что и сама оболочка и файл должны содержать не более 500 последних команд.

После того как вы некоторое время поработаете в оболочке, наберите history:

$ history
...
781 /bin/ls -d */
782 /bin/ls -F *(/)
783 /bin/ls -d -F *(/)
784 /bin/ls -d -F */
785 /bin/ls -d */

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

$ !785
ChangeLog-branches/ doc/ po/ src/ util/ windows/

Если же вам понадобилась не вся команда, а только какой-либо из аргументов, можно добавить к предыдущей записи двоеточие, после которого указать номер аргумента. При этом 0 ссылается на имя команды, 1 - на первый аргумент и т.д. Ниже приведены несколько примеров работы с историей:

$ echo !782:2
echo *(/)
ChangeLog-branches doc po src util windows

$ ls AUTHORS COPYING INSTALL MACHINES
AUTHORS COPYING INSTALL MACHINES

$ echo !!:3
echo INSTALL

$ history -2
788 ls AUTHORS COPYING INSTALL MACHINES
789 echo INSTALL

$ echo !788^
echo AUTHORS
AUTHORS

$ echo !788$
echo MACHINES
MACHINES

Команда "history -2" печатает две последние выполненные команды. Символы каретки (^) и доллара ($) используются для ссылки на первый и последний аргументы команды соответственно. Можно сослаться сразу на некоторый диапазон аргументов, например как здесь:

$ echo AUTHORS COPYING INSTALL MACHINES
AUTHORS COPYING INSTALL MACHINES
$ echo !!:1-2
echo AUTHORS COPYING
AUTHORS COPYING

Есть ещё один, достаточно эффективный путь вызова команды из истории:

$ ls I*
$ ls M*
$ echo !?M
echo ls M*

Конструкция !?M производит поиск по истории и перевыполняет последнюю команду, в которой нашлась заглавная буква M.

Переменные окружения

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

Некоторые переменные окружения, такие как $SAVEHIST, оказывают влияние только на саму оболочку.

Другие, которые называются экспортируемыми, действуют глобально, т.е. копируются в пространство процесса (окружения) каждой программы, которую вы запускаете из оболочки. Например, в переменной $HOME записан путь к домашней директории текущего пользователя. Эта переменная устанавливается в процессе регистрации (login) пользователя в системе. Впоследствии, оболочка, будучи запущенной использует эту переменную для поиска своих файлов настроек. Другие приложения также обращаются к ней, SSH и FTP -- чтобы найти файл .netrc, в котором хранятся пароли для удалённог доступа. Такие переменные как $HOME, $PATH и $SHELL могут быть использованы всеми программами. Другие могут иметь смысл только для отдельных приложений.

Для ознакомления со всеми вашими переменными окружения напечатайте printenv. Вы должны увидеть что-то похожее на это:

$ printenv
PATH=/Users/strike/bin:/Applications/xampp/xamppfiles/bin:/Users/strike/bin:/usr/bin:/
bin:/usr/sbin:/sbin
HOME=/Users/strike
SHELL=/bin/zsh
USER=strike
TERM=xterm-color
LOGNAME=strike
SHLVL=1
PWD=/Local/src/versions/wget/wget-1.9
OLDPWD=/Local/src/versions/wget/wget-1.9/src
PERL5LIB=/Applications/xampp/xamppfiles/lib/perl5/site_perl/5.8.7:/Projects/IGSP/src
CLICOLOR=true
MANPATH=/Local/root/share/man:/usr/share/man:/opt/local/share/man
INFOPATH=/opt/local/share/info
LESS=-n

Скорее всего, вы узнаете большинство из переменных, но некоторые окажутся незнакомыми. $SHLVL (shell levev, уровень оболочки) показывает как глубоко вы погрузились, запуская одну оболочку из другой. 1 соответствует оболочке входа в систему. Вы можете использовать это значение, чтобы изменять вид приглашения командной строки для каждой новой вложенной оболочки. $TERM отражает тип вашего терминала, что важно для правильного отображения текста, цветов и реакции на различные комбинации клавиш. $PWD содержит имя текущей рабочей директории, а $OLDPWD -- имя предыдущей рабочей директории. Эти переменные можно использовать для быстрого перемещения по директориям как показано ниже:

$ echo $PWD
/Users/strike

$ echo $OLDPWD
/Local/src/versions/wget/wget-1.9

$ cd $OLDPWD

$ echo $PWD
/Local/src/versions/wget/wget-1.9

$ echo $OLDPWD
/Users/strike

Остальные переменные относятся к отдельным приложениям. $PERL5LIB содержит пути, где Perl должен искать дополнительные библиотеки. Команда ls использует переменную $CLICOLOR для раскрашивания файлов в соответствии с их типом и расширением. Такие переменные обычно документируются в руководствах, посвященных программам, которые их используют.

Переменные окружения определяются также как и переменные оболочки, но для того чтобы они стали доступны другим приложениям, их надо экспортировать:

$ MYVARIABLE=$HOME/projectX
$ export TMPDIR=/tmp/projectX

Первая из команд задаёт переменную $MYVARIABLE. При присвоении переменной значения знак доллара перед именем не ставится, но в дальнейшем при использовании переменной для получения значения, он обязателен. $MYVARIABLE видима только оболочке, поскольку мы её не экспортировали. Для вывода списка переменных оболочки используется команда set. Её вывод будет включать и переменные окружения, видимые внешним программам, поскольку оболочке они тоже видны.

Вторая команда определяет и экспортирует переменнную $TMPDIR. Одно из многих приложений, использующих эту переменную -- компилятор GCC. По пути, который мы записали в $TMPDIR, GCC будет создавать свои временные файлы.

Если вам потребуется удалить какую-либо из переменных окружения, воспользуйтесь командой unset:

$ set
HOME=/Users/strike
MYVARIABLE=/Users/strike/projectX
TMPDIR=/tmp/projectX
...

$ unset MYVARIABLE TMPDIR

$ set
HOME=/Users/strike
....

Псевдонимы и файлы запуска

Файлы запуска перечитываются оболочкой всякий раз, как она стартует. Это идеальное место для хранения всех настроек: пременных оболочки, пременных окружения и псевдонимов.

Псевдоним -- это достаточно короткая последовательность символов, используемая вами для представления более длинной и сложной команды. Вместо того, чтобы раз за разом набирать:

$ find /home/joe -type f -name '*.txt' -print | xargs grep -l "Monthly Report"

вы можете создать псевдоним и набирать:

$ findreports

Оболочка сделает за вас всю тяжелую работу, заменив короткую команду на длинную. Для создания псевдонима findreports, введите:

alias findreports='find $HOME -type f -name "*.txt" -print | xargs grep -l "Monthly Report"'

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

$ alias ll='/bin/ls -l'
$ ll -d 2002*
drwxrwxr-x 2 www-data www-data 4096 Jan 16 2002 2002-02
drwxrwxr-x 2 www-data www-data 4096 Jan 22 2002 2002-03
drwxrwxr-x 2 www-data www-data 4096 Apr 15 2002 2002-04
drwxrwxr-x 2 www-data www-data 4096 Apr 19 2002 2002-05
...

$ alias lt='ll -t'
$ lt -d 2002*
drwxrwxr-x 2 www-data www-data 4096 Apr 19 2002 2002-05
drwxrwxr-x 2 www-data www-data 4096 Apr 15 2002 2002-04
drwxrwxr-x 2 www-data www-data 4096 Jan 22 2002 2002-03
drwxrwxr-x 2 www-data www-data 4096 Jan 16 2002 2002-02

$ alias m='pinky | grep mstreicher'
$ m
mstreicher Martin Streicher ...

$ alias snap='pinky >> ~/.pinky'
$ snap
$ snap
$ cat ~/.pinky
Login Name TTY Idle When Where
mstreicher Martin Streicher pts/0 Jun 18 16:40 cpe-071-065-224-025.nc.res.rr.com
Login Name TTY Idle When Where
mstreicher Martin Streicher pts/0 Jun 18 16:40 cpe-071-065-224-025.nc.res.rr.com

Псевдоним ll ссылается на /bin/ls, использование абсолютного пути предохраняет от возможных подстановок.

Когда вы ввели ll, это слово было заменено псевдонимом и остаток строки был добавлен к команде. Т.о. "ll -d 2002*" превратилась в "/bin/ls -l -d 2002*". Псевдоним lt ссылается на ll и добавляет к этой команде флаг -t для сортировки файлов по времени последнего изменения. Вызов lt превращается в "/bin/ls -l -t -d 2002*".

Псевдоним m использует пайп. Псевдоним snap использует двойную воронку для дописывания вывода команды к содержимому файла.

Чтобы посмотреть, какие псевдонимы уже определены в вашей оболочке, введите alias (без параметров):

$ alias
alias findreports='find $HOME -type f -name "*.txt" -print | xargs grep -l
"Monthly Report"'
alias ll='/bin/ls -l'
alias lt='ll -t'
alias m='pinky | grep mstreicher'
alias snap='pinky >> ~/.pinky'
...

Если требуется удалить некий псевдоним, используйте unalias. Причём, псевдонимы можно удалять списками:

$ unalias m snap
$ alias
alias findreports='find $HOME -type f -name "*.txt" -print | xargs grep -l
"Monthly Report"'
alias ll='/bin/ls -l'
alias lt='ll -t'

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

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

Z shell читает настройки из .zshrc и .zprofile, в вашей домашней директории. Файл .zshrc обрабатывается каждый раз, когда оболочка стартует. А вот .zprofile считывается только в случае старта оболочки входа в систему (login shell).

После того как вы настроили оболочку, сохраните настройки:

$ set >> $HOME/.zshrc
$ alias >> $HOME/.zshrc

Возможно, вам захочется подредактировать полученный файл, удалив переменные специфичные для текущей сессии.

эффективная работа zsh shell

Previous post Next post
Up