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

DEK*_*KER 5 grep bash sed awk text-processing

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

我想出了这个,但正如你所见,存在很大的问题

   trimLineNum=$(cat "${varFileLog}" | grep -m1 -n "c")
   echo "c is at line #"${trimLineNum}
Run Code Online (Sandbox Code Playgroud)

输出将是:

c is at line #1:abc
Run Code Online (Sandbox Code Playgroud)

问题:

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

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

Phi*_*pos 8

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

sed -n '/^c/{=;q;}'
Run Code Online (Sandbox Code Playgroud)

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

sed '/^c/!d;=;Q'
Run Code Online (Sandbox Code Playgroud)


lau*_*hub 7

存在多种解决方案

与 AWK

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

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

使用 grep + 过滤

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

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

关于性能

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

grep -m1 -n '^c' "${varFileLog}" | cut -d: -f1
Run Code Online (Sandbox Code Playgroud)


Ste*_*itt 4

您需要grep通过将匹配锚定到行的开头来告诉 \xe2\x80\x9cthat 应该位于行的开头 \xe2\x80\x9d 约束^

\n
trimLineNum=$(grep -m1 -n -- '^c' "${varFileLog}")\n
Run Code Online (Sandbox Code Playgroud)\n

然后对 \xe2\x80\x99s 输出进​​行后处理grep以仅保留行号:

\n
trimLineNum=$(grep -m1 -n -- '^c' "${varFileLog}")\ntrimLineNum="${trimLineNum%%:*}"\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n