如何使用grep查找字符的位置?


11

我需要使用grep命令识别字符串中字符的位置。

例如,字符串为RAMSITALSKHMAN|1223333

grep -n '[^a-zA-Z0-9\$\~\%\#\^]'

如何找到|给定字符串中的位置?


必须与grep在一起吗?
Braiam 2014年

Answers:


29

您可以使用-b获取字节偏移量,该偏移量与简单文本的位置相同(但对于UTF-8或类似字符而言则不同)。

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|'
14:|

在上面,我使用-a开关告诉grep使用输入作为文本;对二进制文件进行操作时必需,并且-o开关仅输出匹配的字符。

如果只需要该位置,则可以使用grep仅提取该位置:

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' | grep -oE '[0-9]+'
14

如果输出奇怪,请检查grep是否启用了颜色。您可以通过传递--colors=never给grep或在grep命令前加上一个前缀\(这将禁用任何别名)来禁用颜色,例如:

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' --color=never | \grep -oE '^[0-9]+'
14

对于返回多个匹配项的字符串,请通过管道进行操作head -n1以获得第一个匹配项。

请注意,我在上文中同时使用了两者,请注意,如果仅通过使用别名通过可执行文件(脚本或其他方式)对grep进行了“别名”,则后者将不起作用。


3
现在搜索2;)
Izkata 2014年

谢谢@Izkata,你是对的。我已经更新了我的帖子并添加了缺少的帽子^:)
runejuhl 2014年

1
您使用了哪个版本的grep?我得到0:|了输出-因为0 |是找到行的开头的字节位置。
Alex

从拉伸的Debian GNU @Alex的grep: grep (GNU grep) 2.27。您也许正在使用OS X?
runejuhl

11

尝试:

printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'

输出:

15:|

这将为您提供基于索引-1的职位。


它不起作用:(
user82782 2014年

1
@ user82782:您运行了什么命令?您怎么知道它不起作用?
cuonglm 2014年

printf '%s\n' '|' | grep -o . | grep -n '|'打印10与预期不符。
l0b0

1
@ l0b0:OP没有告诉他想要索引基数0或
1。– cuonglm

我只是说软件开发人员会期望什么。
l0b0

8

如果您使用的是 shell,则可以使用纯粹的内置操作,而无需生成诸如类的外部进程:

$ str="RAMSITALSKHMAN|1223333"
$ tmp="${str%%|*}"
$ if [ "$tmp" != "$str" ]; then
> echo ${#tmp}
> fi
14
$ 

这使用参数扩展来删除|任何字符串出现的所有跟随事件,并将其保存在临时变量中。然后,只需测量临时变量的长度以获得的索引即可|

注意,if正在检查|原始字符串中是否存在。如果不是,则临时变量将与原始变量相同。

还要注意,这提供了从零开始的索引,|在为bash字符串建立索引时通常很有用。但是,如果您需要基于一个的索引,则可以执行以下操作:

$ echo $((${#tmp}+1))
15
$ 

1
可能是最好的答案,这种语法很漂亮,而且当您理解其含义时非常快捷且易于使用,对内核来说万岁
vdegenne

4

您可以使用awk的index函数以字符形式返回匹配发生的位置:

echo "RAMSITALSKHMAN|1223333"|awk 'END{print index($0,"|")}'
15

如果您不介意使用Perl的index功能,则可以处理报告零次,一次或多次出现的字符:

echo "|abc|xyz|123456|zzz|" | \
perl -nle '$pos=-1;while (($off=index($_,"|",$pos))>=0) {print $off;$pos=$off+1}'

仅出于可读性考虑,管道已分为两行。

只要找到目标字符,就index返回基于零(0)的正值。因此,字符串“ abc | xyz | 123456 | zzz |” 解析后返回位置0、4、8、15和19。


为此,awk比grep更有用/更容易。
Archemar 2014年

这仅打印第一个位置,不适用于类似RAMSITALSKHMAN|1|223333
cuonglm的

3

我们也可以使用“ expr match”或“ expr index”

expr match $ string $ substring,其中$ substring是RE。

echo `expr match "RAMSITALSKHMAN|1223333" '[A-Z]*.|'`

而上面的位置将给您,因为它返回匹配的子字符串的长度。

但更具体地说,搜索索引:

mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`

我没有足够的声誉在其他任何地方发表评论。我个人喜欢@Gnouc给出的答案。但是,当我们可以使用'expr'做简单的事情时,为什么要使用awk并使它变得复杂
bluefoggy

@kingsdeb只是一个建议。
Avinash Raj

@kingsdeb:因为(1)awk可以修改解决方案以在文件的每一行上报告此信息(您要做的就是END从JRFerguson的答案中删除从未真正需要的,而Avinash Raj的确已经做到了) ; 然而,要使用expr解决方案来做到这一点,您将需要添加一个显式循环(我所看到的,Gnouc的答案根本不容易适应此操作),并且(2)awk解决方案可以适应于报告所有比expr解决方案更容易在每一行中进行匹配(实际上,Avinash Raj's已经做到了)。
G-Man说'Resstate Monica'14

你为什么要echo `...`在这里使用?
斯特凡Chazelas

这只是在此处显示输出
bluefoggy14年


2

一些替代方案包括:

与Gnouc的答案类似,但带有shell:

echo 'RAMSITALSKHMAN|1223333' |
tr -c \| \\n | 
sh

sh: line 15: syntax error near unexpected token `|
sh: line 15: `|'

seddc可能跨越多个行:

echo 'RAMSITALSKHMAN|1223333' |
sed 's/[^|]/1+/g;s/|/p/;1i0 1+' |dc

15

$IFS...

IFS=\|; set -f; set -- ${0+RAMSITALSKHMAN|1223333}; echo $((${#1}+1))

这也将告诉你如何许多有像...

echo $(($#-1))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.