bash 从变量字符串中提取ip地址

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24851449/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 10:55:15  来源:igfitidea点击:

extract ip address from variable string

bashunix

提问by mk_89

I'm trying to create a bash script which will be able to change the "allow from" ip address in the phpmyadmin command file (which im still not sure is possible to do) and restart apache

我正在尝试创建一个 bash 脚本,该脚本将能够更改 phpmyadmin 命令文件中的“允许来自”IP 地址(我仍然不确定是否可以这样做)并重新启动 apache

I'm currently trying to extract an ip address from a variable and after searching the web I still have no clue, here is what I have so far...

我目前正在尝试从变量中提取 ip 地址,在网上搜索后我仍然不知道,这是我目前所拥有的......

#bash shell script
#!/bin/bash

clear
echo "Get client IP address"
ip=$(last -i)
echo $ip

exit
echo "restart apache"
/etc/init.d/apache2 reload

I've tried adding the following line with no luck

我尝试添加以下行但没有运气

ip=$(head -n 1 $ip)

If anyone can tell me how I can extract the first instance of an IP address from the variables $ip I would appreciate it very much.

如果有人能告诉我如何从变量 $ip 中提取 IP 地址的第一个实例,我将不胜感激。

回答by Cyrus

ip=$(last -i | head -n 1 | awk '{print }')

Update:

更新:

ip=$(last -i | grep -Pom 1 '[0-9.]{7,15}')

回答by konsolebox

You can use grepwith read:

你可以用grepread

read ip < <(last -i | grep -o '[0-9]\+[.][0-9]\+[.][0-9]\+[.][0-9]\+')
read ip < <(last -i | grep -Eo '[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+')
  • \bmay also be helpful there. Just not sure about its compatibility.
  • \b在那里也可能有帮助。只是不确定它的兼容性。

And yet another:

还有一个:

ip=$(last -i | gawk 'BEGIN { RS = "[ \t\n]"; FS = "." } /^([0-9]+[.]){3}[0-9]+$/ && ! rshift(or(or(, ), or(, )), 8) { print ; exit; }')

回答by anubhava

To get the first instance you can just do:

要获得第一个实例,您可以执行以下操作:

ip=$(last -i -1 | awk '{print }')

回答by terdon

I'd just do

我只想做

ip=$(last -i -1 | grep -Po '(\d+\.){3}\d+')

The above uses grepwith Perl Compatible Regular Expressions which lets us use \dfor digits. The regular expression looks for three repetitions of [0-9]followed by a dot (so, for example 123.45.123), then another stretch of digits. The -oflag causes grepto only print the matching line.

以上grep与 Perl 兼容的正则表达式一起使用\d,这让我们可以使用数字。正则表达式查找三个重复,[0-9]后跟一个点(例如123.45.123),然后是另一段数字。该-o标志导致grep仅打印匹配的行。

This approach has the advantage of working even when the number of fields per line changes (as is often the case, for example with system bootas the 2nd field). However, it needs GNU grep so if you need a more portable solution, use @konsolebox's answerinstead.

这种方法的优点是即使每行的字段数发生变化(通常情况下,例如system boot第二个字段)也能正常工作。但是,它需要 GNU grep,因此如果您需要更便携的解决方案,请改用@konsolebox 的答案

回答by jm666

Or if you're a nitpicker (and have a grep with -P), you can test the next:

或者,如果您是一个挑剔的人(并且有一个 grep -P),您可以测试下一个:

while read -r testline
do
    echo "input :=$testline="
    read ip < <(grep -oP '\b(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))\b' <<< "$testline")
    echo "result:=${ip:=NOTFOUND}="
    echo
done <<EOF
some bla bla 127.0.0.1 some
10.10.10.10
bad one 300.200.300.400
some other bla 127.0.0.1 some another 10.1.1.0
10.10.10.10 10.1.1.0
bad one 300.200.300.400 and good 192.168.1.1

above is empty and no ip here too
EOF

It skips wrong ip adr, like 800.1.1.1so, for the above test prints:

800.1.1.1对于上面的测试打印,它会跳过错误的 ip adr,就像这样:

input :=some bla bla 127.0.0.1 some=
result:=127.0.0.1=

input :=10.10.10.10=
result:=10.10.10.10=

input :=bad one 300.200.300.400=
result:=NOTFOUND=

input :=some other bla 127.0.0.1 some another 10.1.1.0=
result:=127.0.0.1=

input :=10.10.10.10 10.1.1.0=
result:=10.10.10.10=

input :=bad one 300.200.300.400 and good 192.168.1.1=
result:=192.168.1.1=

input :==
result:=NOTFOUND=

input :=above is empty and no ip here too=
result:=NOTFOUND=

The \bis needed to skip matching an ip, like: 610.10.10.10, what is containing a valid ip (10.10.10.10).

\b需要跳过匹配IP,如:610.10.10.10,什么是包含一个有效的IP(10.10.10.10)。

The regex is taken from: https://metacpan.org/pod/Regexp::Common::net

正则表达式取自:https: //metacpan.org/pod/Regexp:: Common:: net

回答by mattst

Since I happen to have needed to do something in the same ballpark, here is a basic regular expression and an extended regular expression to loosly match an IP address (v4) making sure that there are 4 sequences of 1-3 numbers delimited by a 3 '.'.

