Алексей Федорчук
Извлечение ранее введённых команд из их «истории» — ещё один способ минимизации набора символов при работе в CLI (наряду с ранее рассмотренными hподстановками и автоматическим дополнением). И эта возможность существует по всех современных командных оболочках (кроме, разве что, кондового POSIX Shell, эмулируемого обычно командой /bin/sh
). Однако и тут Zsh некогда выделился дополнительными функциями (правда, ныне реализованными и в Bash, хотя там они включаются несколько иным способом).
Для начала — несколько общих слов. Всем известно, что команды в истории оных можно последовательно просматривать, нажимая клавиши Up (назад) и Dowm (вперёд). А найдя там нужную — отправить её на исполнение нажатием клавиши Enter. При необходимости предварительно отредактировав опции и (или) аргументы. Однако это может быть занятием достаточно нудным, потому что нужно учитывать следующее.
История команд, доступная для «перебора клавишами», сохраняется в Zsh как бы дважды. Во-первых, в буфере текущего сеанса шелла, запущенного в данном терминальном окне, его вкладке (если эмулятор терминала таковые поддерживает) или в текущей виртуальной консоли (впрочем, о специфике CLI в «голой» консоли речь будет отдельная).
А во-вторых, история команд записывается в специальный dot-файл домашнего каталога пользователя — в Cintu таковым является ~/.zhistfile
. Причём в ней Zsh настроен таким образом, что вновь введённая команда попадает в файл истории сразу, а не по завершении текущего сеанса. То есть она будет последней в списке команд следующего сеанса, при открытии нового терминального окна или вкладки в существующий.
Так что при высоком лимите на количество строк в буфере сеанса и в файле истории (а в Cintu лимит этот — 2000 и 10000 строк, соответственно), перебор команд может потребовать немало времени. Конечно, файл ~/.zhistfile
можно просто просмотреть, например, командой less
, дабы найти нужную, в том числе и с применением фильра типа grep
. Однако и это не намного легче. Даже с учётом того, что в файл истории, в соответствие с принятыми в Cintu настройками Zsh, не попадают дубликаты команд и пустые строки.
Кстати, пока не забыл: предотвратить попадание команды в историю, если это почему-либо не желательно (например, её аргумент содержит учётные данные доступа ftp-серверу), можно, введя пробел перед именем команды. Однако в буфере текущего сеанса она всё равно сохранится до конца оного, и будет доступна для «перебора» — причём именно в такой, «историко-недоступной», форме. Эта функция оказывается неоценимой на финальной стадии подготовки образов в Sytemback. Когда, казалось бы, всё уже сделано и файл истории уничтожен (дабы не «светить кухню»). Но, как обычно бывает (по крайней мере, у меня), пара мелочей, требующих выполнения команд, оказалась забытой.
Думаю, ни для кого не секрет также, что для вызова списка команд предназначена специальная команда history
. Однако в данном случае следует учитывать, что это — встроенная команда оболочки, зависит от последней, а потому её возможности в Bash и в Zsh различаются. И редкий случай — не в пользу последней, поскольку в Bash её функционал обеспечивается библиотекой GNU History Library, в Zsh не задействованной.
Впрочем, потеря не велика — команда history
в её Bash-модификации никогда не казалась мне очень удобной. Тем более что в Zsh есть замечательный механизм history-substring-search
— поиска в истории по начальной последовательности символов.
Что это такое — проще пояснить на примере: вы вводите в командной строке один символ (для примера — s
) и нажимаете клавишу Up. И тут в дальнейший «перебор» включаются только те команды из истории, которые с буковки s
начинаются. Вводя дополнительные символы, можно сузить круг поиска: например, последовательность sudo
позволяет просмотреть, что мы наколбасили от лица суперпользователя вообще. А если добавить ещё и apt
, легко вспомнить, что было наустановлено или наудалено ранее.
Кроме того для облегчения процедуры поиска предусмотрена такая интересная возможность, как наращиваемый поиск (incremental search). Выполняется он так: после нажатия (при пустой командной строке) клавишной комбинации Control+R появляется предложение ввести алфавитный символ (или — последовательность символов произвольной длины), заведомо входящий в состав требуемой команды:
$ bck-i-search: _
Ввод такого символа выведет последнюю из команд, его содержащих. При этом введённый символ будет отмечен знаком курсора. Он не обязан входить в имя команды, но может быть составляющим её опций или аргументов (имени файла или пути к нему, например). Следующее нажатие Control+R зафиксирует курсор на предыдущем символе, в пределах этой же или более ранней по списку команды, и т.д. Однако вместо этого в строке поиска можно вводить дополнительные символы, детализирующие условия поиска команды (или — её опций и аргументов).
Процедуру поиска можно продолжать вплоть до достижения требуемого результата — то есть нахождения той команды, которая нужна именно сейчас. Нажатие клавиши Enter в любой из этих моментов запускает найденную (то есть помещенную в командную строку) команду на исполнение, с завершением поиска. Поиск обрывается также и нажатием комбинации Control+C. Перед запуском найденная команда может быть отредактирована стандартными средствами — с использованием управляющих последовательностей.
Перебор через history-substring-search
и инкрементный поиск по Control+R отнюдь не исключают друг друга, а дополняют: первым способом проще искать ранее введённые директивы по имени команды, вторым — по её аргументам, например, по имени файла.
И ещё, и инкрементный поиск, и history-substring-search
имеется как в Zsh, так и в Bash. И в обоих оболочках первая функция работает по умолчанию, а вторая должна быть включена в конфигурационных файлах, причём по разному. Как это делается в Zsh — расскажу под занавес, а в Bash — описано, например, здесь. Ну и справедливости ради стоит заметить, что функция history-substring-search
впервые появилась в оболочке Tcsh, где она, как правило, включена по умолчанию.