Работаем с историей команд. Часть I. Основы.Как известно, лень человеческая - помимо слабости, является одним из основных двигателей прогресса. Не чужды ей и простые смертные линуксоиды и юниксоиды вместе взятые. Итак, как помочь человеку попавшему в дебри командного интерпретатора и облегчить его труд и усилить во сто крат силу его? Ответ на сей вопрос прост - надо дать ему в руки, и научить пользоваться таким полезным инструментом, как история команд. Сей инструмент в той или иной мере присутствует во многих программах и системах. В том же многострадальном MS-DOS, было жалкое подобие истории введенных команд, история также присутствовала в NC, FAR и других командных оболочках. Но там они ни в какое сравнение не идут с возможностями присутствующими в любом мало мальски распространенном shell под linux или unix. Далее я буду описывать работу c bash, хотя на сколько мне известно tcsh, csh и некоторые другие интерпретаторы имеют сходный набор команд для работы с историей. Итак начав работу с командной строкой bash, я обнаружил что с помощью клавиш перемещения курсора можно перемещаться по списку ранее введенных команд. Так когда мне нужна была некоторая команда из ранее введенных я жал клавишу „стрелка вверх“ до тех пор пока нужная мне не появлялась в командной строке, потом я ее корректировал нужным мне образом и жал „Enter“ для ее выполнения. Это конечно значительно экономило время однако, как оказалось, не было наиболее эффективным способом работы. Итак, все по порядку. Для просмотра списка ранее введенных команд в bash - имеется команда . По умолчанию
она выводит список команд хранящийся в истории. Размер данного списка
определяется переменными окружения
- размер списка
хранящегося в памяти интерпретатора, а
- максимальное
количество команд хранящихся в файле истории. По умолчанию этоn файл
, а его размер -
500 команд. Если вы желаете хранить историю в другом файле, то нужно в
.bashrc, задать команду -
. Я
для себя переопределяю только размер списка команд и размер файла истории,
устанавливая их значения в 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 -
$ 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 ..... Таким образом я избегаю повторного ввода имени файла.
$ 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 `locate diald.conf` mode ppp accounting-log /tmp/dialdlog ..........А если я не помню названия начала команды, но помню ее середину , то тогда набираем: $ !?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 /etc/diald.conf mode ppp accounting-log /tmp/dialdlog ......... $ vim !$Первой командой мы
выводим содержимое файла, например для того, чтобы удостоверится что это
нужный нам файл. Удостоверившись я хочу его отредактировать, для того,
чтобы повторно не набирать имя файла пишу
- что после
подстановки преобразуется в
.
Кратко опишу основные операторы обращения к различным частям предыдущей
команды:
Перед всеми описанными операторами, кроме ^ $ * %, необходимо ставить двоеточие. Для ясности приведу несколько примеров:$ 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 Я наиболее часто использую операторы !^, !$, !* - которые ссылаются на первый аргумент, на последний аргумент и на все аргументы предыдущей команды соответственно. Еще нужно упомянуть о так называемых модификаторах, подробно о них можно почитать на страницах руководства. Но об одном из них я скажу отдельно. Этот заслуживающий внимания модификатор - . Он говорит интерпретатору
о том, что полученную в результате подстановки команду не надо выполнять,
а только напечатать. Например: $ 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, не были выполнены, так как использовался модификатор . Вместо этого были выведены
результаты подстановки.
Вот в общих чертах и все. Что я имел сказать - я сказал. Еще хочу предложить вашему вниманию, парочку небольших скриптов облегчающих работу с историей, написанных мной на досуге, так сказать, для тренировки с одной стороны, и для удобства, с другой. Их описание можно найти на следующей странице, а сами сценарии на странице Программки. |
Работаем с историей команд. Часть II. Усовершенствования.Разбираясь с функционированием перечня ранее введенных команд, я обнаружил что перечень обладает несколькими отрицательными свойствами. Так при вводе одной и той же команды, она каждый раз оседает в истории. Пример:$ echo 1 1 $ echo 1 1 $ echo 1 1 $ history 5 26 PS1='$ ' 27 echo 1 28 echo 1 29 echo 1 30 history 5Как видно команда
была три раза введена и три раза была записана в историю. Для чего не
понятно. Это можно устранить вставив строку
в ваш
файл .
Вышеприведенный пример будет выглядеть следующим образом: $ HISTCONTROL=ignoredups $ echo 1 1 $ echo 1 1 $ echo 1 1 $ echo 1 1 $ history 4 42 history 4 43 HISTCONTROL=ignoredups 44 echo 1 45 history 4Как видно теперь повторяющаяся четыре раза команда , в перечне встречается
только один раз. Но вот от следующей неприятности вышеприведенная опция не
спасет: $ echo 1 1 $ echo 2 2 $ echo 1 1 $ history 5 51 history 6 52 echo 1 53 echo 2 54 echo 1 55 history 5Здесь команда ,
включена опять-таки два раза, что на мой взгляд, весьма неприятно.
Еще один неприятный момент, это то, что история засоряется короткими
командами, смысла хранить которые нет. К таким командам можно отнести
Чтобы это исправить, пришлось написать парочку небольших функций облегчающих работу с историей. Скрипт реализующий их можно найти на странице Программы. Если вкратце, то там реализованы такие функции для работы с историей:
$ hr 10 348 echo $HISTFILESIZE 9 349 vim lib/advhist.sh 8 350 ls 7 351 PS!='$ ' 6 352 PS1='$ ' 5 353 hr 4 354 ps 3 355 PS1='$ ' 2 356 who 1 357 hr $ hr 5 5 354 ps 4 355 ws 3 356 who 2 357 hr 1 358 hr 5 $ hs # Выкидывает из перечня короткие и повторяющиеся команды $ hr # Проверяем результаты 10 716 lynx sit/linux 9 717 getpg 8 718 lynx www.sit.kiev.ua/linux 7 719 echo $HISTFILE 6 720 echo $HISTSIZE 5 721 echo $HISTFILESIZE 4 722 vim lib/advhist.sh 3 723 PS!='$ ' 2 724 PS1='$ ' 1 725 hr $ hg ping # Находим все команды в которых присутствует подстрока ping 116 613 ping www.yandex 53 676 ping www.yandex.ru 1 728 hg ping $ !-53 # Выполняем найденный ping ping www.yandex.ru PING yandex.ru (62.118.249.254) from 195.230.153.157 : 56(84) bytes of data. 64 bytes from yandex.ru (62.118.249.254): icmp_seq=0 ttl=235 time=609.5 ms 64 bytes from yandex.ru (62.118.249.254): icmp_seq=1 ttl=235 time=600.0 ms ..... Замечу, что сохранение отфильтрованного перечня команд выполняется автоматически, при выходе из интерпретатора, или при обрыве связи при работе на удаленной машине. Для использования этих функций, advhist.sh должен находится в ~/lib/advhist.sh, а в ваш .bashrc, необходимо добавить следующие строки:if [ "$PS1" -a -f ~/lib/advhist.sh ]; then . ~/lib/advhist.sh fiДля настройки можно изменить следующие переменные окружения:
|