由于我碰巧需要在同一个范围内做一些事情,这里有一个基本的正则表达式和一个扩展的正则表达式来松散地匹配 IP 地址 (v4),确保有 4 个由 3 分隔的 1-3 数字序列'.'。

# Basic Regular Expression to loosly match an IP address:
bre_match_ip="[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"

# Extended Regular Expression to loosly match an IP address:
ere_match_ip="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"

Of course when matching IP (v4) addresses from a file (say HTML) it's quite easy to inadvertently match a version string or an url which contains versioning as part of its file path. The following is some Awk code I wrote a while ago for use in a Bash script to extract valid unique (no duplicates) IP addresses from a file. It avoids version numbers whether in the text or as part of an url and makes sure the IP numbers are in range.

当然,当从文件(比如 HTML)匹配 IP (v4) 地址时,很容易无意中匹配版本字符串或包含版本控制作为其文件路径一部分的 URL。以下是我不久前编写的一些 Awk 代码,用于在 Bash 脚本中从文件中提取有效的唯一(无重复)IP 地址。它避免在文本中或作为 url 的一部分的版本号,并确保 IP 号在范围内。

I appreciate that this is overkill for the original poster and that it is not tailored for his needs but someone doing a search may come across this answer and find the fairly comprehensive nature of the code useful. The Awk code is thankfully well commented as it uses some slightly obscure aspects of Awk that the casual Awk user would probably not be familiar with.

我很欣赏这对于原始海报来说太过分了,并且它不是为他的需要量身定制的,但是进行搜索的人可能会遇到这个答案并发现代码的相当全面的性质很有用。幸运的是,Awk 代码得到了很好的注释,因为它使用了 Awk 的一些稍微晦涩的方面,而普通的 Awk 用户可能不熟悉这些方面。

awkExtractIPAddresses='
BEGIN {
    # Regex to match an IP address like sequence (even if too long to be an IP).
    # This is deliberately a loose match, the END section will check for IP
    # address validity.
    ipLikeSequence = "[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[0-9.]*";

    # Regex to match a number sequence longer than 3 digits.
    digitSequenceTooLongNotIP = "[0-9][0-9][0-9][0-9]+";

    # Regex to match an IP address like sequence which is a version number.
    # Equivalent to "(version|ver|v)[ .:]*" if "tolower(
ip=$(awk '{if(NR == 1) {print ; exit;}}' < <(last -i))
)" was used. versioningNotIP = "[Vv]([Ee][Rr]([Ss][Ii][Oo][Nn])?)?[ .:]*" ipLikeSequence; # Regexes to match IP address like sequences next to forward slashes, to # avoid version numbers in urls: e.g. http://web.com/libs/1.6.1.0/file.js beginsWithFwdSlashNotIP = "[/]" ipLikeSequence; endsWithFwdSlashNotIP = ipLikeSequence "[/]"; } { # Set line to the current line (more efficient than using
read -ra array < <(last -i)
ip="${array[2]}"
below). line =
read -ra array < <(last -1 -i)
ip="${array[2]}"
; # Replace sequences on line which will interfere with extracting genuine # IPs. Use a replacement char and not the empty string to avoid accidentally # creating a valid IP address from digits on either side of the removed # sections. Use "/" as the replacement char for the 2 "FwdSlash" regexes so # that multiple number dot slash sequences all get removed, as using "x" # could result in inadvertently leaving such a sequence in place. # e.g. "/lib1.6.1.0/1.2.3.4/5.6.7.8/file.js" leaves "/lib1.6.1.0xx/file.js" gsub(digitSequenceTooLongNotIP, "x", line); gsub(versioningNotIP, "x", line); gsub(beginsWithFwdSlashNotIP, "/", line); gsub(endsWithFwdSlashNotIP, "/", line); # Loop through the current line matching IP address like sequences and # storing them in the index of the array ipUniqueMatches. By using ipMatch # as the array index duplicates are avoided and the values can be easily # retrieved by the for loop in the END section. match() automatically sets # the built in variables RSTART and RLENGTH. while (match(line, ipLikeSequence)) { ipMatch = substr(line, RSTART, RLENGTH); ipUniqueMatches[ipMatch]; line = substr(line, RSTART + RLENGTH + 1); } } END { # Define some IP address related constants. ipRangeMin = 0; ipRangeMax = 255; ipNumSegments = 4; ipDelimiter = "."; # Loop through the ipUniqueMatches array and print any valid IP addresses. # The awk "for each" type of loop is different from the norm. It provides # the indexes of the array and NOT the values of the array elements which # is more usual in this type of loop. for (ipMatch in ipUniqueMatches) { numSegments = split(ipMatch, ipSegments, ipDelimiter); if (numSegments == ipNumSegments && ipSegments[1] >= ipRangeMin && ipSegments[1] <= ipRangeMax && ipSegments[2] >= ipRangeMin && ipSegments[2] <= ipRangeMax && ipSegments[3] >= ipRangeMin && ipSegments[3] <= ipRangeMax && ipSegments[4] >= ipRangeMin && ipSegments[4] <= ipRangeMax) { print ipMatch; } } }' # Extract valid IP addresses from $fileName, they will each be separated # by a new line. awkValidIpAddresses=$(awk "$awkExtractIPAddresses" < "$fileName")

I hope this is of interest.

我希望这很有趣。

回答by John B

You could use Awk.

你可以使用 awk。

##代码##

回答by Idriss Neumann

Using bash only :

仅使用 bash :

##代码##

Or :

或者 :

##代码##