Pull to refresh

Comments 72

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

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

Да, я себе завёл похожий, чтобы прокси каждый раз не вбивать. И ещё один для обрезки скачанного, чтобы убрать 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, вырежет из трека указанный кусок и оставит только его, заменив оригинальный файл.

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

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

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

iptables.action

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

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

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

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

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

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

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

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

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

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

Например:
_ssh_05_01_raspberri_pi_5_user1

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

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

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

4) Enter

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

Когда увидел упоминание 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

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

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

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

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

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

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

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

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

Сидит переводчик такой, катает очередную статью откуда-нибудь с Medium, чтобы в блоге корпорации-нанимателя была и дальше активность. Переписывает, старается, тратит силы на это, от него просят лучше и чище, он в этом варится, варится... И тут раз, приятный комментарий! 🌞
Был бы я автором статей, я бы тоже раз или два из любопытства попробовал найти пару фраз из них в переводе. Вдруг аудитория их из вторых рук читает, переводит, свои мысли выражает.

какой переводчик в 2025-м году? скорее редактор перевода от Deepl. вручную писать и переписывать сейчас просто глупо

Пожалуй, правы. Иначе откуда в тексте останется ":memory:" вместо emoji?

А что не так с :memory:? И причем тут эмодзи? Здесь это часть скрипта #!/usr/bin/env bash set -e set -u set -o pipefail exec sqlite3 :memory:

В таком случае извиняюсь.

You can create an in-memory database in SQLite by using the special filename ":memory:" when opening a database connection.

Хм, Deepl переводит слово "launcher" как "лаунчер" ? Не, тут видна рука российского профессионала.

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

Скрытый текст
#!/usr/bin/env python3
"""
Compare two YAML files and generate a patch with differences.
Usage: ./get-yaml-diff.py default-values.yaml custom-values.yaml
"""

import sys
import yaml
from typing import Any


def find_differences(base: dict[str, Any], custom: dict[str, Any], path: str = "") -> dict[str, Any]:
    """Recursively find differences between two dictionaries."""
    differences: dict[str, Any] = {}
    keys = set(base) | set(custom)

    for key in sorted(keys):
        full_path = f"{path}.{key}" if path else key

        if key not in base:
            differences[full_path] = {'default': None, 'custom': custom[key]}
        elif key not in custom:
            differences[full_path] = {'default': base[key], 'custom': None}
        else:
            base_val, custom_val = base[key], custom[key]

            if isinstance(base_val, dict) and isinstance(custom_val, dict):
                differences.update(find_differences(base_val, custom_val, full_path))
            elif base_val != custom_val:
                differences[full_path] = {'default': base_val, 'custom': custom_val}

    return differences


def create_patch(differences: dict[str, Any]) -> dict[str, Any]:
    """Convert flat differences dictionary to nested patch structure."""
    patch: dict[str, Any] = {}

    for dotted_path, info in differences.items():
        value = info['custom']
        if value is None:
            continue

        current = patch
        parts = dotted_path.split('.')
        for key in parts[:-1]:
            current = current.setdefault(key, {})
        current[parts[-1]] = value

    return patch


def load_yaml(filename: str) -> dict[str, Any]:
    """Load YAML file and return its content as a dictionary."""
    try:
        with open(filename, 'r') as f:
            return yaml.safe_load(f) or {}
    except FileNotFoundError:
        print(f"Error: File '{filename}' not found.", file=sys.stderr)
        sys.exit(1)
    except yaml.YAMLError as e:
        print(f"Error parsing YAML file '{filename}': {e}", file=sys.stderr)
        sys.exit(1)


def main():
    """Load YAML files, compute differences, and print patch."""
    if len(sys.argv) != 3:
        print(f"Usage: {sys.argv[0]} default-values.yaml custom-values.yaml", file=sys.stderr)
        sys.exit(1)

    default_file, custom_file = sys.argv[1], sys.argv[2]

    default_values = load_yaml(default_file)
    custom_values = load_yaml(custom_file)

    differences = find_differences(default_values, custom_values)
    patch = create_patch(differences)

    print(yaml.dump(patch, allow_unicode=True, sort_keys=False, default_flow_style=False, indent=2))


if __name__ == "__main__":
    main()

diff <(yq -P file1.yml) <(yq -P file2.yml)

yq - must have при работе с yaml'ами

Это у Вас Terminus? (Шрифт)

Какие-то сомнительные скрипты. Будто человек только-только начал разбираться в командах консоли.

ох сейчас отхвачу...

А можно не для жителей консоли, хоть чутка разъяснить, как это работает?

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

