Разработчики ПО — если не единственные, то практически единственные, кому очень просто создавать инструменты для улучшения своей профессиональной работы; однако со временем это усложняет жизнь людям, постоянно переключающимся между разными инструментами и не вкладывающим время в глубокое изучение своего инструментария. Имея глубокое уважение к негласным знаниям людей лучше меня, я всё же считаю, что отличная эвристика 80/20 заключается в том, чтобы изучать старые добрые инструменты Unix cat, ls, cd, grep и cut. (а если вам повезло устроиться на должность настоящего современного сисадмина, то ещё и sed с awk.)

Однако существуют инструменты, выгода от использования которых настолько мгновенна и ценность от применения настолько уникальна, что эвристика 80/20 полностью к ним неприменима. Один из них — это fzf. И меня очень печалит то, что многие скачивают его, запускают в командной строке «как есть», а потом просто мотают головой и произносят: «Я не понимаю».

Мне хотелось бы изменить ситуацию. Предположим, что вы работаете на более-менее стандартной машине с Ubuntu. Вы только что установили fzf при помощи стандартного скрипта установки. Что же дальше?

Сначала попробуйте Ctrl+R…


В большинстве терминалов, как в Linux, так и в Windows Ctrl+R позволяет выполнять поиск в обратном порядке введённых команд. Возможно вы, как и я, не слышали об этом до сего момента, несмотря на то, что работаете с шеллом уже десяток лет; причина в том, что базовая версия этого ПО неудобна по двум причинам:

  • Чтобы получить то, что вы пытаетесь вспомнить, нужно ввести полностью совпадающую строку.
  • Вы получаете только одно превью, поэтому если ошибётесь в полностью совпадающей строке хотя бы на один символ, придётся искать ветра в поле.

fzf — довольно странная программа, потому что её установка полностью перезаписывает целую кучу горячих клавиш, чтобы сделать их лучше. В обычной ситуации мне бы это не понравилось. Но…


… Это существенное улучшение по сравнению с тем, что было.

(Стоит заметить, что установка fzf через менеджер пакетов наподобие apt может и не дать такого результата! Именно поэтому я продолжаю намекать, что следует использовать скрипт установки, даже если вы согласны со мной в том, что curl | bash — это зло!)

… а теперь попробуйте Alt+C


Допустим, вы запускаете пустой терминал. Вы пытаетесь быстро найти свои репозитории хобби-проектов и перейти к ним с помощью cd, но вы уже несколько недель не работали с ними, потому что ваша основная работа необычайно интересна и увлекательна… Как их найти?

Ответ: с помощью fzf. fzf превращает Alt+C в сочетание горячих клавиш для тюнингованного cd с нечётким поиском и позволяет очень быстро перемещаться, когда единственное, что вы смутно помните — имя нужной папки.


Основная команда fzf


Итак, мы разобрались с горячими клавишами. Откровенно говоря, эти две функции сами по себе представляют основную ценность, получаемую мной от fzf, но давайте всё-таки посмотрим, что делает сама эта команда.


Она выполняет нечёткий поиск местоположений файлов! По крайней мере, относительно вашей собственной папки. Само по себе это не особо полезно.

Но попробуйте vi $(fzf), и вуаля…!



Вы получаете возможность нечёткого поиска в редакторе!

(Кстати, в данном случае в vi нет ничего уникального. Можно вызывать команду с emacs, nano, code и любым другим редактором!)

vi $(find. '/' | fzf): для поиска произвольных файлов конфигурации


Однажды я попытался создать свою первую автоматическую перезагрузку при помощи расширения Firefox, entr и nginx. И у меня возник вопрос: где же находится nginx.conf?

Я составил список возможных действий. Можно было:

  1. Воспользоваться полузабытыми знаниями FHS, чтобы попытаться угадать при помощи trees и grep, или
  2. Просто крепко запомнить местонахождение и ощущать своё превосходство над всеми остальными, или
  3. Присоединить пайпом find. ‘/’ к fzf и начать поиск.


