Я уже более десяти лет веду собственные дотфайлы и за это время написал множество скриптов оболочки. В этой статье я решил поделиться с вами теми из них, которые сам применяю регулярно.

Буфер обмена

copy и pasta — это простые обёртки для менеджеров системного буфера обмена вроде pbcopy в macOS и xclip в Linux. Я использую их постоянно.

# Общие примеры.
run_some_command | copy
pasta > file_from_my_clipboard.txt

# Копирование содержимого файла.
copy < file.txt

# Открытие пути файла из буфера обмена.
vim "$(pasta)"

# Декодирование base64 из буфера обмена.
pasta | base64 --decode

pastas выводит текущее состояние буфера обмена в stdout и затем при каждом изменении буфера также выводит новую версию. Этот инструмент я использую где-то раз в неделю.

# Общий пример.
pastas > everything_i_copied.txt

# Скачивает содержимое каждой ссылки, которую я копирую в буфер обмена.
pastas | wget -i -

cpwd копирует адрес текущего каталога в буфер обмена. По сути, это pwd | copy. Я часто так делаю, когда хочу использовать текущий каталог в другой вкладке терминала. То есть я копирую адрес в одной вкладке и перехожу по нему через cd в другой. Пригождается где-то раз в день.

Управление файлами

mkcd foo создаёт каталог и переходит в него через cd. По сути, это команда mkdir foo && cd foo. Я этим скриптом пользуюсь постоянно — почти при каждом создании каталога.

tempe создаёт временный каталог и переключается на него. По существу, это команда cd "$(mktemp -d)". Её я часто использую, когда нужно проделать какую-то временную работу, чтобы потом вручную всё не подчищать. Вот пара типичных примеров:

# Скачивание и извлечение файла.
tempe
wget 'https://example.com/big_file.tar.xz'
tar -xf big_file.tar.xz
# ...какие-то действия с файлом...

# Написание быстрого одноразового скрипта для экспериментов.
tempe
vim foo.py
python3 foo.py

trash a.txt b.png отправляет a.txt и b.png в корзину. Работает в macOS и Linux. Этим скриптом я пользуюсь каждый день, причём явно чаще, чем rm. Полезная штука — защищает от случайного удаления файлов.

mksh позволяет быстро создавать скрипты оболочки. К примеру, mksh foo.sh создаёт foo.sh, делает его исполняемым с помощью chmod u+x, добавляет префиксы Bash и открывает скрипт в редакторе (в моём случае Vim). Пригождается раз в несколько дней. Многие из перечисленных в этой статье скриптов были созданы с помощью mksh.

Интернет

serveit запускает на порту localhost:8000 статический файловый сервер, предоставляющий доступ к файлам текущего каталога. По сути, это команда python3 -m http.server 8000, только в этом случае скрипт обрабатывает сценарии, когда Python не установлен, используя вместо него другие программы. Мне этот инструмент пригождается несколько раз в неделю. Если вы не веб-разработчик, то вам он может оказаться не так полезен.

getsong использует yt-dlp для скачивания музыки в максимальном доступном качестве с таких ресурсов, как YouTube или SoundCloud. Например, getsong https://www.youtube.com/watch?v=dQw4w9WgXcQ скачает указанный ролик в виде трека. Я пользуюсь этим скриптом несколько раз в неделю. Обычно для скачивания саундтреков к играм.

getpod также с помощью yt-dlp скачивает какие-нибудь записи для проигрывателя подкастов. Пригождается несколько раз в месяц.

getsubs скачивает английские субтитры к видео. Этот скрипт хорош тем, что сначала ищет «официальные» субтитры и только потом использует сгенерированные. Иногда я считываю субтитры вручную, иногда выполняю getsubs https://video.example/foo | ollama run llama3.2 "Summarize this", а иногда использую этот скрипт просто для генерации описания к видео, которое не хочу сохранять на ПК. Пригождается раз в несколько дней.

wifi offwifi on и wifi toggle помогают с управлением WiFi. wifi toggle я обычно использую, когда возникают траблы с интернетом. Благо, в этих целях пригождается он где-то всего раз в месяц.

