在bash中查找括号之间的字符串
以下是我的代码:在bash中查找括号之间的字符串,bash,Bash,以下是我的代码: #!/bin/bash echo "Enter a website name here : " read name #reads the user input echo "Website name entered : $name" echo "$name" traceroute -I $name read -t lines < <(traceroute -I $name) N=0 # loop to convert the output of "trac
#!/bin/bash
echo "Enter a website name here : "
read name #reads the user input
echo "Website name entered : $name"
echo "$name"
traceroute -I $name
read -t lines < <(traceroute -I $name)
N=0 # loop to convert the output of "traceroute" into array
for i in $(traceroute -I $name);
do
myarray[$N]="$i"
echo "$N = $i"
let "N= $N + 1"
done
echo "${#myarray[@]}" #echoes length of array
echo "The connections made include's the following IP Addresses : "
for ((i=2; i < ${#myarray[@]} ; i=$i+9));
do
echo $str | cut -d "(" -f5 | cut -d ")" -f1
echo ${myarray[${i}]}
done
我希望循环只回显括号之间的文本。因此,173.205.40.26
我不知道该用什么。我一直在研究bash中的正则表达式,但没有发现任何有用的东西。这个难题有多种答案。第一个是你自己做的,只使用
-f2
而不是-f5
:
str='ip4.gtt.net (173.205.40.26) 132.149 ms 129.899 ms 129.892 ms'
echo "$str" | cut -d "(" -f2| cut -d ")" -f1
173.205.40.26
或使用sed
:
echo "$str" | sed 's/.*(//;s/).*//'
sed
这里有两个部分,由分隔代码>。第一部分用空字符串替换所有字符*
和左括号(
),结果是173.205.40.26)132.149 ms 129.899 ms 129.892 ms
;第二部分将结束括号)
和*
后面的所有字符替换为空字符串,从而生成173.205.40.26
或者完全在bash
:
str2=${str//*(/}
str3=${str2//)*/}
echo $str3
像@LjmDullaart一样,我也找到了不同的解决方案。
cut
命令是直接的,我有相同的解决方案:
echo "${str}" | cut -d "(" -f2 | cut -d ")" -f1
对于sed
我的解决方案(记住()
之间的部分并用\1
调用它)有点让人困惑:()
也被sed
使用
echo "${str}" | sed 's/.*(\(.*\)).*/\1/'
# or with the -r flag
echo "${str}" | sed -r 's/.*\((.*)\).*/\1/'
第三种方法是寻找IP地址
echo "${str}" | grep -Eo "[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}"
编辑:
点是通配符,因此最好使用
grep -Eo "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
第一个表单找到129.899
。此字符串与[0-9]{1}.[0-9]{1}.[0-9]{1}.[0-9]{1}
匹配
编辑2:
不那么模棱两可的是(注释为Tx@CharlesDuffy)
在GNU-grep
中使用负回溯
$ str='ip4.gtt.net (173.205.40.26) 132.149 ms 129.899 ms 129.892 ms'
$ grep -o -P '(?<=\().*(?=\))' <<<"${str}"
173.205.40.26
$str='ip4.gtt.net(173.205.40.26)132.149 ms 129.899 ms 129.892 ms'
$grep-o-P'(?如果您真的想使用正则表达式,请使用bash的内置支持:
# our regular expression, in POSIX ERE form
re='[(](.*)[)]'
# our string to test
str='ip4.gtt.net (173.205.40.26) 132.149 ms 129.899 ms 129.892 ms'
# if the string matches the regex, print the first (only) match group
[[ $str =~ $re ]] && echo "${BASH_REMATCH[1]}"
正确发射:
173.205.40.26
要在循环中正确执行此操作,如下所示:
re='[(](.*)[)]'
while IFS= read -r str; do
[[ $str =~ $re ]] && echo "${BASH_REMATCH[1]}"
done < <(traceroute -I "$name")
re='[(](.*)[)]'
而IFS=read-r str;do
[[$str=~$re]]&&echo“${BASH_重赛[1]}”
完成<您可以将问题简化为:输入:ip4.gtt.net(173.205.40.26)132.149 ms 129.899 ms 129.892 ms
所需输出:173.205.40.26
我尝试的:echo$str | cut-d”(“-f5 | cut d”)“-f1
nsregularexpression
标记在这里毫无意义——这是Swift语言中的构造,而不是bash。这是一个非常不可移植的构造,没有什么特别好的理由。我们知道OP是在一个有bash的平台上;我们不知道他们有GNUgrep
,更不用说用(可选,libpcre
-依赖项添加)PCRE支持。@CharlesDuffy我添加了一条关于GNU grep
的注释,感谢您的提醒。:-)嗯。有没有理由每行调用一次grep
,而不是将其移动到流程替换中,并让在读取时迭代其输出?我还希望管道直接从traceroute进入grep
工作。我不知道这一点。traceroute
成本很高,OP可能想要这样做保存它以供以后分析。这有什么效率?这需要一个人从文件或从traceroute
输出循环每行。@iamauser,如果一个人使用内部bash构造循环,而不是启动每行的外部命令,例如grep
,这是相对的事情——如果你正在处理数千个lines你最好用一个grep
处理所有的代码,但是只有几十行(就像你典型的traceroute
一样),使用一个样式的循环会更便宜,并且避免为grep
的启动支付一次成本。嗯,奇怪的是回音和[…]
在while循环中进行匹配
比如说30行(30跳trceroute
),比grep traceroute\u outputfile
快。需要时间
分析。@iamauser,这有什么奇怪的?echo
是内置在shell中的;[[
。调用它们只是从C程序调用一个C函数。grep
是一个外部命令——它需要一个fork()
为它创建一个新的进程树条目,然后是一个exec()
之后,调用ld
以提取它链接到的动态库。运行外部命令需要很多开销——我们通常谈论几十微秒。@iamauser,…因此,在我当前的平台上,时间{((i=0;i/dev/null
需要0.002s的挂钟——同样是30行。time grep a可能应该用echo“$str”替换echo$str
在sed
案例中。traceroute
有时会在其输出中包含空格*
s;您不希望将其替换为文件名列表(尤其是当前目录中的任何名称包含paren时!)非常感谢您的回答!我只是想知道是否有任何方法可以绕过第三种方法,从而提高网络速度和IP,而不仅仅是IP。因此,如果我使用icmp数据包,我建议[。]
而不是\。
——不那么模棱两可;在引用上下文中,反斜杠可以被视为本地字符串语法的一部分,而不是文字,而方括号不会放在任何地方,无论您处于何种引用上下文中(唯一的例外是完全不带引号的用法,它们可以被解释为glob表达式的一部分,该表达式与文件名中的literal
匹配)。
#!/bin/bash
traceroute -I example.com > connFile
grep -o -P '(?<=\()[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}(?=\))' connFile
# our regular expression, in POSIX ERE form
re='[(](.*)[)]'
# our string to test
str='ip4.gtt.net (173.205.40.26) 132.149 ms 129.899 ms 129.892 ms'
# if the string matches the regex, print the first (only) match group
[[ $str =~ $re ]] && echo "${BASH_REMATCH[1]}"
173.205.40.26
re='[(](.*)[)]'
while IFS= read -r str; do
[[ $str =~ $re ]] && echo "${BASH_REMATCH[1]}"
done < <(traceroute -I "$name")