A Вы (ТС и unknown) как это юзаете? Рабочий стол вообще есть? или консоль онли?

Есть и с графикой, и без графики пара VDS. Просто когда дружишь с терминалом - некоторые вещи там делать намного проще.

Дело привычки (и удобства), я думаю. Если настроен запуск терминала по одной клавише, то может быть проще нажать эту клавишу и напечатать reboot, чем искать нужный .bat файл. Особенно с увеличением количества команд.

Ещё какие-то команды работают с текущим каталогом или файлами в нём. Например, как команда serveit у ТС (запустить вёб-сервер в текущем каталоге). Что удобно интегрируется если вся работа изначально ведётся через консоль:

  1. перейти в нужный каталог

  2. запустить serveit

  3. редактировать файлы и наблюдать изменения в браузере

Вместо консоли того же можно достичь при интеграции с файловым менеджером - например, в Total Commander есть User Menu куда можно добавлять свои команды - и им, ЕМНИП, можно передавать имена текущего каталога и выбранных файлов.

Так что, по-моему, это во многом дело привычки/вкуса/удобства.

И, опять же, как UnknownUserMax сказал, на некоторых VPS консольный доступ может присутствовать, а Total Commander - быть недоступен. Тогда возможность написать mkcd ... вместо mkdir ...; cd ... может быть удобна.

Рабочий стол вообще есть? или консоль онли?

За UnknownUserMax не скажу, а ТС пару раз упомянул macOS - насколько я знаю, там нет варианта "консоль онли". Если интересно, расскажу про себя: использую KDE в качестве рабочего стола, после перезагрузки первым приложением запускаю браузер, окна терминала открываю по надобности, но всё равно считаю себя "жителем консоли" (например, чтобы посмотреть фильм с диска, открываю его через ls; ffplay ...).

p.s. А из полезных скриптов могу упомянуть такой алиас:

alias ccat="sed -r '/^\s*(#|$)/d'"

который "очищает" файл от пустых и закомментированных строк. Помогает легко увидеть, например, какие шесть опций устанавливает файл /etc/ssh/sshd_config.

О, спасибо за полезный алиас, утащу к себе в ~/.bashrc! В качестве алаверды могу поделиться таким вот (ls с выводом полного таймстампа файла в UTC):

alias lsut='TZ=UTC ls -gG --time-style=+"%Y-%m-%dz%H:%M:%S"'

завёл себе на русскую ч и английскую x команду shutdown, теперь через ч 50 за одну клавишу ставлю кино и иду спать зная, что ноут отключится

ну и поставил две команды по две буквы py и ph для cd pycharm и phpstorm projects, очень удобно до папки с проектами добираться из терминала

yt-dlp в статье есть... всё

Если используется zsh, то можно

hash -d py="$HOME/projects/pycharm"

а потом до него добираться через

~py

Каждый раз, как вижу упоминание yt-dlp, пытаюсь что-нибудь скачать с ютуба. Ни разу не получилось. Как вам это удаётся? Серьёзно.

Если ютуб не заблокирован, то примерно так:

Он обязательно должен быть свежий. Youtube постоянно меняется, и dlp перестаёт работать пока не обновят. Только что работал.

Собирайте сами из сорцов. В дистрорепах чаще всего уже протухшее.

После однократного wget yt-dlp_linux есть встроенный автоапдейт с гита, ./yt-dlp_linux -U

Может быть, шрифты проверять? Начертание глифов, выравнивание, лигатуры... Хотя тут уже простого алфавита будет мало

Проверить что какой-то символ ascii? Однако многие редакторы умеют “show Non-ASCII symbols”

Заморочились вы знатно. У меня только одна такая штука, которая со мной уже второе десятилетие:

$ cat tarj

#/bin/bash

tar -cjf $1.tar.bz2 $1

Все на что меня хватило это несколько алиасов для гита, которые гору времени экономят...

Отдельная тема это pdftk и различные комбинации - поставить подписи, разъединить, соединить документы. А также что то вроде и многое многое другое

Конвертер

for i in *.m4a; do ffmpeg -i "$i" -c:v copy -c:a libmp3lame -q:a 4 "${i%.*}.mp3"; done

Убрать все не ASCII-символы в файле из KiCAD, который преобразует в Specctra а далее он следует на автороутер Layout:

perl -i.bk -pe 's/[^[:ascii:]]//g;' $1

umount/mount внешние диски

Пробросить RDP от сервера Win подчинённой машины Linux на localhost

ssh -L 8888:192.168.10.10:3389  -p 22 Serv@192.168.10.1

