我需要找出给定搜索字符串的第一次出现的行号,该字符串应该位于文本文件的行首,并将其存储在我的 bash 脚本中的变量中。例如我想找到“c”的第一次出现:
abc
bde
cddefefef // this is the line that I need its line number
Casdasd // C here is capital, I dont need it
azczxczxc
b223r23r2fe
Cssdfsdfsdf
dccccdcdcCCDcdccCCC
eCCCCCC
我想出了这个,但正如你所见,有很大的问题
trimLineNum=$(cat "${varFileLog}" | grep -m1 -n "c")
echo "c is at line #"${trimLineNum}
输出将是:
c is at line #1:abc
问题:
- 所以很明显它与第一行匹配,因为该行中有一个“c”。
- 输出还将包括该行的内容!我希望它只是行号
我应该改变什么来解决这些问题?
使用 POSIX
sed
,您可以使用该选项抑制正常输出,然后对于以(pattern )-n
开头的行,使用和uit打印行号:c
^c
=
q
使用 GNU
sed
,您可以使用Q
命令退出而不输出并简化为存在几种解决方案
带 AWK
/^c/
: 匹配以开头的行c
print NR
:打印记录(行)号exit
: 不继续处理我喜欢
awk
,这是我的首选解决方案用 grep + 过滤
'^c'
: 匹配以开头的行c
head -1
: 只显示 grep 结果的第一行sed 's/:.*//'
:删除之后的任何内容:
sed 's/:.*//'
并且cut -d: -f1
在这种情况下具有相同的效果关于性能
这可能比斯蒂芬的解决方案慢:
您需要
grep
通过以下方式将匹配锚定到行首来说明您的“应该在行首”约束^
:然后 post-process
grep
的输出只保留行号:请注意,这
-m
是一个 GNU 扩展(并且对于 GNUgrep
,您需要--
即使^c
不以开头--
,以防$varFileLog
它本身可能以-
GNUgrep
接受选项开头,即使在非选项参数之后也是如此)。通常,您可以将输出通过管道传输到head -n 1
。如果不匹配,第一个命令将返回 false/failure,而第二个命令将始终返回 true,除非您启用了
pipefail
多个 shell 支持的选项,包括bash
.grep 可以打印匹配的行号
-n
or--line-number
所以你可以使用它。然后问题简化为:
您可以使用第一个,
head
第二个使用cut
:在您的示例输出中,您有一些额外的文本 - 我不确定这对您是否重要。但是,当您在 STDOUT 上有一个数字时,为此添加一些字符串前缀是一项简单的任务,我将把它留给您。
使用Raku(以前称为 Perl_6)
或者
或者
输出:
使用Raku 的
-ne
(逐行非自动打印)命令行标志。为了获得行号,state
变量$i
被初始化一次,然后每读取一行就递增。如果识别出行首“c”(通过正则表达式、或index
、或starts-with
),则对字符串"c starts line $i"
进行插值并输出(say
)。注意:低优先级条件
as last
被添加到上面的每个示例中。删除此条件以返回所有匹配的行号,例如:附录:感谢这个 SO answer
first
,这是使用 Raku 的例程获取以“c”开头的第一个零索引行号的快速方法:样本输入:
https://raku.org