zsh
ZSH — это современная командная оболочка UNIX. Она совместима с командной оболочкой bourne shell, которую часто называют sh, по имени исполняемого файла. Лично я столкнулся с ней, когда заинтересовался небольшим удобством для себя — отображением имени ветки в репозиториях git. Одним из решением было установка оболочки zsh с набором плагинов «Oh My Zsh» от сообщества. В его составе уже сейчас больше 300 плагинов и больше 140 тем. Набор замечательный, и я пользовался им продолжительное время. Но немного напрягало, что это большой по объёму код, куда можно спрятать что угодно. Кроме этого, набор способен самостоятельно обновляться, хоть это и отключается. Внутренний параноик был против этого, поэтому я решил разобраться как можно обойтись без набора плагинов простой конфигурацией zsh, тем более, что пользовался я очень небольшой частью набора. В таком варианте это и работает быстрее.
Постановка задачи
Прежде всего, что мне необходимо от командной строки из того, что я реально использовал в «Oh My Zsh»:
- навигация по файловой системе без команды
cd
; - строка-приглашение в стиле
eastwood
: отображение текущего пути, вспомогательной информации о git репозитории; - короткие алиасы для часто используемых команд;
- короткие алиасы для часто используемых директорий;
- поиск по истории после ввода нескольких символов в командной строке (а не перебор всей истории команд).
Конфигурация по умолчанию
Для начала я очистил файл конфигурации от всех комментариев и оставил конфигурацию по умолчанию. За одно добавил опцию для удобной навигации по файловой системе, когда не нужно вводить команду cd
, а можно просто набрать имя любой папки. Бонусом, ввод имени папки не сохраняется в истории как вереница команд cd
.
autoload -Uz compinit
compinit
setopt COMPLETE_IN_WORD
setopt AUTOCD
Работа с историей команд
Далее включил историю и настроил её:
HISTFILE=$HOME/.zsh_history
setopt APPEND_HISTORY # дописывать историю в файл
setopt INC_APPEND_HISTORY # сразу записывать команду в файл
setopt HIST_IGNORE_DUPS # не сохранять дубликаты подряд
setopt HIST_IGNORE_SPACE # не сохранять команды с пробелом в начале
setopt HIST_VERIFY # подтверждать перед выполнением !history
Плагины для удобства
Из имеющихся в репозиториях плагинов в Ubuntu и Debian нашёл:
zsh-syntax-highlighting
— подсветка синтаксиса;zsh-autosuggestions
— подсказки из истории серым цветом.
Второй плагин добавляет функционал, которого у меня изначально не было, но я решил его оставить.
После установки плагинов через apt или dnf добавил их подключение. Чтобы не было ошибок в том случае, если плагины не установлены, добавил проверку их наличия перед загрузкой. Обязательно нужно обратить внимание на порядок подключения. Если поставить zsh-autosuggestions
после zsh-syntax-highlighting
, то могут возникать глюки.
if [ -f /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh ]; then
source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh
fi
if [ -f /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]; then
source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
fi
К сожалению не нашлось удобного плагина, который позволяет искать в истории аналогичные команды с помощью стрелок вверх и вниз при вводе части команды, поэтому установил его из git репозитория:
git clone https://github.com/zsh-users/zsh-history-substring-search ~/.zsh/zsh-history-substring-search
Установка производится в домашнюю папку пользователя. Подключаю плагин, предварительно проверив его наличие:
if [ -f $HOME/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh ]; then
source $HOME/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh
bindkey '^[[A' history-substring-search-up
bindkey '^[[B' history-substring-search-down
fi
Настройка строки-приглашения
Далее настроил строку-приглашения. Поддержка zsh есть непосредственно в git. Добавляем строки согласно рекомендации и настраиваю приглашение по собственному желанию. Также тут присутствует функция git_status_symbol, которая позволяет добавить в приглашение красную звёздочку если в текущей директории есть git репозиторий с изменёнными файлами, а также user_host_ssh, которая отображает имя пользователя и пароль, если пользователь зашёл в систему через ssh или переключился на другого пользователя.
git_status_symbol() {
if git rev-parse --is-inside-work-tree &> /dev/null; then
if ! git diff --quiet &> /dev/null; then
echo "%F{red}*%f"
fi
fi
}
user_host_ssh() {
if [[ -n "$SSH_CONNECTION" || -n "$SUDO_USER" ]]; then
echo '%F{red}%n@%m%f:'
fi
}
autoload -Uz vcs_info
precmd() { vcs_info }
zstyle ':vcs_info:git:*' formats '[%b]'
setopt PROMPT_SUBST
PROMPT='$(user_host_ssh)$(git_status_symbol)%F{green}${vcs_info_msg_0_}%F{cyan}[%~]%f%(#.#.$) '
Здесь в PROMPT:
%F{color}
— установка цветаcolor
для шрифта;%f
— отмена установки цвета шрифта;%n
— имя пользователя;%m
— имя текущей машины в краткой форме (%M
в полной с доменом);$(git_status_symbol)
— вызов функции git_status_symbol;${vcs_info_msg_0_}
— вывод информации о git репозитории в текущем каталоге;%~
— вывод текущего пути с заменой домашнего каталога на «~»;%(#.#.$)
— условный оператор, который выводит#
для root и$
для других пользователей.
Я решил за одно добавить в приглашении имя пользователя и короткое имя машины, если вдруг решусь устанавливать zsh на удалённые машины и использовать его, так будет понятнее с какой машиной я работаю. Локально у себя на компьютере лучше убрать, чтобы сэкономить место на экране, как это сделано в оригинальной теме eastwood
.
Вместо условного оператора можно использовать просто %#
, который аналогично выведет #
для root и %
для других пользователей.
Стиль вывода информации о git репозитории можно настроить в строке с zstyle
.
Алиасы для команд
Далее добавил алиасы для часто используемых команд. Выбрал то, что нужно мне. Вообще можно поискать и другие в папке plugins
в «Oh My Zsh». Для добавления алиаса нужно добавить команду alias с указанием сокращения или функцию, если требуется выполнить что-то сложнее одной команды. Во втором случае, для примера привожу вариант команд gpa и gpat, которые находят все настроенные удалённые репозитории в репозитории git и делают команды push и push с тегами во все из них. Пробовал предложить эти команды в «Oh My Zsh», но мой запрос отклонили, но это не мешает добавить эти команды в свой файл конфигурации.
alias ga='git add'
alias gaa='git add --all'
alias gc='git commit --verbose'
alias gc!='git commit --verbose --amend'
alias gca='git commit --verbose --all'
alias gca!='git commit --verbose --all --amend'
alias glog='git log --oneline --decorate --graph'
function gpa() {
for server in $(git remote -v | cut -f1 | uniq) ; do
echo "git push $server"; git push $server
done
}
function gpat() {
for server in $(git remote -v | cut -f1 | uniq) ; do
echo "git push $server --tags"; git push $server --tags
done
}
alias gst='git status'
Для vscode пришлось немного исправить код, но можно было бы и ввести переменную, как в оригинале:
function vsc {
if (( $# )); then
code $@
else
code .
fi
}
Осталось настроить сокращения для часто используемых путей, например www
для папки /var/www
. В этом случае достаточно будет ввести в командной строке ~www
, чтобы попасть в необходимую папку.
hash -d www=/var/www
При переходе в папки, которые указаны в hash
, также экономится пространство с строке приглашения, т.к. вместо полного пути отображается его сокращённый вариант. Особенно это удобно, если нужно сократить длинный путь, например, если добавить следующее
hash -d tavda=/home/user/NetBeansProjects/tavda.info
то при входе в папку /home/user/NetBeansProjects/tavda.info
в строке приглашении высветится ~tavda
, а для вложенных папок будет отображён сокращённый путь, например, ~tavda/public
.
Заключение
В результате получился вот такой файл конфигурации:
# default config
autoload -Uz compinit
compinit
setopt COMPLETE_IN_WORD
setopt AUTOCD
# history
HISTFILE=$HOME/.zsh_history
setopt APPEND_HISTORY
setopt INC_APPEND_HISTORY
setopt HIST_IGNORE_DUPS
setopt HIST_IGNORE_SPACE
setopt HIST_VERIFY
# plugins
if [ -f /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh ]; then
source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh
fi
if [ -f /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]; then
source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
fi
if [ -f $HOME/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh ]; then
source $HOME/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh
bindkey '^[[A' history-substring-search-up
bindkey '^[[B' history-substring-search-down
fi
# prompt
git_status_symbol() {
if git rev-parse --is-inside-work-tree &> /dev/null; then
if ! git diff --quiet &> /dev/null; then
echo "%F{red}*%f"
fi
fi
}
user_host_ssh() {
if [[ -n "$SSH_CONNECTION" || -n "$SUDO_USER" ]]; then
echo '%F{red}%n@%m%f:'
fi
}
autoload -Uz vcs_info
precmd() { vcs_info }
zstyle ':vcs_info:git:*' formats '[%b]'
setopt PROMPT_SUBST
PROMPT='$(user_host_ssh)$(git_status_symbol)%F{green}${vcs_info_msg_0_}%F{cyan}[%~]%f%(#.#.$) '
# git aliases
alias ga='git add'
alias gaa='git add --all'
alias gc='git commit --verbose'
alias gc!='git commit --verbose --amend'
alias gca='git commit --verbose --all'
alias gca!='git commit --verbose --all --amend'
alias glog='git log --oneline --decorate --graph'
function gpa() {
for server in $(git remote -v | cut -f1 | uniq) ; do
echo "git push $server"; git push $server
done
}
function gpat() {
for server in $(git remote -v | cut -f1 | uniq) ; do
echo "git push $server --tags"; git push $server --tags
done
}
alias gst='git status'
# vscode aliases
function vsc {
if (( $# )); then
code $@
else
code .
fi
}
# hashes
hash -d www=/var/www
Текст можно просто скопировать и разместить в домашней папке ~/.zshrc
. Теперь можно изменить оболочку по умолчанию у нужного пользователя (chsh -s /bin/zsh
) и повторно войти в систему. Если вы не установите дополнительные плагины через пакетный менеджер своего дистрибутива или через git clone, то этот функционал просто не будет включен.
Приятного и комфортного вам управления вашими устройствами!
Обратите внимание, что заметки могут обновляться со временем. Это может быть как исправление найденных ошибок, так и доработка содержания с целью более полного раскрытия темы. Информация об изменениях доступна в репозитории на github. Там же вы можете оставить в Issue ваши замечания по данной заметке.
Если данная заметка оказалась вам полезной, можете поблагодарить автора финансово.