Skip to content

Instantly share code, notes, and snippets.

@mailinglists35
Created July 9, 2025 13:19
Show Gist options
  • Save mailinglists35/0d4e70328d3d81d2724cce0d676dcbc0 to your computer and use it in GitHub Desktop.
Save mailinglists35/0d4e70328d3d81d2724cce0d676dcbc0 to your computer and use it in GitHub Desktop.
linux any interface traffic rate viewer using only bare tools
#!/bin/bash
# Funcție pentru a afișa utilizarea și a ieși
show_help() {
echo "Utilizare: $0 [-i <interfață>] [-t <secunde>]"
echo " -i <interfață> : Specifică interfața de rețea de monitorizat (ex: eth0, enp0s3)."
echo " Dacă nu este specificată, se va detecta interfața implicită."
echo " -t <secunde> : Intervalul de timp în secunde pentru calculul mediei și refresh (implicit: 1)."
echo " Va afișa media ultimelor <secunde> și se va actualiza la fiecare <secunde>."
echo ""
echo "Exemple:"
echo " $0 # Monitorizează interfața implicită la fiecare secundă"
echo " $0 -i enp0s3 # Monitorizează enp0s3 la fiecare secundă"
echo " $0 -t 5 # Monitorizează interfața implicită la fiecare 5 secunde"
echo " $0 -i eth0 -t 10 # Monitorizează eth0 la fiecare 10 secunde"
exit 0
}
# Valori implicite
INTERFACE=""
INTERVAL=1
# Procesează argumentele din linia de comandă
while getopts "i:t:h" opt; do
case ${opt} in
i ) INTERFACE=$OPTARG ;;
t ) INTERVAL=$OPTARG ;;
h ) show_help ;;
\? ) echo "Opțiune invalidă: -$OPTARG" >&2; show_help ;;
: ) echo "Opțiunea -$OPTARG necesită un argument." >&2; show_help ;;
esac
done
# Verifică dacă INTERVAL este un număr valid
if ! [[ "$INTERVAL" =~ ^[0-9]+$ ]] || [ "$INTERVAL" -eq 0 ]; then
echo "Eroare: Intervalul de timp trebuie să fie un număr pozitiv."
show_help
fi
# --- Funcție pentru a returna scriptul AWK de parsare a rutei ---
get_awk_route_parser() {
cat <<'EOF_AWK'
{
dev_name = ""; metric_val = "0"; # Initialize dev_name as empty, metric_val as 0 (default metric)
for (i=1; i<=NF; i++) {
if ($i == "dev") {
dev_name = $(i+1);
}
if ($i == "metric") {
metric_val = $(i+1);
}
}
if (dev_name != "") { # Only dev_name is mandatory
print dev_name " " metric_val;
}
}
EOF_AWK
}
# Detectează interfața implicită dacă nu este specificată
if [ -z "$INTERFACE" ]; then
# Vom colecta toate rutele default găsite, împreună cu interfața și metricul
# Format: "interfață metric"
DEFAULT_ROUTES_CANDIDATES=""
# Stochează scriptul AWK într-o variabilă
AWK_SCRIPT_CONTENT=$(get_awk_route_parser)
# 1. Caută ruta default în tabela 'main' (comportament normal)
# Folosim ip route show (fara 'table main' explicit) pentru a acoperi cazurile in care main e implicita
MAIN_DEFAULT=$(ip route show | awk '/^default/ { print | "cat" }' | awk "$AWK_SCRIPT_CONTENT")
if [ -n "$MAIN_DEFAULT" ]; then
DEFAULT_ROUTES_CANDIDATES="$MAIN_DEFAULT"
fi
# 2. Caută rute default în tabelele custom definite de ip rules
CUSTOM_TABLES=$(ip rule | awk '{
for (i=1; i<=NF; i++) {
if ($i == "lookup" && $(i+1) !~ /^(local|main|default)$/) {
print $(i+1);
}
}
}' | sort -u) # Folosim sort -u pentru a evita duplicaturile
for TABLE_NAME in $CUSTOM_TABLES; do
TABLE_DEFAULT=$(ip route show table "$TABLE_NAME" | awk '/^default/ { print | "cat" }' | awk "$AWK_SCRIPT_CONTENT")
if [ -n "$TABLE_DEFAULT" ]; then
if [ -n "$DEFAULT_ROUTES_CANDIDATES" ]; then
DEFAULT_ROUTES_CANDIDATES="${DEFAULT_ROUTES_CANDIDATES}\n${TABLE_DEFAULT}"
else
DEFAULT_ROUTES_CANDIDATES="$TABLE_DEFAULT"
fi
fi
done
# Acum că avem toți candidații, sortează-i după metric și ia-l pe cel cu metricul cel mai mic
if [ -n "$DEFAULT_ROUTES_CANDIDATES" ]; then
INTERFACE=$(echo -e "$DEFAULT_ROUTES_CANDIDATES" | sort -nk2 | head -n1 | awk '{print $1}')
fi
if [ -z "$INTERFACE" ]; then
echo "Eroare: Nu s-a putut detecta o interfață implicită."
echo "Vă rugăm să specificați una folosind -i <interfață>."
exit 1
fi
echo "Interfață implicită detectată: $INTERFACE"
fi
# Verifică dacă interfața există
if ! ip link show "$INTERFACE" &> /dev/null; then
echo "Eroare: Interfața '$INTERFACE' nu există sau nu este activă."
exit 1
fi
echo "Monitorizare interfață: $INTERFACE | Interval: $INTERVAL secunde"
echo "---------------------------------------------------------------"
echo " Rx (KB/s) | Tx (KB/s) | Total (KB/s)"
echo "---------------------------------------------------------------"
# Inițializarea valorilor anterioare
PREV_RX_BYTES=$(cat "/sys/class/net/$INTERFACE/statistics/rx_bytes")
PREV_TX_BYTES=$(cat "/sys/class/net/$INTERFACE/statistics/tx_bytes")
LAST_TIMESTAMP=$(date +%s)
while true; do
sleep "$INTERVAL"
CURRENT_RX_BYTES=$(cat "/sys/class/net/$INTERFACE/statistics/rx_bytes")
CURRENT_TX_BYTES=$(cat "/sys/class/net/$INTERFACE/statistics/tx_bytes")
CURRENT_TIMESTAMP=$(date +%s)
TIME_DIFF=$((CURRENT_TIMESTAMP - LAST_TIMESTAMP))
# Prevenim împărțirea la zero și resetăm dacă intervalul este prea mic sau negativ (nu ar trebui)
if [ "$TIME_DIFF" -le 0 ]; then
PREV_RX_BYTES=$CURRENT_RX_BYTES
PREV_TX_BYTES=$CURRENT_TX_BYTES
LAST_TIMESTAMP=$CURRENT_TIMESTAMP
continue
fi
# Calculează ratele în bytes/secundă
RX_RATE_BPS=$(( (CURRENT_RX_BYTES - PREV_RX_BYTES) / TIME_DIFF ))
TX_RATE_BPS=$(( (CURRENT_TX_BYTES - PREV_TX_BYTES) / TIME_DIFF ))
# !!! Modificare AICI: Forțează locales pentru calcule și printf !!!
# Convertește în KB/secundă (rotunjire la 2 zecimale cu printf)
# Folosim bash arithmetic pentru a calcula valorile intregi pentru a minimiza dependintele,
# apoi bc pentru float.
RX_RATE_KBPS=$(LC_NUMERIC=C bc -l <<< "scale=2; $RX_RATE_BPS / 1024")
TX_RATE_KBPS=$(LC_NUMERIC=C bc -l <<< "scale=2; $TX_RATE_BPS / 1024")
TOTAL_RATE_KBPS=$(LC_NUMERIC=C bc -l <<< "scale=2; ($RX_RATE_BPS + $TX_RATE_BPS) / 1024")
# Afișează rezultatele formatat
LC_NUMERIC=C printf "%10.2f | %11.2f | %12.2f\n" "$RX_RATE_KBPS" "$TX_RATE_KBPS" "$TOTAL_RATE_KBPS"
# Actualizează valorile anterioare pentru următoarea iterație
PREV_RX_BYTES=$CURRENT_RX_BYTES
PREV_TX_BYTES=$CURRENT_TX_BYTES
LAST_TIMESTAMP=$CURRENT_TIMESTAMP
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment