<===

ProNotes

2026-02-23 17:30:11
## Скрипт для переключения OpenVPN‑клиентов (Manjaro, systemd)

Конфиги: `/etc/openvpn/client/*.conf`  
Сервисы: `openvpn-client@NAME.service` (NAME = имя конфига без `.conf`).

### Скрипт `/usr/local/bin/vpnsw`

```bash
#!/usr/bin/env bash

SERVICE_PREFIX="openvpn-client"
CONF_DIR="/etc/openvpn/client"

get_active_vpn() {
    systemctl list-units --type=service --state=running \
        | awk -v p="${SERVICE_PREFIX}@" '$1 ~ "^"p {print $1}' \
        | sed -E "s/^${SERVICE_PREFIX}@([^\.]+)\.service/\1/" | head -n1
}

show_status() {
    local active
    active="$(get_active_vpn)"
    echo "Текущий VPN-сервис: ${active:-нет}"
    ip -brief a show tun0 2>/dev/null || echo "tun0: не найден"
    echo
}

stop_active() {
    local active
    active="$(get_active_vpn)"
    if [[ -n "$active" ]]; then
        echo "Останавливаю ${SERVICE_PREFIX}@${active}.service ..."
        sudo systemctl stop "${SERVICE_PREFIX}@${active}.service"
    else
        echo "Активных ${SERVICE_PREFIX}@*.service не найдено."
    fi
}

stop_all() {
    echo "Останавливаю все ${SERVICE_PREFIX}@*.service ..."
    sudo systemctl stop "${SERVICE_PREFIX}"@*.service 2>/dev/null || true
    sleep 2
    show_status
}

start_vpn() {
    local name="$1"
    if [[ -z "$name" ]]; then
        echo "Не указано имя профиля."
        return 1
    fi
    if [[ ! -f "${CONF_DIR}/${name}.conf" ]]; then
        echo "Конфиг ${CONF_DIR}/${name}.conf не найден."
        return 1
    fi

    echo "Стартую ${SERVICE_PREFIX}@${name}.service ..."
    sudo systemctl start "${SERVICE_PREFIX}@${name}.service"

    sleep 2

    sudo systemctl status "${SERVICE_PREFIX}@${name}.service" --no-pager -n 5
}

menu_mode() {
    while true; do
        show_status

        shopt -s nullglob
        local files=("${CONF_DIR}"/*.conf)
        shopt -u nullglob

        if (( ${#files[@]} == 0 )); then
            echo "В ${CONF_DIR} нет *.conf"
            return 1
        fi

        local names=()
        local f
        for f in "${files[@]}"; do
            f="${f##*/}"    # io.conf
            f="${f%.conf}"  # io
            names+=("$f")
        done

        # 1: без VPN, далее профили, последний пункт — Выход
        local options=("без VPN" "${names[@]}" "Выход")
        PS3="Выбери VPN (1 — без VPN, ${#options[@]} — выход): "

        select opt in "${options[@]}"; do
            if [[ "$opt" == "без VPN" ]]; then
                stop_all
                break          # обновить статус и меню
            fi

            if [[ "$opt" == "Выход" ]]; then
                echo "Выход."
                return 0
            fi

            if [[ -z "$opt" ]]; then
                echo "Неверный выбор: $REPLY"
                break          # перерисовать меню
            fi

            local name="$opt"
            stop_active
            start_vpn "$name"
            echo
            break              # вернуться в while -> обновить статус и меню
        done
    done
}

main() {
    local VPN_NAME="$1"

    # режим: без VPN с CLI
    if [[ "$VPN_NAME" == "0" || "$VPN_NAME" == "none" || "$VPN_NAME" == "off" ]]; then
        stop_all
        exit 0
    fi

    # режим: сразу включить профиль
    if [[ -n "$VPN_NAME" ]]; then
        stop_active
        start_vpn "$VPN_NAME"
        show_status
    else
        # интерактивное меню
        menu_mode
    fi
}

main "$@"

```

### Установка

```bash
sudo nano /usr/local/bin/vpnsw    # вставить скрипт
sudo chmod +x /usr/local/bin/vpnsw
```

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

```bash
vpnsw          # меню: список профилей по *.conf
vpnsw io       # сразу переключиться на io
vpnsw uqu      # сразу на uqu
```   
← Previous Next →
Back to list