Terminal: полезные трюки
https://t.me/nuancesprogЗадача статьи — показать тебе, как использовать консоль на всю катушку, добавить +50 к скорости ввода команд и +100 к эффективности. Она не научит, как объединять команды в пайпы и перенаправлять ввод-вывод или писать скрипты и функции.
Мигрируем на ZSH
Первое, что стоит сделать перед началом прокачки скиллов, — это избавиться от bash. Не потому, что он плохой или устаревший, а потому, что существует ZSH. Он неиллюзорно повысит твою продуктивность.
ZSH — очень сложный и комплексный командный интерпретатор. Полное руководство ZSH насчитывает около 800 страниц, а абсолютно все его функции, наверное, не знает никто. Но этого ни от кого и не требуют. На свете уже несколько лет существует проект oh-my-zsh, где пользователи создают набор скриптов, с помощью которых можно твикать и настраивать ZSH быстро и легко.
Чтобы получить стандартный набор твиков и настроек, включая мощный механизм автодополнения, информативное приглашение к вводу команды, настройки, повышающие удобство работы с ZSH, достаточно просто установить oh-my-zsh. Далее его можно обвешать плагинами для большего удобства работы с разными приложениями и поменять тему приглашения на любую из десятков, созданных пользователями.
Итак, для начала устанавливаем ZSH:
$ sudo apt-get install zsh
А затем скачиваем и устанавливаем oh-my-zsh:
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
Скрипт установки клонирует git-репозиторий в каталог /home/username/.oh-my-zsh
, добавит необходимые правки для вызова нужных скриптов в конфиг /home/username/.zshrc
и запустит ZSH.
Теперь необходимо сделать ZSH шеллом по умолчанию:
$ sudo usermod -s /usr/bin/zsh имя_юзера
И перелогиниться, чтобы эмулятор терминала использовал ZSH в качестве дефолтового шелла. В качестве опционального шага ты можешь изменить тему. В комплект oh-my-zsh входит огромное количество тем, ознакомиться с которыми можно на wiki-странице. Чтобы выбрать новую тему, исправь значение переменной ZSH_THEME в файле ~/.zshrc. Выберем, например, тему agnoster:
ZSH_THEME="agnoster"
Перемещаемся по каталогам быстро
Одна из главных проблем консоли состоит в том, что ее неудобно использовать для перемещения по каталогам. Особенно если вложенных каталогов много, они имеют длинные имена, а еще хуже — похожие имена. В этом случае система автодополнения с помощью кнопки Tab помогает плохо и все, что остается, — это печатать имена каталогов руками.
ZSH упрощает навигацию. Во-первых, он умеет исправлять регистр букв, поэтому ты можешь начать печатать нечто вроде
$ cd ~/do
Затем нажать Tab и получить это:
$ cd ~/Downloads
Во-вторых, система автодополнения имен каталогов ZSH намного развитее своего аналога из bash. Если ZSH обнаружит, что с введенных тобой символов начинаются имена сразу нескольких каталогов, он не будет пищать, а затем выводить список каталогов, заставляя тебя уточнять запрос, а сразу выведет список и позволит выбрать нужный каталог с помощью Tab или стрелок.
В-третьих, автодополнение работает не только для начала имени каталога/файла, но и для любой его части. Чтобы перейти в каталог ~/Downloads, ты можешь набрать load и нажать Tab.
Наконец, в-четвертых, ZSH умеет дополнять имена каталогов по всему пути, а не только в последней его части. Это значит, что ты можешь напечатать нечто вроде этого:
$ cd /u/s/zs
Затем нажать Tab и получить это:
$ cd /usr/share/zsh
Более того, тебе совсем не обязательно печатать даже первые буквы имен каталогов. ZSH и bash умеют находить нужные каталоги самостоятельно, если они перечислены в переменной CDPATH. Добавь, например, следующую строку в ~/.zshrc:
export CDPATH=/var/www:/home/имя_юзера/Dropbox
Теперь, чтобы открыть каталог ~/Dropbox/Books, можно использовать такую команду:
$ cd Books
ZSH проверит, есть ли каталог Books в /var/www или /home/имя_юзера/Dropbox, и переместит тебя в него, если он существует.
Fasd
Есть и гораздо более мощное средство для перемещения между каталогами. Это утилита fasd (произносится как fast — быстрый). Она запоминает все каталоги (и просто пути к файлам), которые ты использовал, и позволяет перемещаться между ними, указав лишь часть пути (даже несколько букв).
Работает это так. Допустим, ранее ты переходил в каталог ~/src/projects/apps/myCoolApp и теперь, спустя часы или даже дни, хочешь в него вернуться. Все, что тебе необходимо сделать, — это выполнить такую команду:
$ z myCoolApp
Можно проще:
$ z CoolApp
И еще проще:
$ z Cool
Требование одно: указанный тобой набор символов должен быть уникальным среди всех путей, которые запомнил fasd. Кроме z, fasd поддерживает и другие шорткаты: a — показывает все сохраненные пути, zz — позволяет перейти в каталог, используя интерактивное меню (если введенный набор символов встречается в нескольких путях), v — открывает файл в редакторе Vim.
Утилита fasd доступна для Debian/Ubuntu, Arch Linux через AUR и для macOS через brew. Установить в Ubuntu можно так:
$ sudo add-apt-repository ppa:aacebedo/fasd $ sudo apt-get update $ sudo apt-get install fasd
Далее необходимо активировать плагин fasd в ~/.zshrc:
plugins=(git fasd)
Peco
Peco — еще один инструмент, способный сильно облегчить навигацию, а также поиск. Это небольшая утилита, которая принимает на вход список строк и выводит на экран псевдографическое меню, с помощью которого можно выбрать или найти нужную строку. Далее peco отдает эту строку на выход и завершает свою работу (по сути, это консольный аналог dmenu).
Peco можно использовать для навигации и поиска в любых текстовых строках, включая пути. Например, если ты запустишь следующую команду и выберешь каталог, peco напечатает его имя в терминале:
$ ls | peco
Не слишком удобно и полезно. Однако, немного усложнив пример, ты получишь интерактивный cd:
$ cd `ls | peco`
Польза появилась, удобство пострадало. Поэтому создадим для этой команды короткий и простой псевдоним. Для этого добавим следующую строку в ~/.zshrc:
alias cdi='cd `ls | peco`'
Теперь команда cdi будет запускать наш интерактивный cd.
Кстати, о самом cd. Запомни два простых правила:
- команда cd без аргументов отправит тебя в домашний каталог;
- команда cd — вернет в предыдущий каталог.
Используем автодополнение на полную катушку
Система автодополнения ZSH интересна не только своими интеллектуальными функциями, но и тем, что она работает не с одними именами каталогов и файлов. ZSH умеет дополнять флаги и опции многих утилит и выводить удобную справку по ним, умеет дополнять названия пакетов apt-get, yum, pacman и других пакетных менеджеров, дополняет имена хостов при подключении по SSH. Если набрать kill и нажать кнопку Tab, ZSH выведет список процессов. После второго нажатия Tab список станет интерактивным, и ты сможешь выбрать процесс, который следует умертвить.
Кроме встроенных правил автодополнения, on-my-zsh имеет множество плагинов с правилами автодополнения для многих утилит и приложений.
Работаем с историей команд
Любой современный командный интерпретатор, будь то ZSH или bash, сохраняет историю введенных команд. ZSH хранит историю в файле /home/username/.zsh_history
. При необходимости его можно погрепать (grep ls ~/.zsh_history
), чтобы найти нужную команду. Но делать это совсем не обязательно, ведь командный интерпретатор уже имеет в своем арсенале набор средств для работы с историей.
Например, следующая команда вставит в строку ввода предыдущую команду:
$ !!
Ее особенно удобно использовать, если забыл указать sudo перед командой, требующей права root:
$ pacman -Syu error: you cannot perform this operation unless you are root. $ sudo !! sudo pacman -Syu
Можно взять из истории только аргумент команды. Например:
$ cd /home/user/foo cd: /home/user/foo: No such file or directory $ mkdir !* mkdir /home/user/foo
А так можно вставить в строку ввода последнюю команду, начинающуюся с указанных символов:
$ !qwerty
Если же нужно найти команду с указанными символами где-то в середине или в конце, можно сделать так:
$ !?qwerty?
Ты можешь даже исправлять описки в последней введенной команде:
$ ^dc^cd
С помощью комбинации Ctrl + R команды можно искать в интерактивном режиме. Просто начни вбивать символы, присутствующие в команде, и ZSH вставит в строку ввода нужную команду. Это очень удобная функция, но ее можно сделать еще удобнее, если использовать возможности уже знакомого нам peco.
В Сети можно найти сторонний плагин для oh-my-zsh под названием zsh-peco-history. Просто скачай его в каталог сторонних плагинов ZSH:
$ git clone https://github.com/jimeh/zsh-peco-history.git $ZSH_CUSTOM/plugins/zsh-peco-history
И активируй в ~/.zshrc:
plugins=(git fasd zsh-peco-history)
Теперь комбинация Ctrl + R будет запускать полноэкранное меню peco вместо однострочной поисковой строки.
Копируем, удаляем, переименовываем
Казалось бы, что может быть проще, чем скопировать или переименовать файл? Просто вбиваешь команду cp или mv, а затем старое и новое имена:
$ cp httpd.conf httpd.conf.bak
Но зачем утруждать себя, нажимая лишние кнопки, если можно сделать так:
$ cp httpd.conf{,.bak}
Строка, содержащая фигурные скобки с двумя строками, разделенными запятой, будет развернута в две строки, в одной из которых будут символы до запятой, а в другой — символы после.
Можно пойти дальше и использовать не просто замену строк, а регулярные выражения. Для этого нам понадобится команда rename:
$ rename 's/регулярка/на_что_заменить/' *.txt
Такая команда заменит все подстроки, подпадающие под регулярное выражение, в именах всех файлов с расширением .txt. Недурно, не правда ли?
Также стоит изучить команду basename. При обычном использовании она просто выводит последний элемент пути:
$ basename /usr/bin/zsh zsh
Но также ее можно использовать для отрезания частей строки, например:
$ basename file.txt .txt file
Ты можешь спросить, что это дает? А вот что:
$ for file in *.png; do convert "$file" "`basename "$file" .png`.jpg" ; done;
Это перекодировщик всех файлов PNG в JPG. Команда крайне проста: мы создаем цикл, который проходится по всем файлам PNG в текущем каталоге, затем запускает команду convert для перекодировки их в JPG. Basename здесь нужен для того, чтобы дать новым файлам корректное имя. Хинт: обратные кавычки запускают заключенную в себя команду в так называемом субшелле. Они нужны для запуска одной команды из другой.
Чтобы понять их мощь, обрати внимание на следующую команду:
$ rm -f `tar ztf /path/to/file.tar.gz`
Уверен, эта команда не раз спасет тебя, когда ты распакуешь архив tar.gz не в тот каталог. Она удаляет все ранее распакованные файлы.
Ищем правильно
Ты уже должен знать, что в любой UNIX-системе есть команда find, предназначенная для поиска файлов. Использовать ее предельно просто:
$ find . -name *.c -type f
Эта команда найдет все файлы с расширением .c в текущем каталоге и во всех его подкаталогах. Но что делать, если в каждом из этих файлов необходимо найти строку open? А вот это:
$ find -name *.c -type f | xargs grep open
Можно и несколько по-другому:
$ find . -name *.c -exec grep -H open {} ;
Этот пример немного сложнее и, как ни странно, медленнее. Почему? Потому, что xargs распараллелит поиск, запустив отдельный процесс grep на каждую строку.
При желании от find можно вообще избавиться:
$ grep -R open --include="*.c".
По сути, это эквивалент предыдущей команды.
Работаем с буфером обмена
Читая эту статью, ты наверняка то и дело копировал команды и вставлял их в терминал. Если нет — значит, ты набирал их сам, что правильно, память тебя отблагодарит. В любом случае копировать и вставлять команды в терминал жутко неудобно, как, впрочем, неудобна и сама концепция копирования/вставки.
Однако в случае с терминалом у тебя есть один очень мощный инструмент. Он называется xclip и позволяет копировать и вставлять в буфер обмена. Для начала добавь в ~/.zshrc следующие строки и перезапусти терминал (или ZSH):
alias -g xcopy='xclip -selection clipboard' alias -g xpaste='xclip -selection clipboard -o'
Теперь, чтобы что-то скопировать в буфер обмена, просто перенаправь вывод в xcopy. Например:
$ uname -a | xcopy
В буфере обмена окажется вывод команды uname -a. Вставить можно таким же образом:
$ xpaste
Вывод также можно перенаправить. Или заключить xpaste в обратные кавычки, чтобы его содержимое было выполнено шеллом.
Выводы
Командная строка не просто мощный инструмент. Это настолько мощный инструмент, что мне даже трудно придумать, какой тип интерфейса ОС может быть эффективнее. То, о чем я написал, — такая крошечная часть верхушки айсберга, что для описания всех трюков командной строки потребовалась бы серия книг, сродни «Большой советской энциклопедии». Ну а напоследок то, чего все так долго ждали, — dd с показом прогресса:
$ pv -tpreb /dev/sdb | dd of=~/sdb.img bs=1M