我需要找出给定搜索字符串第一次出现的行号,该搜索字符串应该位于文本文件中行的开头,并将其存储在我的 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”。
- 输出还将包括该行的内容!我希望它只是行号
我应该改变什么来解决这些问题?
答案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)