Как настроить удобный поиск и запуск команд терминала и сессий SSH в Tmux с помощью плагина FZF смотрите под спойлером:
Спойлер :)
Сразу напомню, что по умолчанию клавиша prefix
в Tmux это сочетание клавиш Ctrl-b
⌨️
Вариант №1 - установка моей конфигурации tmux
Предварительные требования:
- Любой моноширный иконочный Powerline шрифт⚡️, например, из проекта Nerd fonts. Я предпочитаю шрифт Hack Nerd Font Mono. Шрифт необходимо поместить по пути
/usr/share/fonts/
либо отдельно для пользователя в~/.local/share/fonts/
и применить его к терминалу; - Любой эмулятор терминал🧑💻, с поддержкой TrueColor и темы Nord, например, Gnome-terminal или Guake;
- (Опционально) Интерактивная командная оболочка💻, например, Zsh + Oh-My-Zsh с темой agnoster.
Установка конфига из моего GitHub:
sudo apt update && sudo apt install -y git xclip fzf tmux
git clone https://github.com/r4ven-me/tmux.git ~/.config/tmux
tmux new -s Work
Первый запуск займет время.
Проверяем работу поиска команд/сессий клавишами.
Вариант №2 - установка и настройка плагина FZF отдельно
Устанавливаем необходимые утилиты:
sudo apt update && sudo apt install -y git xclip fzf tmux
Открываем на редактирование конфиг:
mkdir -p ~/.config/tmux/
nvim ~/.config/tmux/tmux.conf
Вставляем следующий код:
# Параметры FZF
set-environment -g TMUX_FZF_OPTIONS "-p -w 65% -h 35% -m"
# Быстрые команды через prefix+Ctrl-b
bind-key C-b run-shell "
command_list="~/.config/tmux/commands.list"
command=\$(cat \$command_list | fzf-tmux \$TMUX_FZF_OPTIONS --reverse --prompt=\"⚡️ Command: \") && \
tmux send-keys \"\${command#*] }\" || \
exit 0
"
# Быстрый запуск SSH сессии из ~/.ssh/config через prefix+Shift-b
bind-key B run-shell "
host=\$(grep -E \"^Host \" ~/.ssh/config | sed \"s/^Host //\" | fzf-tmux \$TMUX_FZF_OPTIONS --reverse --prompt=\"🌐 SSH: \") && \
tmux new-window -n \"SSH [\$host\"] \"ssh \$host\" || \
exit 0
"
# активация плагина FZF
set -g @plugin 'sainnhe/tmux-fzf'
# эта строка обязательно должна быть последней!
run '~/.config/tmux/plugins/tpm/tpm'
Создаем файл commands.list со списком нужных команд:
nvim ~/.config/tmux/commands.list
Указываем команды построчно. Пример:
ps --sort=-%cpu -eo user,pid,ppid,state,comm | head -n6
ps --sort=-%mem -eo user,pid,ppid,state,comm | head -n6
du -h / 2> /dev/null | sort -rh | head -n 20
Если вы хотите добавить комментарий к команде, сделайте это в квадратных скобках до самой команды + пробел между ними. Пример:
[ps top5 cpu] ps --sort=-%cpu -eo user,pid,ppid,state,comm | head -n6
[ps top5 mem] ps --sort=-%mem -eo user,pid,ppid,state,comm | head -n6
[du top20] du -h / 2> /dev/null | sort -rh | head -n 20
Теперь устанавливаем пакетный менеджер tpm
и запускаем установку плагина FZF:
git clone https://github.com/tmux-plugins/tpm ~/.config/tmux/plugins/tpm
tmux new -s Work '~/.config/tmux/plugins/tpm/bin/install_plugins'
Готово. Создаем новую сессию:
tmux new -s Work
Если необходимо задать дополнительные параметры FZF, то делается это через специальную переменную окружения TMUX_FZF_OPTIONS.
Ранее мы уже задали ее прямо в конфиге tmux.
Например, следующие значения задают пользовательские параметры размера всплывающего окна и цветовую палитру Nord:
set-environment -g TMUX_FZF_OPTIONS "
-p -w 65% -h 35% -m
--exact
--color=fg:#e5e9f0,bg:#2e3440,hl:#81a1c1
--color=fg+:#e5e9f0,bg+:#2e3440,hl+:#81a1c1
--color=info:#eacb8a,prompt:#bf6069,pointer:#b48dac
--color=marker:#a3be8b,spinner:#b48dac,header:#a3be8b
--color=border:#5e81ac
--border=rounded
"
Проверяем работу поиска команд/сессий клавишами.
prefix+Ctrl-b
(команды):prefix+Shift-b
(SSH хосты):
Пример заполнения конфига SSH
Создаем/открываем файл клиентского конфига SSH со списком хостов:
nvim ~/.ssh/config
Заполняем его примерно так:
Host local
HostName localhost
User ivan
Port 22
Host test
HostName test.r4ven.me
User ivan
Port 2222
Подробнее про тонкую настройку клиента SSH мы говорили в этой статье.
Собственно, сам список команд:
## Process Management
# показать топ-5 процессов по CPU
ps --sort=-%cpu -eo user,pid,ppid,state,comm | head -n6
# показать топ-5 процессов по памяти
ps --sort=-%mem -eo user,pid,ppid,state,comm | head -n6
# показать дерево процессов
ps -axf -eo user,pid,ppid,state,comm
# показать зомби-процессы
ps -eo user,pid,ppid,state,comm | awk '$4=="Z" {print $3}'
# показать команду родительского процесса
ps -o pid,command --ppid 698
# показать дерево cgroups systemd
systemd-cgls
# показать иерархию процессов в виде дерева
pstree -p -t -n -C age
# вывести исполняемые бинарники всех процессов пользователя
for pid in $(ps -u $USER -o pid); do exe=$(readlink -f /proc/$pid/exe 2>/dev/null); if [ "$exe" ]; then echo "$pid: $exe"; fi; done | awk '{print $2}' | sort -u
## System Monitoring
# показать точки монтирования с заполнением >80%
df -h | awk '$5 ~ /^8[0-9]%/ {print $6}'
# показать топ-20 по использованию диска
du -h / 2> /dev/null | sort -rh | head -n 20
# показать открытые файлы в директории
lsof +D /opt
# показать аптайм в unixtime
date -d "$(uptime -s)" +%s
# показать топ-10 команд из истории bash
history | awk '{print $2}' | sort | uniq -c | sort -rn | head
# показать процессы, использующие swap
for file in /proc/*/status ; do awk '/VmSwap|Name/{printf $2 " " $3}END{ print ""}' $file; done | sort -k 2 -n -r | head -n 10
# показать значение swappiness
cat /proc/sys/vm/swappiness
# показать OOM score для процессов
printf "PID\tOOM Score\tOOM Adj\tCommand\n"; while read -r pid comm; do [ -f /proc/$pid/oom_score ] && [ $(cat /proc/$pid/oom_score) != 0 ] && printf "%d\t%d\t\t%d\t%s\n" "$pid" "$(cat /proc/$pid/oom_score)" "$(cat /proc/$pid/oom_score_adj)" "$comm"; done < <(ps -e -o pid= -o comm=) | sort -k 2nr
# мониторинг IO активности
iotop -o -P -d 5
# извлечь IP-адреса из лога
grep -a -E '([0-9]{1,3}\.){3}[0-9]{1,3}' /var/log/nginx/access.log
## Scheduling
# добавить задание в cron
{ crontab -l; echo "0 3 * * 0 ls -l &> dirs.txt"; } | crontab -
## Networking
# показать прослушиваемые порты
ss -tuln | awk '{print $5}' | grep -Eo ':[0-9]+$' | sort -t: -k2 -n -u
# игнорировать ICMP-пинги
echo 1 | sudo tee /proc/sys/net/ipv4/icmp_echo_ignore_all
# iptables: отслеживать ICMP-запросы
iptables -A INPUT -p icmp --icmp-type echo-request -m recent --set --name PING_LIST
# iptables: ограничить ICMP-запросы
iptables -A INPUT -p icmp --icmp-type echo-request -m recent --update --seconds 10 --hitcount 5 --name PING_LIST -j DROP
# nftables: заменить правило
nft replace rule inet filter input handle 23 'tcp dport 2222 accept comment "Allow SSH"'
# проверить порт через curl
curl -v telnet://10.11.12.13:1234
# проверить порт через echo
echo > /dev/tcp/r4ven.me/443 && echo "open" || echo "unavailable"
# проверить порт через openssl
openssl s_client -connect r4ven.me:443
## Packet Capture
# захват пакетов по хосту и порту
tcpdump -i any -nn -q dst host 10.11.12.13 and dst port 443
# захват пакетов в файл
sudo tcpdump -nn -i any host 10.11.12.13 -w ./tcpdump.pcap
# захват пакетов в stdout
sudo tcpdump -nn -i any host 10.11.12.13 >> ./tcpdump.txt
# чтение pcap дампа
sudo tcpdump -qns 0 -X -r ./tcpdump.pcap | less
## Encryption / Certificates
# зашифровать tar через openssl
tar -czf - /var/log/apt | openssl enc -aes-256-cbc -pbkdf2 -e -out ./logs.tar.gz.enc
# расшифровать файл через openssl
openssl enc -aes-256-cbc -pbkdf2 -d -in ./logs.tar.gz.enc -out ./logs.tar.gz
# подключиться к серверу через openssl
openssl s_client -connect r4ven.me:443
# показать сертификат удалённого сервера
openssl s_client -connect r4ven.com:443 < /dev/null 2> /dev/null | openssl x509 -text
# показать альтернативный сертификат
openssl s_client -connect r4ven.me:443 -servername r4ven.me < /dev/null 2>/dev/null | openssl x509 -text
# показать локальный сертификат
openssl x509 -in ./ca-cert.pem -text -noout
# зашифровать файл через GPG
gpg --batch --passphrase-file /path/to/password_file --symmetric --cipher-algo AES256 example.txt
## DNS / Network Tools
# запрос через dig (по умолчанию)
dig r4ven.me +short +answer +identify
# запрос через альтернативный DNS
dig @8.8.8.8 r4ven.me +short +answer +identify
# nmap: проверка TCP порта
nmap 10.11.12.13 -p 22
# nmap: проверка UDP порта
nmap -sU 10.11.12.13 -p 53
## Docker
# создать docker-сеть
docker network create --opt com.docker.network.bridge.name=br-monitoring --opt com.docker.network.enable_ipv6=false --driver bridge --subnet 172.22.22.0/24 --gateway 172.22.22.1 monitoring_network
# подключиться к сети контейнером
docker run -it --rm --network swarm_network alpine sh
# собрать docker-образ
docker build -t r4venme/test .
# сборка multiarch образа
docker buildx create --use && docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t r4venme/test:1.0 .
# запустить multitool контейнер
docker run --rm -it --network=container:test --pid container:test wbitt/network-multitool:alpine-extra bash
## Git
# инициализировать репозиторий и добавить remote
git init --initial-branch=main && git remote add origin ssh://git@github.com/r4ven-me/reponame.git
# инициализировать git с конфигом пользователя
git init --initial-branch=main && git config user.name "Ivan Cherniy" && git config user.email "kar-kar@r4ven.me" && git remote add origin ssh://git@github.com/r4ven-me/reponame.git
# отправить изменения в репозиторий
git add . && git commit -m 'Upd' && git push
## File Management
# заменить текст в файле на месте
sed -i.bak 's/old_text/new_text/g' file.txt
# изменить права на файлы
find /path -type f -exec chmod 644 {} \;
# изменить права на директории
find /path -type d -exec chmod 755 {} \;
# установить ACL для пользователя
setfacl -m u:ivan:rwx /opt/mydata
## Web
# скачать файл через curl
curl -fsSL https://raw.githubusercontent.com/r4ven-me/dots/main/.zshrc -o ~/.zshrc
# трассировка HTTP-запроса
curl --trace-ascii trace.txt r4ven.me
## Users and groups
# добавить системную группу
addgroup --system --gid 1995 zabbix
# добавить системного пользователя
adduser --system --gecos 'Zabbix monitoring system' --disabled-password --uid 1997 --ingroup zabbix --shell /sbin/nologin --home /opt/zabbix/zabbix_data zabbix
## Systemd
# отредактировать unit-файл
systemctl edit --full --force unitname.service
# показать параметры system.slice
systemctl show system.slice
# показать параметры юнита
systemctl show unit_name
# проверить статус службы
systemctl is-active --quiet cron
# перезапустить службу с отладкой
sudo SYSTEMD_LOG_LEVEL=debug systemctl restart systemd-networkd
# показать cgroups systemd
sudo systemd-cgls
# top по cgroups
sudo systemd-cgtop -d 3
## Sysrq
# показать справку SysRq
echo h | sudo tee /proc/sysrq-trigger | grep 'sysrq: HELP' /var/log/kern.log
# выполнить перезагрузку через SysRq
echo b > /proc/sysrq-trigger
## Ansible
# получить факты узла
ansible debian12-vpn -m setup -a 'filter=os_family,distribution_version'
# запустить playbook с переменными
ansible-playbook playbook.yml -e 'user_name=root' -e 'user_home=/root'
# запустить команду оболочки
ansible debian12-vpn -b -m shell -a 'systemctl start service_name'
## Asciinema
# записать сессию терминала
asciinema rec demo.cast
# конвертировать запись в GIF
agg demo.cast demo.gif --theme nord --font-family 'Hack Nerd Font Mono' --line-height 1.3 --font-size 18
## Proc
# трассировка exec команд
strace -f -e execve ls -l
# подключиться к PID через strace
strace -p 123
# показать переменные окружения процесса
sudo cat /proc/<pid>/environ | xargs -0 -n1
## Logging
# перенаправить вывод в лог с отметкой времени
exec > >(tee >(logger -t $(basename "${BASH_SOURCE[0]}")) | while IFS= read -r line; do echo "$(date +"[%Y-%m-%d %H:%M:%S.%3N]") - $line"; done | tee -a "${BASH_SOURCE[0]%.*}.log") 2>&1
## SSH
# прямое пробрасывание порта
ssh -q -f -N -L 127.0.0.1:5432:localhost:5432 ivan@test.r4ven.me
# временное пробрасывание порта
ssh -q -f -L 127.0.0.1:5432:localhost:5432 ivan@test.r4ven.me sleep 60
# временное пробрасывание с ключом и опциями
ssh -q -f -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ExitOnForwardFailure=yes -L 127.0.0.1:5432:localhost:5432 test.r4ven.me -p 2222 -l ivan -i ~/.ssh/id_ed25519_test sleep 60
# обратное пробрасывание порта
ssh -q -f -N -R 127.0.0.1:4443:localhost:5001 ivan@test.r4ven.me
## Misc
# сгенерировать псевдослучайную строку
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1