Настройка и работа в Linux
adb5321d

Работаем с историей команд Часть 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. Вместо этого были выведены результаты подстановки.

Вот в общих чертах и все. Что я имел сказать - я сказал.

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


Содержание раздела