url "$my_url" парсит URL-адрес на составляющие части. Использую примерно раз в месяц для получения информации об URL, зачастую просто потому, что не хочу кликать по ссылке с трекером.

url 'https://evil.example/track-user-link?url=https%3A%2F%2Furl-i-want-to-visit.example&track=06f8582a-91e6-4c9c-bf8e-516884584aba#cookie=123'
# original: https://evil.example/track-user-link?url=https%3A%2F%2Furl-i-want-to-visit.example&track=06f8582a-91e6-4c9c-bf8e-516884584aba#cookie=123
# protocol: https
# hostname: evil.example
# path: /track-user-link
# query: url=https%3A%2F%2Furl-i-want-to-visit.example&track=06f8582a-91e6-4c9c-bf8e-516884584aba
# - url https://url-i-want-to-visit.example
# - track 06f8582a-91e6-4c9c-bf8e-516884584aba
# hash: cookie=123

Обработка текста

line 10 выводит строку 10 из stdin. Например, cat some_big_file | line 10 выводит 10 строку файла. Думаю, такая возможность должна быть встроенной — как команды head и tail. Использую её где-то раз в месяц.

scratch открывает временный буфер Vim. По сути, это алиас для $EDITOR $(mktemp). Пригождается почти каждый день для оперативной обработки текста или для написания временной заметки.

straightquote преобразует «умные кавычки» в “прямые”. Вообще, меня этот нюанс не особо волнует, но иногда такие кавычки просачиваются в код, с которым я работаю. Кроме того, их изменение в прямые позволяет чуть уменьшить размер файла, что порой весьма актуально. Мне эта функция пригождается как минимум раз в неделю.

markdownquote добавляет > перед каждой строкой. Пользуюсь этим скриптом в Vim постоянно. Я выбираю нужный фрагмент и выполняю :'<,'>!markdownquote, чтобы сделать выбранный текст цитатой. Пригождается где-то раз в неделю.

length foo возвращает 3 (пожалуй, нужно просто использовать wc -c.)

jsonformat получает JSON из stdin и в красивом виде выводит через stdout. Использую этот скрипт несколько раз в год.

uppered и lowered преобразуют строки в нижний и верхний регистр. Например, echo foo | uppered возвращает FOO. Пригождается раз в неделю.

nato bar возвращает Bravo Alfa Romeo. Обычно использую при общении со службой поддержки, когда нужно вывести длинную строку из букв и цифр, что за всю жизнь мне приходилось делать всего несколько раз. Но иногда выручает!

u+ 2025 возвращает ñ, LATIN SMALL LETTER N WITH TILDE. Быстрый способ поиска строки Юникода. Этот скрипт пригождается редко — может, раз в месяц.

snippets foo выводит содержимое ~/.config/evanhahn-snippets/foo. Я использую snippet arrow в качестве snippet recruiter в качестве быстрого ответа рекрутёрам “not interested”snippet lorem для вывода блока “Lorem ipsum” и ещё несколько других. В неделю пригождается пару раз.

Лаунчеры REPL

Вдохновлённый интерактивной оболочкой REPL в Ruby, я создал несколько лаунчеров:

  • iclj запускает Clojure REPL,

  • ijs запускает Deno REPL (или Node REPL, если Deno отсутствует),

  • iphp запускает PHP REPL,

  • ipy запускает Python REPL,

  • isql запускает оболочку SQLite (алиас для sqlite3 :memory:).

Дата и время

hoy выводит текущую дату в формате ISO, например, 2020-04-20. Им я пользуюсь постоянно, так как люблю добавлять в начало названий файлов текущую дату.

timer 10m запускает таймер на 10 минут, затем воспроизводит рингтон и отправляет системное уведомление (подробнее в notify ниже). Я также регулярно использую команду bb timer 5m, чтобы запустить пятиминутный таймер в фоновом режиме (подробнее о bb ниже). В целом этот скрипт пригождается мне почти каждый день в качестве эффективного инструмента отслеживания времени.

rn выводит текущее время и дату, используя date и cal. Пригождается где-то раз в неделю. Вот пример его выдачи:

4:20PM on Wednesday, October 22, 2025

    September 2025