Мне очень нравится этот клип, потому что в нём показаны некоторые тонкости использования fzf, а также одна из наиболее продвинутых функций поиска — поиск conf$ отфильтровывает все строки, которые не заканчиваются на conf. Обратите внимание, что fzf временно сходит с ума, когда find сталкивается с кучей ошибок «Permission denied», но спустя несколько секунд приходит в себя.

Стоят ли платить этими лишними секундами за возможность нахождения файлов конфигурации таким не требующим мыслительных усилий способом? На мой взгляд, да.

Ещё меньше проблем: vi **<TAB>


Спасибо sigmonsays за то, что напомнил мне об этой возможности!

Примерно посередине спектра между «перезаписать сочетания горячих клавиш» и «использовать стандартный fzf» находится «использовать две звёздочки для нечёткого автозаполнения отступов». Вот пример того, как я применяю это для выполнения чего-то похожего на vi $(fzf):


После получения команды всё-таки придётся ещё раз нажать на Enter.

У меня пока не появилось привычки использовать это часто, потому что в реальной жизни это пригождается мне дома только как замена $(fzf), а вызов явным образом мне запомнить намного проще. Думаю, для любителей tab-tab-звёздочки это похоже на то, как мой коллега копипастит вручную из терминала, вместо того, чтобы воспользоваться :read ! echo "Hello world!".

mv $(fzf) $(fzf) — для реально страдающих амнезией


Для случаев, когда вы не помните точно, ни куда вы выполнили перемещение, ни что переместили, но понимаете, что это точно было сделано.


Знакомство с rg: с быстрым и рекурсивным по умолчанию grep


Всё, что описано ниже, можно выполнить и при помощи grep, однако истинные возможности rg (также называемого ripgrep) раскрывает его рекурсивная по умолчанию природа. Крайне рекомендую скачать его и использовать в показанных ниже примерах. Но если вы боитесь новых инструментов, то не стоит волноваться!

rg . | fzf: нечёткий поиск каждой строки в каждом файле

Итак, теперь мы зашли на территорию настоящей амнезии.

rg . | fzf | cut -d ":" -f 1: нечёткий поиск каждой строки в каждом файле и возврат местоположения файла

vim $(rg . | fzf | cut -d ":" -f 1): нечёткий поиск каждой строки в каждом файле и открытие этого файла