Я где-то лет пять писал программу для себя, в которую аккуратно пристроил все свои утилиты, скрипты и поделки. Идей было много, шёл по пути "комбайн всё-в-одном". Сделал главный экран со всем необходимым, с красивым задником и кнопочками, сбоку -- вывод всякого по типу виджет-панели, сверху -- справка по программе и настройки (всё, что я хотел, всё можно было менять).
Последнее, что я помню: я долго упарывался по кастомным полям ввода (писал свой аналог <datalist>), потом возился с контекстным меню, потом перерисовывал интерфейс для поддержки разных масштабов. На том всё и зависло.

А утилиты и скрипты по-прежнему прекрасно себя чувствуют, с рабочего стола их даже не убирал. Сейчас я больше всего работаю в браузере и командной строке, и вот думаю, как бы их туда пересадить, чтобы не открывать лишнего :)
Про утилиты напишу отдельным комментарием, тут я и так много всего наговорил.

Из тех, что я запускаю регулярно по сей день: отсчёт времени (время берёт из расписания, которое подгружает по сети), парсер записей ВК (за пять лет так с него и не слез, удобно с него посты копировать в HTML и перекидывать на сайт), поиск на сайтах (ввод дублируется в отмеченных полях, можно одним нажатием запустить поиск сразу в 5 поисковиках или новостных порталах, всего я записал себе адреса где-то двух сотен сайтов).

Этот "велосипед" ломается на русском языке, на букве ё.

echo {а..я}
 а б в г д е ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я

Этот "велосипед" ломается на русском языке, на букве ё.

и причем тут русский язык ?

Мои личные скрипты для повседневной работы.

Нужны скрипты на:

  • Утренний подъём без будильника.

  • Комфортное перемещение на работу и обратно.

  • Отправку детей в сад.

  • И готовку еды на утро и вечер.

/sarcasm

этот скрипт = жена. вот 100% инфа

Я слышал, что там поддержку отменили, баги не фиксятся, пожелания доработок игнорятся

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

Я использую группу tr -транслит названий. tr-files, tr-folders и tr-all. Только файлы, только папки и все подряд + рекурсивно.

Интересная какая идея, такого я ещё не встречал. У меня разве что архив или пара файлов рядом меняли имена на транслит, переименовывать сразу всё в папке ещё не приходилось

мои скрипты)

# статус
_() { git status; }

# логи
__() { git log --oneline "${1:-}"; }

# посимвольный change в коммите
sw() { git show --color-words=. "${1:-}"; }

# fetch с удалением всего того что удалили в удаленном репозитории
gtfo() { git fetch origin --prune-tags --prune; }

Для гита у меня такие мелочи:

gt ca [name] [first] [second]        #Checkout common ancestor of two branches 
# переключает на общего предка двух веток 
# часто пригождается чтоб избежать мороки с (потенциальными) конфликтами

gt del                               #Delete local branches 
# удаляет локальные ветки 
# со временем куча мусора накапливается в которой сложно ориентироваться

gt rb <task>                         #Restore branch by task name
# ищет мерж по имени таска и подимает таск-ветку 
# иногда пригождается 

gt diff [options] [source] [target]  #Generate diff by task commits report
# генерирует репорт чего там накоммитили в ветке:)
# Размеры файлов и папок в текущей директории, отсортированно по возрастанию
alias sz='du -sh * | sort -h'
# Запустить web-сервер в текущей директории на порту $1
alias pyhttp='python -m http.server $1'
# Поиск по history
alias hgrep='history | grep $1'

# Вывести содержимое файла без комментариев (работает так же и с stdin)
clean() {
  if [[ -n "$1" ]]; then
    grep -v "^[[:space:]]*#\|^$" "$1"
  else
    cat | grep -v "^[[:space:]]*#\|^$"
  fi
}
# Проверить доступность tcp порта
ports() {
  /bin/ncat/ncat -w 1 -z "$1" "$2"
  if [[ "$?" == "0" ]]; then
    echo "$1:$2 is opened"
  else
    echo "$1:$2 is closed"
  fi
}

Ctrl+r вместо history | grep

А ещё обернуть его в fzf

Ctrl-r вернёт одну строку за раз, а тут весь список

backupfile() {
  if [[ $# -ne 1 ]]; then
    echo "Usage: bak <file>"
    return 1
  fi
  local f="$1"
  if [[ ! -e $f ]]; then
    echo "File not found: $f"
    return 1
  fi
  cp -a "$f" "${f}.$(date +%Y%m%d_%H%M%S).bak"
  echo "Backup created: ${f}.$(date +%Y%m%d_%H%M%S).bak"
}
alias bak=backupfile

Резервная копия файла

Крутой набор, обязательно себе заберу кое-что)0) из подобного у меня сейчас есть

