我对bash不太熟练,但积极尝试改进,因此我想请一些专家提出一些建议:)
假设我有以下文本文件:
Some
spam
about which I don't care.
I want following letters:
X1
X2
X3
I do not want these:
X4
X5
Nor this:
X6
But I'd like these, too:
I want following letters:
X7
And so on...
我想获取带有这些字母的行数,因此所需的输出应如下所示:
5 6 7 15
为了阐明这一点:我希望所有与某个正则表达式/\s*X./
匹配的行都在与另一个正则表达式/\sI want following letters:/
匹配之后立即出现
现在我有一个可行的解决方案,我不太喜欢:
cat data.txt | grep -oPz "\sI want following letters:((\s*X.)*)" | grep -oPz "\s*X." > tmp.txt
for entry in $(cat tmp.txt); do
grep -n $entry data.txt | cut -d ":" -f1
done
我的问题是:是否有任何聪明的方法,我不知道的任何工具都具有可以在一行中完成此功能的功能? (我特别不喜欢在这里使用临时文件和循环)
答案 0 :(得分:3)
您可以使用awk
:
awk '/I want following/{p=1;next}!/^X/{p=0;next}p{print NR}' file
多行版本的说明:
#!/usr/bin/awk
/I want following/{
# Just set a flag and move on with the next line
p=1
next
}
!/^X/ {
# On all other lines that doesn't start with a X
# reset the flag and continue to process the next line
p=0
next
}
p {
# If the flag p is set it must be a line with X+number.
# print the line number NR
print NR
}
答案 1 :(得分:1)
以下内容可能会对您有所帮助。
awk '!/X[0-9]+/{flag=""} /I want following letters:/{flag=1} flag' Input_file
如果您不想使用这些行,则上面还将打印包含I want following letters:
的行,然后使用following。
awk '!/X[0-9]+/{flag=""} /I want following letters:/{flag=1;next} flag' Input_file
要在输出中添加行号,请使用以下
。awk '!/X[0-9]+/{flag=""} /I want following letters:/{flag=1;next} flag{print FNR}' Input_file
答案 2 :(得分:0)
首先,让我们对当前脚本进行一些优化:
#!/bin/bash
FILE="data.txt"
while read -r entry; do
[[ $entry ]] && grep -n $entry "$FILE" | cut -d ":" -f1
done < <(grep -oPz "\sI want following letters:((\s*X.)*)" "$FILE"| grep -oPz "\s*X.")
这里有一些评论:
cat file|grep ...
=> grep ... file
for i in $(command)
,这通常是导致多个错误的原因,并且总是a smarter solution。然后,有很多更短的解决方案。这是使用awk
的一个:
$ awk '{ if($0 ~ "I want following letters:") {s=1} else if(!($0 ~ "^X[0-9]*$")) {s=0}; if (s && $0 ~ "^X[0-9]*$") {gsub("X", ""); print}}' data.txt
1
2
3
7