Su Mo Tu We Th Fr Sa
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

Аудио, видео и изображения

ocr my_image.png извлекает из изображения текст и выводит его в stdout. К сожалению, работает только в macOS, но я планирую это исправить. (Вот отдельная статья, посвящённая этому скрипту).

boop (алиас, не скрипт оболочки). Если команда была выполнена успешно, издаёт мажорный звук, в противном случае — минорный. Я применяю его, например, так: run_the_tests ; boop, чтобы понять, успешно ли завершились тесты. Он также пригождается при выполнении длительных команд, так как об их завершении уведомлений не поступает. Использую его постоянно.

sfx foo, по сути, просто воспроизводит ~/.config/evanhahn-sfx/foo.ogg. Применяется в описанных выше boop и timer.

tunes воспроизводит аудио из файла с помощью mpv. Использую постоянно через команду --shuffle ~/music.

pix показывает изображение с помощью mpv. Пригождается несколько раз в неделю для просмотра фото.

radio — небольшая обёртка для моих любимых станций radio lofi и radio salsa. Использую несколько раз в месяц.

speak считывает данные из stdin, удаляет всё форматирование Markdown и передаёт их в механизм речевого синтеза (say в macOS и espeak-ng в Linux). Пользуюсь этим несколько раз в месяц, обычно, когда нет возможности вычитать собственный текст вслух.

shrinkvid — обёртка ffmpeg, немного сжимающая видео. Пригождается где-то раз в месяц.

removeexif удаляет из JPEG данные EXIF. Пользуюсь этой штукой редко, отчасти, потому что она не удаляет EXIF из файлов других форматов вроде PNG. Но я рассчитываю однажды её доработать, поэтому пока держу на вооружении.

tuivid — этот скрипт позволяет смотреть видео в терминале, но я его почти не использую. Хотя при всей своей странности он мне нравится.

Управление процессами

each — мой ответ xargs и find ... -exec, которые я нахожу сложными в работе. Например, ls | each 'du -h {}' выполняет du -h для каждого файла в каталоге. Пользуюсь этим решением я редко, но регулярно мучаюсь с xargs, так что это неплохая альтернатива.

running foo аналогичен ps aux | grep foo, но намного читабельнее (лично для меня) — просто выделенный фиолетовым PID и команда.

murder foo or murder 1234 — это обёртка вокруг kill, которая отправляет kill -15 $PID, недолго ожидает, отправляет kill -2, ожидает, отправляет kill -1, и ещё раз ожидает, прежде чем в завершение отправить kill -9. Если я хочу остановить программу, то сначала прошу её об этом вежливо и уже потом грублю. Пригождается несколько раз в месяц.

waitfor $PID — ожидает завершения PID и только потом продолжает выполнение. Также не позволяет системе уйти в режим сна. Я этим скриптом пользуюсь где-то раз в месяц, когда:

# Хочу запустить что-либо только после завершения другого процесса.
waitfor 1234 ; something_else

# Запустил длительный процесс и хочу знать, когда он завершится.
waitfor 1234 ; notify 'process 1234 is done'

bb my_command подобна my_command &, только выполняет команду в глубоком фоновом режиме, совершенно не требуя вашего внимания. Пригождается, когда вам нужно запустить демона или длительный процесс, дальнейшее выполнение которого вы отслеживать не хотите. Чаще всего я применяю этот макрос в виде bb ollama serve и bb timer 5m. В целом пригождается где-то раз в день.

prettypath выводит $PATH, но с разделением строк пробелами для повышения читабельности. Использую этот скрипт в основном при отладке проблем с $PATH, которые случаются редко. Зато, когда такое происходит, он очень выручает.

tryna my_command выполняет my_command, пока та не завершится успешно. trynafail my_command, напротив, выполняет my_command, пока та не провалится. Пригождается редко, но в некоторых случаях помогает. tryna wget ... будет пытаться скачать указанный элемент. trynafail npm test останавливает тесты, когда те начинают проваливаться.

Быстрый доступ

emoji помогает находить эмодзи. Например, emoji cool выводит:

?
?
?
?
?

