Работаем с историей команд. Часть I. Основы.
Как известно, лень человеческая - помимо слабости, является одним из основных двигателей прогресса. Не чужды ей и простые смертные линуксоиды и юниксоиды вместе взятые. Итак, как помочь человеку попавшему в дебри командного интерпретатора и облегчить его труд и усилить во сто крат силу его? Ответ на сей вопрос прост - надо дать ему в руки, и научить пользоваться таким полезным инструментом, как история команд. Сей инструмент в той или иной мере присутствует во многих программах и системах. В том же многострадальном MS-DOS, было жалкое подобие истории введенных команд, история также присутствовала в NC, FAR и других командных оболочках. Но там они ни в какое сравнение не идут с возможностями присутствующими в любом мало мальски распространенном shell под linux или unix. Далее я буду описывать работу c bash, хотя на сколько мне известно tcsh, csh и некоторые другие интерпретаторы имеют сходный набор команд для работы с историей.
Итак начав работу с командной строкой bash, я обнаружил что с помощью клавиш перемещения курсора можно перемещаться по списку ранее введенных команд. Так когда мне нужна была некоторая команда из ранее введенных я жал клавишу „стрелка вверх“ до тех пор пока нужная мне не появлялась в командной строке, потом я ее корректировал нужным мне образом и жал „Enter“ для ее выполнения. Это конечно значительно экономило время однако, как оказалось, не было наиболее эффективным способом работы. Итак, все по порядку. Для просмотра списка ранее введенных команд в bash - имеется команда history . По умолчанию она выводит список команд хранящийся в истории. Размер данного списка определяется переменными окружения HISTSIZE - размер списка хранящегося в памяти интерпретатора, а HISTFILESIZE - максимальное количество команд хранящихся в файле истории. По умолчанию этоn файл ~/.bash_history , а его размер - 500 команд. Если вы желаете хранить историю в другом файле, то нужно в .bashrc, задать команду - HISTFILE=~/.vasya_history . Я для себя переопределяю только размер списка команд и размер файла истории, устанавливая их значения в 1000 команд. Итак введя:
$ history
1 history | less
2 hg test
3 test 333
4 lynx www.yahoo.com
5 cat /etc/profile.d/colorls.sh
6 vim .screen
7 vim .screenrc
..........................
305 man bash
306 man vfork
307 hg lynx
308 cd txt/everyday/
309 vim history.txt
310 histroy
Отсюда видно, что в истории на данный момент находится 310 команд, конечно они все на экране не поместятся, посему если вам надо только последние 20 команд, то можно набрать:
$ history 20
295 vim lib/advhist.sh
296 getpg
297 vim .bash_logout
298 vim .bashrc
299 cat .lynxrc
300 vim .lynxrc
301 ls lib
302 cat .bashrc
303 getmail
304 ls
305 man bash
306 man vfork
307 hg lynx
308 cd txt/everyday/
309 vim history.txt
310 histroy
311 history
312 history
313 fg
314 history 20
Таким образом получим только последние 20 команд. Каждая команда имеет свой номер, с помощью которого к ней можно обратится. Если нам надо повторить 302 команду, то просто печатаем:
$ !302
cat .bashrc
# .bashrc
# User specific aliases and functions
if [ "$PS1" -a -f ~/lib/advhist.sh ]; then
. ~/lib/advhist.sh
fi
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
umask 066
Здесь сначала печатается команда под номером 302 - cat .bashrc , а затем результат ее выполнения. Приведу список команд для работы с историей:
-
!! - ссылается на предыдущую команду;
-
!n - ссылается на команду под номером n;
-
!-n - ссылается на команду по номером „текущая минус n“;
-
!string - ссылается на команду, начинающуюся с string;
-
!?string[?] - ссылается на команду, содержащую строку string;
-
^string1^string2[^] - „быстрая замена“, заменяет первое вхождение строки string1 в предыдущей команде, на string2, после чего выполняет полученную команду.
Приведу несколько примеров по использованию вышеприведенных команд. Я часто выполняю приблизительно следующую последовательность:
$ locate diald.conf
/etc/diald.conf
$ cat /etc/diald.conf
.......
Первой командой я нахожу требуемый файл, а второй вывожу его содержимое. Сей короткий пример можно автоматизировать следующим образом:
$ locate diald.conf
/etc/diald.conf
$ cat `!!`
cat `locate diald.conf`
mode ppp
accounting-log /tmp/dialdlog
.....
Таким образом я избегаю повторного ввода имени файла. `!!` означает - выполнить предыдущую команду и подставить ее результат в качестве параметра cat . Результирующая команда после подстановки из перечня печатается сразу за командной строкой: cat `locate diald.conf` .После чего выводится результат выполнения команды. На мой взгляд весьма удобно. Идем дальше:
$ history 10
324 hg \'
325 hg \`
326 locate diald.c
327 locate diald.conf
328 cat `locate diald.conf`
329 getmail
330 history 10
331 ls
332 ps
333 history 10
$ !328
cat `locate diald.conf`
mode ppp
accounting-log /tmp/dialdlog
..........
Данная команда выполняет 328 команду перечня. Другой способ обратится к этой же команде:
$ !-6
cat `locate diald.conf`
mode ppp
accounting-log /tmp/dialdlog
..........
Здесь используется обратная нумерация, то есть номер команды вычисляется как текущая минус 6. Следующий способ, это когда я помню что команда начиналась со строки cat , чтобы ее повторить я печатаю следующее:
$ !cat
cat `locate diald.conf`
mode ppp
accounting-log /tmp/dialdlog
..........
А если я не помню названия начала команды, но помню ее середину diald , то тогда набираем:
$ !?diald
cat `locate diald.conf`
mode ppp
accounting-log /tmp/dialdlog
..........
Следующий интересный момент касается исправления неверно введенных команд или их корректировки:
$ cta /etc/diald.conf
bash: cta: command not found
$ ^ta^at
cat /etc/diald.conf
mode ppp
accounting-log /tmp/dialdlog
...............
В результате опечатки первая команда была введена с ошибкой, вместо cat , было введено cta , естественно интерпретатор не нашел такой команды, о чем и вывел предупреждение. Вторая команда ^ta^at^ - исправляет ошибку, делая замену ta на at . Это намного удобнее чем вызывать предыдущую команду на экран потом подводить курсор под нужный символ, а затем редактировать команду с помощью вставки/удаления символов. Данная возможность особенно удобна при удаленной работе с telnet на медленных линиях.
До настоящего момента при вызове команд из списка, мы ссылались на команду целиком. Но частенько надо повторить не всю команду, а только ее часть. Пример:
$ cat /etc/diald.conf
mode ppp
accounting-log /tmp/dialdlog
.........
$ vim !$
Первой командой cat мы выводим содержимое файла, например для того, чтобы удостоверится что это нужный нам файл. Удостоверившись я хочу его отредактировать, для того, чтобы повторно не набирать имя файла пишу vim !$ - что после подстановки преобразуется в vim /etc/disld.conf . Кратко опишу основные операторы обращения к различным частям предыдущей команды:
-
$ - последний аргумент командной строки;
-
^ - первый аргумент командной строки;
-
0 - нулевое слово, другими словами имя команды;
-
N - N-ый аргумент командной строки;
-
x-y - аргументы с x по у командной строки;
-
-y - сокращенное обращение к 0-y;
-
* - все аргументы, синоним 1-$;
-
x* - синоним x-$, другими словами аргументы с номера x до конца строки;
-
x- - синоним x*, но не включает последний аргумент.
Перед всеми описанными операторами, кроме ^ $ * %, необходимо ставить двоеточие. Для ясности приведу несколько примеров:
$ echo 1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8
$ echo !$
echo 8
8
$ echo 1 2 3 4 5 6 7 8
$ echo !*
echo 1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8
$ echo !:3*
echo 3 4 5 6 7 8
3 4 5 6 7 8
$ echo !^
echo 3
3
$ echo !-2:-3
echo echo 3 4 5
echo 3 4 5
Я наиболее часто использую операторы !^, !$, !* - которые ссылаются на первый аргумент, на последний аргумент и на все аргументы предыдущей команды соответственно. Еще нужно упомянуть о так называемых модификаторах, подробно о них можно почитать на страницах руководства. Но об одном из них я скажу отдельно. Этот заслуживающий внимания модификатор - :p . Он говорит интерпретатору о том, что полученную в результате подстановки команду не надо выполнять, а только напечатать. Например:
$ echo 1 2 3 4 5 6 7
$ !!
echo 1 2 3 4 5 6 7
1 2 3 4 5 6 7
$ !!:p
echo 1 2 3 4 5 6 7
$ echo !-2:p
echo echo 1 2 3 4 5 6 7
$
Как можно заметить - последняя и предпоследняя команды echo, не были выполнены, так как использовался модификатор :p . Вместо этого были выведены результаты подстановки.
Вот в общих чертах и все. Что я имел сказать - я сказал.
Еще хочу предложить вашему вниманию, парочку небольших скриптов облегчающих работу с историей, написанных мной на досуге, так сказать, для тренировки с одной стороны, и для удобства, с другой. Их описание можно найти на следующей странице, а сами сценарии на странице Программки.
|