Termnal

fzf: интерактивный поиск в терминале macOS

BorisBoris
|
8 января 2026 г.
|
13 мин чтения
|
113 просмотров
fzf: интерактивный поиск в терминале macOS

Если вы проводите много времени в терминале, то наверняка знаете это чувство: нужно найти файл, вспомнить команду из истории или переключиться на нужную ветку Git. Обычно это означает много набора текста, grep, find и прочих команд. fzf — инструмент, который превращает эти рутинные задачи в быстрый интерактивный поиск.

Что такое fzf?

fzf (fuzzy finder) — это универсальный инструмент для "нечёткого" поиска в командной строке. Он принимает любой список строк и позволяет мгновенно фильтровать его по мере набора текста.

Ключевые особенности:

  • Fuzzy-поиск — не нужно помнить точное название, достаточно нескольких букв в любом порядке
  • Мгновенная фильтрация — результаты обновляются при каждом нажатии клавиши
  • Универсальность — работает с любым текстовым вводом (файлы, история, процессы, ветки Git и т.д.)
  • Интеграция — встраивается в bash, zsh, fish и другие оболочки
  • Лёгкий — написан на Go, работает молниеносно даже с огромными списками

Пример "нечёткого" поиска

Допустим, вы ищете файл UserAuthenticationController.ts. С fzf достаточно набрать:

  • uac — найдёт по первым буквам слов
  • authcon — найдёт по части слов
  • controller user — порядок не важен

fzf находит все строки, содержащие введённые символы в любом порядке, и ранжирует их по релевантности.


Установка fzf на macOS

Самый простой способ — через Homebrew:

brew install fzf

После установки запустите скрипт настройки для интеграции с вашей оболочкой:

# Установит полезные key bindings и автодополнение
$(brew --prefix)/opt/fzf/install

Скрипт спросит:

  • Enable fuzzy auto-completion? — да, это добавит автодополнение с fzf
  • Enable key bindings? — да, это добавит горячие клавиши (Ctrl+R, Ctrl+T и др.)
  • Update shell config? — да, добавит нужные строки в .bashrc или .zshrc

После установки перезапустите терминал или выполните:

source ~/.zshrc  # или ~/.bashrc

Проверка установки:

fzf --version
# 0.54.3 (brew)

Базовое использование

Поиск файлов

Просто запустите fzf в любой директории:

fzf

Это откроет интерактивный список всех файлов в текущей директории и поддиректориях. Начните набирать — список будет фильтроваться в реальном времени.

Управление:

КлавишаДействие
/ Перемещение по списку
EnterВыбрать и вывести результат
Esc / Ctrl+CОтмена
TabВыбрать несколько (в режиме multi-select)
Ctrl+J / Ctrl+KАльтернатива стрелкам

Передача данных через pipe

fzf работает с любым списком строк:

# Найти процесс
ps aux | fzf

# Найти установленный brew-пакет
brew list | fzf

# Выбрать ветку Git
git branch | fzf

Использование результата

Результат fzf можно подставить в другую команду:

# Открыть выбранный файл в VS Code
code $(fzf)

# Удалить выбранный файл (осторожно!)
rm $(fzf)

# Перейти в выбранную директорию
cd $(find . -type d | fzf)

Горячие клавиши в терминале

После установки key bindings появляются три мощные комбинации:

Ctrl+R — поиск по истории команд

Это, пожалуй, самая полезная функция. Вместо стандартного Ctrl+R, который показывает команды по одной, fzf показывает всю историю с интерактивным поиском.

# Нажмите Ctrl+R и начните вводить
# Например: "docker" — покажет все команды с docker
# Или: "npm run" — все npm run команды

Преимущества:

  • Видно сразу много результатов
  • Нечёткий поиск: gco найдёт git checkout
  • Можно искать по любой части команды

Ctrl+T — вставка пути к файлу

Находясь в середине набора команды, нажмите Ctrl+T чтобы найти и вставить путь к файлу:

# Набираете команду:
vim <нажимаете Ctrl+T>

# Открывается fzf, выбираете файл
# Путь автоматически вставляется:
vim src/components/Header.vue

Alt+C (или Esc+C на macOS) — переход в директорию

Мгновенный поиск и переход в любую поддиректорию:

# Нажмите Alt+C (или Esc, затем C)
# Выберите директорию — cd выполнится автоматически

Примечание для macOS: По умолчанию Alt в Terminal.app работает иначе. Либо используйте Esc+C (нажать Esc, отпустить, нажать C), либо настройте терминал на использование Option как Meta.


Продвинутые возможности

