web-dev-qa-db-fra.com

Extraction de l'adresse IP d'un texte et rangez-la dans une variable

J'ai un fichier texte nommé ABD présenté ci-dessous.

48878 128.206.6.136
34782 128.206.6.137
12817 23.234.22.106

Je veux extraire une adresse IP du texte et le stocker dans une variable et utiliser à d'autres fins.

J'ai essayé cela.

for line in `cat abd`
do

ip=`grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' $line`

echo $ip

done

Je reçois une erreur comme suit

grep: 34782: No such file or directory

grep: 128.206.6.137: No such file or directory

grep: 12817: No such file or directory

grep: 23.234.22.106: No such file or directory

Je ne sais pas ce qui ne va pas ici. Toute aide serait appréciée.

5
Swatesh Pakhare

Vous avez presque eu raison de la première fois. La réponse awk est bonne pour votre cas spécifique, mais la raison pour laquelle vous receviez une erreur est parce que vous essayiez d'utiliser grep comme s'il recherchait un fichier au lieu d'une variable.

En outre, lorsque vous utilisez des expressions régulières, j'utilise toujours grep -E juste pour être en sécurité. J'ai également entendu dire que les backtsks sont obsolètes et devraient être remplacés par $().

La bonne façon de grep une variable avec des coquilles prenant en charge hersers utilise la redirection d'entrée avec 3 de ces gars: <, donc votre commande grep ($ip variable) devrait effectivement se lire comme suit:

ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"

S'il s'agit d'un fichier que vous recherchez, j'utilise toujours une boucle while _, car il est garanti d'allumer la ligne de ligne, alors que for boucles sont souvent jetées s'il y a une bizarre espacement. Vous mettez également en œuvre une utilisation inutile de cat qui pourrait également remplacer par la redirection d'entrée. Essaye ça:

while read line; do
  ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
  echo "$ip"
done < "abd"

En outre, je ne sais pas quel système d'exploitation ou de version de grep vous utilisez, mais le caractère d'échappement que vous aviez avant que les accolades bouclés ne soient généralement pas nécessaires chaque fois que j'ai utilisé cette commande dans le passé. Cela pourrait provenir d'utiliser grep -E ou parce que je l'utilise dans des devis et sans backticks - je ne sais pas. Vous pouvez l'essayer avec ou sans et voyez simplement ce qui se passe.

Que vous utilisiez une boucle for boucle ou une boucle while, qui est basée sur laquelle on fonctionne pour vous dans votre situation spécifique et si le temps d'exécution est de la plus haute importance. Cela ne me semble pas si OP essaye d'essayer d'attribuer des variables distinctes à chaque adresse IP, mais qu'il souhaite attribuer une variable à chaque adresse IP dans la ligne afin qu'il puisse l'utiliser dans la boucle elle-même - dans laquelle cas, il n'a besoin que d'une seule variable $ip par itération. Je colle mes armes sur celui-ci.

7
rubynorails

Si l'adresse IP est toujours le deuxième champ de ce fichier, vous pouvez utiliser awk ou cut _ pour l'extraire.

awk '{print $2}' abd

ou

cut -d' ' -f2 abd

Si vous avez besoin de itération via les adresses IP, les boucles habituelles for ou while peuvent être utilisées. Par exemple:

for ip in $(cut -d' ' -f2 abd) ; do ... ; done

ou

awk '{print $2}' abd | while read ip ; do ... ; done

Ou vous pouvez lire toutes les adresses IP dans un tableau:

$ IPAddresses=($(awk '{print $2}' abd))
$ echo "${IPAddresses[@]}"
128.206.6.136 128.206.6.137 23.234.22.106
9
cas

grep recherche des fichiers ou une entrée standard pour les modèles. Vous ne pouvez pas réussir les chaînes de données pour correspondre à la ligne de commande grep. Essaye ça:

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' abd

Si vous avez besoin d'obtenir chaque adresse IP dans une variable:

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' abd |
while read IP
do
    echo "$IP"
done

Test de performance comparatif de la réponse acceptée

La réponse recommande d'exécuter une invocation distincte de grep sur chaque ligne du fichier d'entrée. Voyons comment cela fonctionne avec des fichiers de 1000 à 5000 lignes. Les fichiers abd.1000 et abd.5000 ont été créés en répliquant simplement le fichier exemple d'origine dans la question. Le code d'origine n'a changé que pour prendre le nom de fichier en tant qu'argument de ligne de commande (${1:?}) au lieu de la codée "ABD".

$ wc -l abd.1000 abd.5000
  1000 abd.1000
  5000 abd.5000
  6000 total

Testez le code exemple dans cette réponse sur un fichier de ligne 1000:

$ cat ip-example.sh
#!/bin/sh
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' "${1:?}" |
while read IP
do
    echo "$IP"
done

$ time sh ip-example.sh abd.1000 > /dev/null

real    0m0.021s
user    0m0.007s
sys     0m0.017s
$

Ce qui précède montre que l'exemple de cette réponse a traité un fichier de 1000 lignes en moins de 1/4 de seconde. Voyons maintenant comment l'exemple de la réponse acceptée effectue:

$ cat accepted.sh
#!/bin/bash
while read line; do
  ip="$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' <<< "$line")"
  echo "$ip"
done < "${1:?}"

$ time bash accepted.sh abd.1000 > /dev/null

real    0m3.565s
user    0m0.739s
sys     0m2.936s
$

Hmmm. L'exemple de la réponse acceptée s'exécute en 3 1/2 secondes, environ 169 fois plus lent que le 1/40 deuxième par exemple pour cette réponse.

Laissez-vous l'ante et le test avec 5000 lignes:

$ time sh ip-example.sh abd.5000 > /dev/null

real    0m0.052s
user    0m0.051s
sys     0m0.029s

A propos de deux fois Tant à traiter 5 fois plus de données.

$ time bash accepted.sh abd.5000 > /dev/null

real    0m17.561s
user    0m3.817s
sys     0m14.333s

L'exemple de code dans la réponse acceptée prend presque 5 fois plus long Pour traiter 5 fois plus de données que pour traiter 1000 lignes de données.

Conclusions

L'exemple de la réponse acceptée prend 337 fois plus longtemps Pour traiter un fichier de 5000 lignes que le ip-example.sh code dans cette réponse (les autres réponses sur cette page doivent fonctionner de la même manière à ip-example.h).

6
RobertL

Je vous suggère d'utiliser awk à cette fin. C'est un outil beaucoup plus approprié pour le traitement des colonnes.

xieerqi:$ vi ipAddresses

xieerqi:$ awk '{printf $2" "}' ipAddresses                                     
128.206.6.136 128.206.6.137 23.234.22.106 
xieerqi:$ ARRAY=($(awk '{printf $2" "}' ipAddresses))                          

xieerqi:$ echo ${ARRAY[@]}
128.206.6.136 128.206.6.137 23.234.22.106

xieerqi:$ echo ${ARRAY[1]} ${ARRAY[2]}
128.206.6.137 23.234.22.106

xieerqi:$ cat ipAddresses                                                      
48878 128.206.6.136
34782 128.206.6.137
12817 23.234.22.106
4

Voir la première question dans la FAQ Bash :

while read -r _ ip; do printf "%s\n" "${ip[@]}"; done < abd
128.206.6.136
128.206.6.137
23.234.22.106
3
jasonwryan