httpstatus выводит все коды HTTP-состояния. httpstatus 204 выводит 204 No Content. Так как я веб-разработчик, этот скрипт пригождается мне несколько раз в месяц, избавляя от необходимости искать ответ в сети.

alphabet просто выводит английский алфавит в верхнем и нижнем регистре. Кстати, использую я этот инструмент на удивление часто (где-то раз в месяц). Вот его вывод:

abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Управление системой

theme 0 меняет тему системы на тёмную, а theme 1 — на светлую. Причём этот скрипт меняет не только тему ОС, но и темы Vim, Tmux и терминала. Пригождается минимум раз в день.

sleepybear отправляет систему в сон. Работает в macOS и Linux. Использую несколько раз в неделю.

ds-destroy рекурсивно удаляет все файлы .DS_Store в каталоге. Мне не нравится, что macOS захламляет ими папки. Пользуюсь этим скриптом редко, но при необходимости он весьма выручает.

Всякая всячина

catbin foo — это, по сути, cat "$(which foo)". Позволяет просматривать исходный код файла, указанного в PATH (к примеру, я его использовал для написания этой статьи). Пригождается пару раз в месяц.

notify отправляет уведомление от ОС. Применял его в некоторых других скриптах (см. выше). Плюс примерно раз в месяц использую его как-то так:

run_some_long_running_process ; notify 'all done'

uuid выводит UUID v4. Применяю где-то раз в месяц.

А какие скрипты часто используете вы? Поделитесь