Превью файлов

fzf может показывать содержимое файла прямо в окне поиска:

fzf --preview 'cat {}'

Для более красивого превью с подсветкой синтаксиса установите bat:

brew install bat

# Теперь превью будет с подсветкой
fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}'
Настройка превью по умолчанию (добавить в .zshrc)
# Красивое превью с bat (если установлен) или cat
export FZF_DEFAULT_OPTS="--preview 'bat --color=always --style=numbers --line-range=:500 {} 2>/dev/null || cat {}'"

# Настройка высоты окна превью (50% справа)
export FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS --preview-window=right:50%:wrap"

Множественный выбор

Флаг -m или --multi позволяет выбрать несколько элементов с помощью Tab:

# Выбрать несколько файлов для удаления
rm $(fzf -m)

# Выбрать несколько файлов для git add
git add $(fzf -m)

Выбор директорий

По умолчанию fzf ищет файлы. Для поиска только директорий:

# Найти и перейти в директорию
cd $(find . -type d | fzf)

# Или создать алиас
alias cdf='cd $(find . -type d | fzf)'

Превью директорий с tree

Команда tree показывает структуру директории в виде дерева — это идеальный инструмент для превью папок в fzf.

Установка tree:

brew install tree

Основные флаги tree:

ФлагОписание
-CЦветной вывод
-L NГлубина вложенности (например, -L 2)
-aПоказывать скрытые файлы
-dТолько директории
-I patternИгнорировать файлы по паттерну

Использование с fzf:

# Выбор директории с превью структуры
cd $(find . -type d | fzf --preview 'tree -C -L 2 {}')
Функция для навигации с tree-превью
# Добавьте в .zshrc
ftree() {
  local dir
  dir=$(find ${1:-.} -type d 2>/dev/null | fzf --preview 'tree -C -L 2 {} 2>/dev/null' --preview-window=right:50%)
  [[ -n "$dir" ]] && cd "$dir"
}

# Или с fd (быстрее)
ftree() {
  local dir
  dir=$(fd --type d --hidden --exclude .git 2>/dev/null | fzf --preview 'tree -C -L 2 {} 2>/dev/null' --preview-window=right:50%)
  [[ -n "$dir" ]] && cd "$dir"
}

Теперь при выборе директории вы сразу видите её содержимое в виде дерева — это значительно упрощает навигацию по незнакомым проектам.

Кастомные команды для генерации списка

Переменная FZF_DEFAULT_COMMAND определяет, откуда fzf берёт список файлов по умолчанию.

Рекомендуемые настройки с fd (современная замена find)

Сначала установите fd — быструю замену find:

brew install fd

Затем добавьте в .zshrc:

# Использовать fd вместо find (быстрее, уважает .gitignore)
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'

# Для Ctrl+T тоже использовать fd
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"

# Для Alt+C (поиск директорий)
export FZF_ALT_C_COMMAND='fd --type d --hidden --follow --exclude .git'

Преимущества fd:

  • В 5-10 раз быстрее find
  • Автоматически игнорирует файлы из .gitignore
  • Более понятный синтаксис

Интеграция с Git

fzf отлично работает с Git. Вот несколько полезных алиасов и функций:

Git-функции для .zshrc
# Переключение веток через fzf
gco() {
  local branch
  branch=$(git branch --all | grep -v HEAD | sed 's/.* //' | sed 's#remotes/origin/##' | sort -u | fzf --height 40% --reverse)
  if [[ -n "$branch" ]]; then
    git checkout "$branch"
  fi
}

# Интерактивный git log с превью коммитов
glog() {
  git log --oneline --color=always | fzf --ansi --preview 'git show --color=always {1}' --preview-window=right:60%
}

# Выбор файлов из git status для git add
gadd() {
  local files
  files=$(git status --short | fzf -m --preview 'git diff --color=always {2}' | awk '{print $2}')
  if [[ -n "$files" ]]; then
    echo "$files" | xargs git add
    git status --short
  fi
}

# Удаление локальных веток
gbr-delete() {
  local branches
  branches=$(git branch | grep -v '\*' | fzf -m)
  if [[ -n "$branches" ]]; then
    echo "$branches" | xargs git branch -d
  fi
}

# Интерактивный git stash
gstash() {
  local stash
  stash=$(git stash list | fzf --preview 'git stash show -p {1}' | cut -d: -f1)
  if [[ -n "$stash" ]]; then
    git stash apply "$stash"
  fi
}

