查找 bash 脚本中文本第一次出现的行号

查找 bash 脚本中文本第一次出现的行号

我需要找出给定搜索字符串第一次出现的行号,该搜索字符串应该位于文本文件中行的开头,并将其存储在我的 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

问题:

  1. 显然它与第一行匹配,因为该行中有一个“c”。
  2. 输出还将包括该行的内容!我希望它只是行号

我应该改变什么来解决这些问题?

答案1

使用 POSIX sed,您可以使用选项抑制正常输出,然后对于以(pattern )-n开头的行,使用和uit打印行号:c^c=q

sed -n '/^c/{=;q;}'

使用 GNU sed,您可以使用Q命令退出而不输出并简化为

sed '/^c/!d;=;Q'

答案2

存在多种解决方案

与 AWK

awk '/^c/ { print NR; exit}' "${varFileLog}"
  • /^c/: 匹配以以下开头的行c
  • print NR:打印记录(行)号
  • exit: 不继续处理

如我所愿awk,这是我的首选解决方案

使用 grep + 过滤

grep -n '^c' "${varFileLog}" | head -n1 | sed 's/:.*//'
  • '^c': 匹配以以下开头的行c
  • head -1: 只显示 grep 结果的第一行
  • sed 's/:.*//': 删除之后的任何内容:

sed 's/:.*//'在这种情况下具有cut -d: -f1相同的效果

关于性能

这可能比斯蒂芬的解决方案慢:

grep -m1 -n '^c' "${varFileLog}" | cut -d: -f1

答案3

您需要grep通过以下方式将匹配锚定到行的开头来说明“应该位于行的开头”约束^

trimLineNum=$(grep -m1 -n -- '^c' "${varFileLog}")

然后 post-processgrep的输出仅保留行号:

trimLineNum=$(grep -m1 -n -- '^c' "${varFileLog}")
trimLineNum="${trimLineNum%%:*}"

请注意,这-m是一个 GNU 扩展(对于 GNU grep,您需要--即使^c不以 开头,--以防$varFileLog其本身可能以 开头,-因为 GNUgrep即使在非选项参数之后也接受选项)。标准情况下,您可以将输出通过管道传输到head -n 1

如果没有匹配,第一个命令将返回 false/失败,而第二个命令将始终返回 true,除非您启用pipefail多个 shell(包括bash.

答案4

使用(以前称为 Perl_6)

raku -ne 'state $i; ++$i; say "c starts line $i" and last if m/^c/;'  

或者

raku -ne 'state $i; ++$i; say "c starts line $i" and last if (.index("c").defined && .index("c") == 0);' 

或者

raku -ne 'state $i; ++$i; say "c starts line $i" and last if .starts-with("c");' 

输出:

c starts line 3

-ne使用Raku 的(逐行非自动打印)命令行标志。为了获取行号,state变量$i被初始化一次,然后在每读取一行时递增。如果识别出行首“c”(通过正则表达式、 或index、 或starts-with),则对字符串"c starts line $i"进行插值并输出 ( say)。

注意:低优先级条件as last被添加到上面的每个示例中。删除此条件以返回所有匹配的行号,例如:

~$ raku -ne 'state $i; ++$i; say "c starts line $i" if m/^c/;'  file
c starts line 3
c starts line 10

附录:感谢这个答案,这是使用 Raku 例程获取以“c”开头的第一个零索引行号的快速方法first

~$ raku -e 'say lines.first(* ~~ / ^ c /):k;' file
2

#OR

~$ perl6 -e 'say lines.first(*.starts-with("c")):k;'  file
2

输入示例:

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
cddefefef // this is the line that I need its line number (again)

https://raku.org

相关内容