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.
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.
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
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
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.
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
).
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
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