Использование:

  • gco — выбрать и переключиться на ветку
  • glog — просмотр истории с превью
  • gadd — интерактивный git add с просмотром diff
  • gbr-delete — удаление локальных веток
  • gstash — применение stash

Интеграция с другими инструментами

npm scripts

Интерактивный запуск npm-скриптов:

Функция для запуска npm scripts
# Добавьте в .zshrc
nr() {
  local script
  script=$(cat package.json | jq -r '.scripts | keys[]' 2>/dev/null | fzf --height 40% --reverse)
  if [[ -n "$script" ]]; then
    echo "Running: npm run $script"
    npm run "$script"
  fi
}

Теперь просто введите nr в проекте с package.json и выберите скрипт.

Docker

Docker-функции для fzf
# Остановить контейнер
dstop() {
  local container
  container=$(docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}' | fzf | awk '{print $1}')
  if [[ -n "$container" ]]; then
    docker stop "$container"
  fi
}

# Посмотреть логи контейнера
dlogs() {
  local container
  container=$(docker ps --format '{{.Names}}\t{{.Image}}' | fzf | awk '{print $1}')
  if [[ -n "$container" ]]; then
    docker logs -f "$container"
  fi
}

# Зайти в контейнер
dexec() {
  local container
  container=$(docker ps --format '{{.Names}}\t{{.Image}}' | fzf | awk '{print $1}')
  if [[ -n "$container" ]]; then
    docker exec -it "$container" sh
  fi
}

# Удалить образы
drmi() {
  local images
  images=$(docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}' | fzf -m | awk '{print $1}')
  if [[ -n "$images" ]]; then
    echo "$images" | xargs docker rmi
  fi
}

SSH-хосты

Быстрое подключение к SSH-хостам
# Добавьте в .zshrc
fssh() {
  local host
  host=$(grep "^Host " ~/.ssh/config | awk '{print $2}' | fzf --height 40% --reverse)
  if [[ -n "$host" ]]; then
    ssh "$host"
  fi
}

Теперь fssh покажет все хосты из ~/.ssh/config и подключится к выбранному.

Kill процесса

Интерактивное завершение процессов
# Добавьте в .zshrc
fkill() {
  local pid
  pid=$(ps -ef | sed 1d | fzf -m --preview 'echo {}' | awk '{print $2}')
  if [[ -n "$pid" ]]; then
    echo "$pid" | xargs kill -9
  fi
}

Полная конфигурация

Рекомендуемая конфигурация fzf для .zshrc
# ==========================================
# FZF Configuration
# ==========================================

# Использовать fd для поиска (быстрее find, уважает .gitignore)
# Если fd не установлен, fzf использует стандартный find
if command -v fd &> /dev/null; then
  export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
  export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
  export FZF_ALT_C_COMMAND='fd --type d --hidden --follow --exclude .git'
fi

# Внешний вид и поведение fzf
export FZF_DEFAULT_OPTS="
  --height 60%
  --layout=reverse
  --border rounded
  --info=inline
  --margin=1
  --padding=1
"

# Превью файлов (использует bat если установлен)
if command -v bat &> /dev/null; then
  export FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS --preview 'bat --color=always --style=numbers --line-range=:300 {} 2>/dev/null || cat {}' --preview-window=right:50%:wrap"
fi

# Цветовая схема (опционально — настройте под свой терминал)
# export FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS
#   --color=fg:#c0caf5,bg:#1a1b26,hl:#bb9af7
#   --color=fg+:#c0caf5,bg+:#292e42,hl+:#7dcfff
#   --color=info:#7aa2f7,prompt:#7dcfff,pointer:#7dcfff
#   --color=marker:#9ece6a,spinner:#9ece6a,header:#9ece6a
# "

# Настройка Ctrl+R (история команд)
export FZF_CTRL_R_OPTS="
  --preview 'echo {}'
  --preview-window=down:3:wrap
  --bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort'
  --header 'Press CTRL-Y to copy command to clipboard'
"

# Настройка Ctrl+T (вставка пути файла)
export FZF_CTRL_T_OPTS="
  --preview 'bat --color=always --style=numbers --line-range=:300 {} 2>/dev/null || cat {}'
  --preview-window=right:60%:wrap
  --bind 'ctrl-/:toggle-preview'
"

# Настройка Alt+C (переход в директорию)
# Использует tree для красивого превью структуры (если установлен)
export FZF_ALT_C_OPTS="
  --preview 'tree -C -L 2 {} 2>/dev/null || ls -la {}'
  --preview-window=right:50%
"

# ==========================================
# Полезные алиасы и функции
# ==========================================