$ p

Переходит в ~/projects

$ p do<TAB>

автодополнением проходит по ~/projects и переходит в него

p <tab>

Выводит список всех директорий в projects.

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

Также logme something - команда генерирует текст вида

dd.MM.YYYY

  • [ ] (HH:mm) something

В файлик, либо дополняет его. Веду на протяжении дня, чтобы вообще быть в курсе чем занимался, либо ответить на вопрос "чем занимался в прошлом месяце" или "когда созванивался с тем разрабом/ПМом/кем угодно"

Стараюсь записывать активность сразу как перехожу к другой, спасает очень часто, тут даже на хабре кто-то писал про подобное

3 года назад писал уже на хабре про showcert, но упомяну.

pipx install showcert

$ showcert habr.ru
IP: 178.248.233.33
Names:
habr.ru habr.ru www.habr.ru
notBefore: 2025-10-09 11:01:02 (25 days old)
notAfter: 2026-01-07 11:01:01 (64 days left)
Issuer: C=US O=Let's Encrypt CN=E8
Tags: [CHAIN-VERIFIED]

Смотреть сертификаты (как по сети HTTPS/IMAP/SMTP/.... так и локальные) - просто и легко. С ним же идет gencert, которым можно делать свои сертификаты.

# ура, вот мы и сами себе CA
gencert --ca "My own CA"

# а вот мы и выпускаем сертификаты!
gencert --cacert My-own-CA.pem example.com

Например, я закрыл на nginx все рабочие сайты от внешнего мира (сгенерил клиентские сертификаты через gencerrt). При том что сами эти приложения написаны плохо, я подозреваю, что имеют уязвимости, но быстро это исправить нет возможности, а клиентскими сертификатами мы получаем защиту от рандомного индонезийского хакера близкую к 100%. Своего рода синяя изолента. Дешево и сердито.

Да, все это можно сделать и через openssl (showcert умеет 1% от функционала openssl и это главная ценность!), но даже как посмотреть дату истечения сертификата на почтовом сервере гугла через openssl - я без гугления не вспомню, а если загуглю - там будет длинная сложная команда. А в showcert все для людей (showcert smtp.google.com:25) и он сам все поймет и сделает STARTTLS для нужного протокола.

Главная идея - юзабилити: простые команды должны быть простыми и очевидными (вы никогда не забудете команду showcert habr.ru). Для более сложных - можно использовать ключики. А еще более сложные функции, которые нужны очень редко - просто не добавлять, чтобы не превращать его в openssl. Это не швейцарский нож, который все делает плохо, а просто удобный нож с открывалкой. Порезать колбасу, открыть пиво - замечательно работает. А вот починить инопланетный звездолет, если потребуется, там придется использовать openssl.

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

можно рассмотреть вариант (публичного?) гит репозитария и делать git clone ... на каждом сервере

Даже не знаю, пригождится ли мне всё это ...

Использую для конвертации всех mp4 видео из папки из Insta360 камеры, видосы ужимаются процентов на 40 без видимой глазу потери качества. К перекодированным видео добавляется нижнее подчеркивание перед расширением "_.mp4", оригинальное видео удаляется.

for i in *.mp4; do ffmpeg -i "$i" -threads 16 -crf 26 -f mp4 -vcodec h264 ./"${i%.*}"_.mp4 && rm "$i"; done


"crf 26" да еще без выставленного пресета? Лихо жмете.

Пара полезных баш-функций для слипов:

Первая позволяет заснуть до определённого времени, например, sleeptill 21:00. Бывает полезно, когда хочешь выполнить какую-нибудь одноразовую команду в конкретное время.

sleeptill() {
    sleep $((($(date -f - +%s- <<<"$1"$' tomorrow\nnow')0)%86400))
}

Вторая работает примерно как обычный sleep , но полезна для длинных слипов в скриптах, т.к. печатает обратный отсчёт, так что понятно, сколько ещё ждать.

sleepc() {
    for i in `seq $1 -1 1` ; do for s in / - \\ \| / - \\ \|; do printf "\r${2:-Sleeping} ($i seconds remaining)... $s"; sleep 0.125; done; printf "\r\033[K"; done
}

Я переболел написанием тыщи скриптов на каждый чих уже давно. Сейчас проще руками набрать что-то не сильно сложное. А сильно сложное - сниппетом (если пользуюсь раз в неделю скажем), или алиасом/функцией.

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

Sign up to leave a comment.

Information

Website
ruvds.com
Registered
Founded
Employees
11–30 employees
Location
Россия
Representative
ruvds