Комментарии (23)


  1. baldr
    31.07.2023 07:45
    +1

    За перевод спасибо.

    Однако, например, для поиска файлов по всему диску все же удобнее пользоваться mlocate, на мой взгляд. find каждый раз начинает поиск сначала и долго пробегается по всем папкам, а locate хранит весь список в свой базе (правда, обновляет ее только раз-два в день). Поэтому когда делаешь find + grep, а потом осознаешь что надо бы еще пару раз применить grep чтобы сократить список - немного раздражает снова ждать полного пересканирования диска.


    1. iDoka
      31.07.2023 07:45
      +1

      Вы можете принудительно вызывать обновление, после значительного обновления содержимого ФС:

      sudo updatedb

      на SSD ext4 обновление занимаем буквально секунды


      1. baldr
        31.07.2023 07:45

        Именно так и делаю. Я уж не стал это писать.


    1. mpa4b
      31.07.2023 07:45
      +1

      А зачeм делать find и потом греп, если у первого есть достаточный набор фильтров, по имени файла в том числе. Мне в голову приходит только find с опцией -exec (ну или далее xargs), где грепом ищется что-то внутри файлов.


      1. baldr
        31.07.2023 07:45
        +1

        Ну вот мне быстрее вспомнить "locate | grep amqplib" чем все ключи у find. А потом надо повторить поиск, но добавив ещё условий, а find работает гораздо медленнее.


    1. orbion
      31.07.2023 07:45
      +1

      У find есть многопоточная (и более дружелюбная, как позиционирует автор) альтернатива – fd, можно найти в репозиториях многих дистрибутивов. От медленного диска, конечно, не спасёт, но работает порой ощутимо быстрее.


    1. Vaitek
      31.07.2023 07:45

      А для быстрого поиска на подмонтированных NFS поможет?


  1. unC0Rr
    31.07.2023 07:45
    +4

    mv $(fzf) $(fzf) — для реально страдающих амнезией

    Для случаев, когда вы не помните точно, ни куда вы выполнили перемещение, ни что переместили, но понимаете, что это точно было сделано.
    Учитывая, что останется в .history — именно так всегда и будет: "что-то куда-то перемещено".


    1. baldr
      31.07.2023 07:45

      Кстати, а fzf ищет по .history или еще по какой-то своей базе? Есть же известная проблема с несколькими терминалами - в history по-умолчанию записывается история только последнего закрытого терминала. У меня постоянно открыто около 20 вкладок терминала, поэтому полагаться можно только на недавнюю историю.


      1. Cheater
        31.07.2023 07:45
        +2

        Fzf не имеет своей БД/индекса поиска, это интерфейс навигации по набору строк, подаваемых ему на вход. По умолчанию например, если его вызывать без аргументов, он вызывает дочерним процессом find и обрабатывает его вывод. Локальную историю соответственно ему тоже можно отдать вызовом правильной утилиты ("fc -lI" в zsh например).


      1. Maxim4711
        31.07.2023 07:45
        +1

        Известную проблему решает например специализированная утилита atuin


      1. iLi0ni
        31.07.2023 07:45
        +1

        Разве это не решает проблему?:

        shopt -s histappend

        PROMPT_COMMAND='history -a'

        https://www.opennet.ru/base/sys/bash_tips.txt.html


        1. baldr
          31.07.2023 07:45
          +2

          Да, но решает опять немного не так как хотелось бы. При нажатии стрелки вверх оно же покажет последнюю команду среди всех окон, а не только текущего?

          Мне нужно чтобы и история не пропадала, но чтобы быстрый поиск использовал, в первую очередь, историю текущего окна.


  1. Aquahawk
    31.07.2023 07:45
    +1

    а еще есть офигенная утилита для поиска ack. Искать всякие упоминания строчек конфига в исходниках удобно


    1. 1allen
      31.07.2023 07:45

      ag, ещё интереснее


  1. LF69ssop
    31.07.2023 07:45
    +11

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

    "Выгода и ценность" после прочтения остались под большим вопросом. Классические инструменты как-то удобнее, и притом они есть везде.


  1. xotkot
    31.07.2023 07:45
    +1

    если искать по строкам то и открывать файл лучше уж сразу на нужной строке:
    rg -n . | fzf | awk -F: '{print "+"$2,$1}'

    для редактора emacs:
    emacs $(rg -n . | fzf | awk -F: '{print "+"$2,$1}')

    для alias:
    alias ff='emacs $(rg -n . | fzf | awk -F: '\''{print "+"$2,$1}'\'')'


  1. PeterFukuyama
    31.07.2023 07:45
    +2

    FZF_DEFAULT_OPTS=--preview="head {} -n 100"

    Добавление предпросмотра при поиске.


  1. brake
    31.07.2023 07:45
    +1

    На серверах, скорее всего, будет только стандартный набор команд и никто не позволит ставить там всё описанное выше. Так зачем привыкать?


    1. saidelman
      31.07.2023 07:45
      +3

      Затем, чтобы было удобно хотя бы локально. Мало кто ведь локально работает в голом vim версии 2008 года? Или в nano. А на серверах только они и будут, скорее всего.

      А ещё далеко не всем нужно ходить на сервера, на которых нельзя ничего ставить. Кому-то можно устанавливать свой софт, а кому-то вообще все эти удалённые сервера нужны раз в тысячелетие.


  1. Amadey17
    31.07.2023 07:45

    Интересная штука. Надо всё же будет в работе потыкать. Спасибо за статью.


  1. Ryav
    31.07.2023 07:45

    Почему всё же fzf, а не fzy?


  1. thunderspb
    31.07.2023 07:45

    Да, отличная утиллита. Использую в личных скриптах для работы с авс.