# Поиск и открытие файла в редакторе
fe() {
  local file
  file=$(fzf --query="$1" --select-1 --exit-0)
  [[ -n "$file" ]] && ${EDITOR:-vim} "$file"
}

# Поиск и переход в директорию
fcd() {
  local dir
  dir=$(find ${1:-.} -type d 2>/dev/null | fzf +m)
  [[ -n "$dir" ]] && cd "$dir"
}

# Поиск в содержимом файлов (требует ripgrep)
frg() {
  if ! command -v rg &> /dev/null; then
    echo "ripgrep (rg) is not installed. Install with: brew install ripgrep"
    return 1
  fi
  local file line
  read -r file line <<< $(rg --line-number --no-heading --color=always "${1:-}" | fzf --ansi | awk -F: '{print $1, $2}')
  [[ -n "$file" ]] && ${EDITOR:-vim} "$file" +"$line"
}

# Git checkout branch
gco() {
  local branch
  branch=$(git branch --all | grep -v HEAD | sed 's/.* //' | sed 's#remotes/origin/##' | sort -u | fzf --height 40% --reverse)
  [[ -n "$branch" ]] && git checkout "$branch"
}

# Git add с превью
gadd() {
  local files
  files=$(git status --short | fzf -m --preview 'git diff --color=always {2}' | awk '{print $2}')
  [[ -n "$files" ]] && echo "$files" | xargs git add && git status --short
}

# npm run с выбором скрипта
nr() {
  local script
  script=$(cat package.json 2>/dev/null | jq -r '.scripts | keys[]' 2>/dev/null | fzf --height 40% --reverse)
  [[ -n "$script" ]] && npm run "$script"
}

Частые проблемы и решения

Alt+C не работает на macOS

Проблема: Комбинация Alt+C не открывает fzf для выбора директории.

Причина: В Terminal.app и iTerm2 клавиша Alt (Option) по умолчанию используется для ввода специальных символов, а не как модификатор Meta.

Решения:

1. Использовать Esc+C: Нажмите Esc, отпустите, затем нажмите C. Это эквивалент Alt+C.

2. Для iTerm2:

  • Preferences → Profiles → Keys
  • Установите "Left Option key" в "Esc+"

3. Для Terminal.app:

  • Preferences → Profiles → Keyboard
  • Включите "Use Option as Meta key"
fzf не находит файлы из .gitignore

Проблема: fzf пропускает некоторые файлы.

Причина: Если вы используете fd или rg как источник, они по умолчанию уважают .gitignore.

Решение:

# Показывать игнорируемые файлы
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --no-ignore'
Поиск медленный в больших директориях

Проблема: fzf долго загружает список файлов.

Решение:

  1. Установите fd вместо стандартного find:
    brew install fd
    export FZF_DEFAULT_COMMAND='fd --type f'
    
  2. Исключите тяжёлые директории:
    export FZF_DEFAULT_COMMAND='fd --type f --exclude node_modules --exclude .git --exclude vendor'
    
  3. Используйте --height для ограничения списка:
    fzf --height 40%
    
Превью не работает

Проблема: Окно превью показывает ошибку или пустое.

Решения:

  1. Проверьте наличие утилит:
    # Для подсветки синтаксиса
    brew install bat
    
    # Для поиска по содержимому
    brew install ripgrep
    
  2. Используйте простое превью:
    export FZF_DEFAULT_OPTS="--preview 'cat {}'"
    
  3. Отключите превью:
    fzf --no-preview
    

Заключение

fzf — это инструмент, который кардинально меняет работу в терминале. После освоения вы удивитесь, как раньше обходились без него.

Рекомендуемый путь освоения:

  1. Начните с Ctrl+R — поиск по истории команд. Это самая частая операция, и вы сразу почувствуете пользу.
  2. Освойте Ctrl+T — вставка путей к файлам. Особенно полезно для vim, code, cat и подобных команд.
  3. Добавьте Git-функцииgco для переключения веток станет вашим новым любимым инструментом.
  4. Настройте превью — установите bat, fd и tree для лучшего опыта.
  5. Создавайте свои функции — fzf универсален, его можно применить практически к любому списку данных.

Полезные ресурсы

  • Официальный репозиторий fzf — документация и примеры
  • fzf Wiki — расширенные примеры использования
  • fd — быстрая альтернатива find
  • bat — cat с подсветкой синтаксиса
  • ripgrep — быстрый grep для поиска по содержимому
  • tree — отображение структуры директорий в виде дерева

Комментарии

Войдите, чтобы оставить комментарий

Пока нет комментариев. Будьте первым!