2
votes

Utilisation de Ping en parallèle dans un script Bash

J'essaie donc de cingler une plage d'adresses en parallèle dans un script bash, de compter celles qui sont vivantes et de les imprimer. Le script fonctionne pour cingler les adresses et imprimer celles en direct, mais il affiche toujours:

"Il y avait 0 hôtes en ligne et 254 hôtes hors ligne"

Il n'incrémente pas la variable ALIVE dans mon code, peut-être parce que c'est dans un sous-shell? Comment pourrais-je contourner cela? Voici ce que j'ai en ce moment:

#!/bin/bash

if [ $# -eq 3 ]
then
    TOTAL=0 #NEW
    TEMP=mktemp #NEW
    echo -n 'Live hosts:'
    for ((i = $2; i <= $3 && i <= 254; ++i))
    do
        ((++TOTAL))
        ping -c 1 -i 0.2 -w 1 -W 1 $1.$i > /dev/null && echo "    $1.$i" >> $TEMP & #NEW
    done
    wait #NEW
    cat $TEMP

    ALIVE=$(cat $TEMP | wc -l) #NEW
    echo "There were $ALIVE online hosts and $((($TOTAL - $ALIVE))) offline hosts"

    rm $TEMP #NEW
else
    echo "USAGE: pingRange.sh <first 3 octets of ip> <last octet start> <last octet end>"
    echo "    Ex: pingRange.sh 192.168.0 1 254

Remarque: Un exemple d'entrée pour le script est affiché dans la partie "else".

Note 2: Oui Je sais que nmap est plus facile, j'ai déjà écrit un script de travail avec nmap, en essayant d'en faire un pour le ping maintenant.

Note 3: J'ai utilisé un fichier temporaire et cela a fonctionné, le code mis à jour a un commentaire #NEW :

#!/bin/bash

TOTAL=0
ALIVE=0

if [ $# -eq 3 ]
then
    echo -n 'Live hosts:'
    for ((i = $2; i <= $3 && i <= 254; ++i))
    do
        ((++TOTAL))
        ping -c 1 -i 0.2 -w 1 -W 1 $1.$i > /dev/null && ((++ALIVE)) && echo "    $1.$i" &
    done

    echo "There were $ALIVE online hosts and $((($TOTAL - $ALIVE))) offline hosts"
else
    echo "USAGE: pingRange.sh <first 3 octets of ip> <last octet start> <last octet end>"
    echo "    Ex: pingRange.sh 192.168.0 1 254


7 commentaires

Ce serait bien de partager la solution nmap.


C'est la sous-coque, oui. Vous pouvez écrire dans un fichier à la place


Pourquoi ne pas utiliser nmap dans votre script? linux.die.net/man/1/nmap


Duplicate de unix.stackexchange.com/questions/344360/... La solution la plus simple semble être celle de: job1 & code1 = $ !; ...; attendez $ code1; ans = $ ?;


Remarque 3 .. cela a fonctionné .. - vous devriez donc poster cela comme réponse à votre question. Dans votre script TEMP = mktemp TEMP est littéralement la chaîne mktemp , ie. TEMP = "mktemp" . Vous voulez que TEMP = $ (mktemp) exécute la commande mktemp .


@KamilCuk J'ai posté ce que j'ai fait après la note. La réponse que j'ai choisie était plus lisible et avait également une solution qui n'avait pas besoin d'utiliser un fichier temporaire, je l'ai donc sélectionnée comme meilleure réponse à la place.


Lisez la page de manuel. La solution est là.


4 Réponses :


2
votes
live_hosts=$(seq -f "$1.%.0f" "$2" "$3" | xargs -n1 -P0 -- sh -c 'ping -c 1 -i 0.2 -w 1 -W 1 "$1" >/dev/null && echo "$1"' --)
alive=$(echo "$live_hosts" | wc -l)
# well, if just the count matters, add the `| wc -l` to the one liner ..

6 commentaires

Je ne pense pas que ce soit tout à fait vrai; && ne crée pas de sous-shell, & le fait.


Pourquoi ne pas utiliser nmap -sn ... au lieu d'essayer d'écrire un script?


@RedCricket OP a spécifiquement déclaré qu'il avait fait nmap et qu'il était intéressé par une solution bash utilisant ping.


@KamilCuk utilisant nmap -sn est un ping.


@RedCricket Oui, j'ai utilisé nmap -sn dans une autre implémentation, cette question posait spécifiquement sur l'utilisation de la commande ping .


Notez que l'utilisation de la sortie de xargs -P n'est généralement pas sûre: mywiki.wooledge.org/...



1
votes

Je pense que vous pouvez le faire simplement en utilisant wait .

Modifier votre code, quelque chose comme (non testé):

#!/bin/bash

TOTAL=0
ALIVE=0

if [ $# -eq 3 ]
then
    unset pids
    declare -A pids
    echo -n 'Live hosts:'
    for ((i = $2; i <= $3 && i <= 254; ++i))
    do
        ((++TOTAL))
        ping -c 1 -i 0.2 -w 1 -W 1 $1.$i > /dev/null &
        pids[$i]=$!
    done

    for i in "${!pids[@]}"
    do
        wait ${pids[$i]} && ((++ALIVE)) && echo "    $1.$i"
    done

    echo "There were $ALIVE online hosts and $((($TOTAL - $ALIVE))) offline hosts"
else
    # ...
  • unset / declare - juste pour être sûr
  • ping ... & exécute toujours la commande en arrière-plan
  • pids [$ i] = $! enregistre son pid
  • for ... boucle sur les touches
  • wait $ {pids [$ i]} renvoie l'état de sortie une fois cmd terminé
  • && ... fait la même chose que précédemment


0 commentaires

0
votes

En utilisant GNU Parallel, cela ressemble à ceci:

pingrange() {
  three=$1
  start=$2
  end=$3
  total=$(($end-$start))
  online="$(seq $start $end |
    parallel -j0 "ping -c 1 -i 0.2 -w 1 -W 1 $three.{} > /dev/null && echo '    $three.{}'")"
  alive=$(echo "$online" | wc -l)
  offline=$((total-alive))
  echo "$online"
  echo "There were $alive online hosts and $offline offline hosts"
}

Il fonctionne correctement même si votre système ne peut pas exécuter tous les ping s en parallèle en même temps (par exemple si votre table de processus est presque pleine).


0 commentaires

0
votes

Ou vous pouvez simplement utiliser:

fping -g $three.$start $three.$end

et travailler sur la sortie. Voir man fping pour d'autres options.

p>


0 commentaires