Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在bash中查找括号之间的字符串_Bash - Fatal编程技术网

在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的平台上;我们不知道他们有GNU
grep
,更不用说用(可选,
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")