Я здесь перечислил лишь те, которыми много пользуюсь сам. Надеюсь, некоторые из них пригодятся и вам.  

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


  1. evgenyk
    02.11.2025 09:08

    Спасибо! Много интересных идей.


  1. zoydik
    02.11.2025 09:08

    Скрипт для скачивания аудио реально хорош


    1. Vindicar
      02.11.2025 09:08

      Да, я себе завёл похожий, чтобы прокси каждый раз не вбивать. И ещё один для обрезки скачанного, чтобы убрать intro/outro, если есть. Правда, они под винду.

      Скачивание аудио
      @yt-dlp --proxy socks5://адрес.byedpi.прокси:1080 ^
          --retries infinite --no-playlist ^
          --format bestaudio --extract-audio --audio-format mp3 ^
          --embed-thumbnail --windows-filenames --force-overwrites ^
          --output "%%(title)s.%%(ext)s" %*

      Если надо скачать видео, достаточно удалить все параметры со словом audio, и добавить вместо них --format "bestvideo[ext=mp4]+bestaudio"

      Обрезка аудио
      @echo off
      ffmpeg -i "%3" -map_metadata 0 -id3v2_version 3 -acodec copy -ss "%1" -to "%2" "%~N3.temp%~X3"
      IF NOT ERRORLEVEL 1 move /Y "%~N3.temp%~X3" %3

      Вызывается как cut-music 00:00:10 00:03:25 musicfile.mp3, вырежет из трека указанный кусок и оставит только его, заменив оригинальный файл.


      1. VADemon
        02.11.2025 09:08

        У youtube-dl можно в ~ положить конфигурационный файл с настройками по умолчанию.


  1. ic10
    02.11.2025 09:08

    Для меня большая проблема с личными скриптами -- запомнить их имена. Иногда то, что они вообще существует :)

    Я придумал лайфхак, который может кому-то будет полезен -- имитация пространства имен. Допустим есть какая-то область деятельности, скажем, управление iptables. Называем все свои скрипты/алиасы через

    iptables.action

    И теперь, когда вы наберете iptables.<TAB>, шелл покажет для автодополнения все ваши скрипты/алиасы и не надо их все запоминать.

    Ну и также для других областей, или все в один неймспейс загнать вроде my.<TAB>


    1. Alex_Sage
      02.11.2025 09:08

      Я как-то на уровне интуиции тоже до этого принципа пришёл. У меня все названия начинаются с главного слова, обозначающего функцию или действие: "start", "count", "search", "calc". Одна утилита, правда, выбивалась из общей концепции (начиналась на "Ultimate"), но из-за этого, думаю, я её и забросил.


    1. xenon
      02.11.2025 09:08

      Да, это хорошее решение важной проблемы. Проблема не в том, что нет инструментов, а в том, что разных задач и инструментов для их исправления так много, что уже запутываешься. Особенно если какой-то инструмент пригождается раз в месяц и реже.

      Аналогично для программирования (python), когда у программы уже много функций я программу делаю на Typer (но тот же подход и с argparse и другими либами работает) и пакую все в суб-парсеры (суб-приложения). Например, у меня команды:

      script company fetch [args]
      script company wipe [args]

      (представьте, что через CLI мы делаем все множество функций, которые доступные через HTTP)

      При этом через ArgAlias прописываю для них алиасы, то есть чтоб не писать длинно company fetch ... можно писать cf ... . Когда скрипт работает с разными сущностями (компании, люди, ....), по каждой есть разные операции - этих секций может быть много, но они все более-менее унифицированы и каждая из них изолирована и достаточно простая. script c -h и видим хелп по операциям с компаниями.


    1. evgenyk
      02.11.2025 09:08

      Я делаю примерно так же, с двумя дополнениями:
      - Свои скрипты начинаю со знака подчеркивания. Так они не путаются с системными командами и программами.
      - Чтобы меньше набирать, доавляю цифровые префиксы.
      Формат получается премерно такой:

      _<ПервыйПрефикс>_<НомерМеню>_<НомерСубменю>_ИнформационнаяЧасть
      
      Например:
      _ssh_05_01_raspberri_pi_5_user1

      Теперь работа получается так:

      1) Набираем _ssh <TAB> - вызываются все ssh скрипты

      2) Нажимаем 05 <TAB> (Если всего скриптов меньше 10, 0 допишется автоматически, тогда нажимаем просто 5)
      3) Нажимаем 01 <TAB> дописывается все имя автоматически.

      4) Enter


  1. Alex_Sage
    02.11.2025 09:08

    Вывод в rn красиво выглядит.
    Я на работе всплывашку с таким календарем добавил для сайта, скопировал из своей утилиты. Теперь осталось только для консоли её переписать, чтобы календари прямо везде были ))


  1. aragaer
    02.11.2025 09:08

    Когда увидел упоминание bb, то ожидал, что дальше будет babashka. Из волшебных скриптов у меня есть

    • xscr -- scrot + xclip + удалить файл (т.е. скриншот сразу в буфер обмена)

    • mpvs -- mpv на содержимое буфера обмена (обычно ссылка на ютуб)

    • ecc -- emacslient -c

    • gpg-check, gpg-unlock -- проверка того, что пассфраза закеширована в агенте и соответственно "запросить пассфразу, чтобы ее закешировать"

    • pyshell -- проверяет наличие .venv, если нет, то создает, а потом создает subshell и в нем этот venv активирует (аналог pipenv shell)

    • tmux-attach (и алиас ta) -- написанная на кложе (собственно bb) обвязка для tmux


    1. Newpson
      02.11.2025 09:08

      xscr -- scrot + xclip + удалить файл (т.е. скриншот сразу в буфер обмена)

      вам не кажется расточительным создавать файл лишь ради того, чтобы через мгновение удалить? или он создаётся в tmpfs?


      1. aragaer
        02.11.2025 09:08

        Видимо когда я это писал, у scrot нельзя было указать имя файла для вывода. Теперь можно, причем можно и сразу в stdout, что позволило сильно упростить скрипт.


      1. randomsimplenumber
        02.11.2025 09:08

        расточительным

        Для скрипта, который запускается исключительно руками и исключительно на localhost- пофиг.


  1. ThingCrimson
    02.11.2025 09:08

    Спасибо за интересные примеры скриптописательства; и большое спасибо за идею выстроить из этого добра некую свою экосистему! Поставил себе в todo перешерстить свои скрипты с подобным подходом.


    1. beskov
      02.11.2025 09:08

      Думаете Evan Hahn тут читает?


      1. ThingCrimson
        02.11.2025 09:08

        Скорее всего нет (хотя, с учётом возможностей современных поисковиков да браузеров с автопереводом — зуб не дам). Но желание выразить благодарность подавлять не стал, плюс это мой маленький вклад в повышение рейтингов статьи — и, соответственно, больше комментариев, хороших и разных!