bar
我想获取出现后第一次出现的行号foo
。
这应该while
针对整个文件循环运行。像这样:
测试文件:
bar foo
xxx
xxx
xxx
bar
bar
xxx
bar
xxxx
xxx
xx
bar foo
xxx
xxx
bar foo
xxx
xxx
xxx
xxx
xxx
bar
bar
我必须找到后面的第一个foo
,但不与 位于同一行foo
。如果有以下内容,bar foo
我希望找到它。未找到 15 号线。
它应该返回:
linenumbersfoo: 1 12 15
linenumbersbar: 5 15 21
我的代码:
linenumbersfoo=($(awk '/foo/ {print FNR}' test_file.sh))
length="${#linenumbersfoo[@]}"
while [[ $COUNTERR -lt length ]]; do
number=$((${linenumbersfoo["$COUNTERR"]}))
linenumbersbar[$COUNTERR]=$(awk '"$number"<=NR, /bar/ {print FNR;exit;}' test_file.sh)
let COUNTERR=COUNTERR+1
done
echo "${linenumbersfoo[@]}"
echo "${linenumbersbar[@]}"
我得到:
linenumbersfoo: 1 12
linenumbersbar: 1 1
问题似乎是变量number
,如果我写eg5
而不是$number
,它就可以工作。
非常感谢任何帮助!
答案1
由于该字段foo
与该字段一起出现,bar
因此可以创建一个非常清晰的算法:
awk '/bar/ {A[NR]=0} /foo/ {A[NR]++} END {for(i in A) print i,A[i]}' file
1 1
5 0
6 0
8 0
12 1
15 1
21 0
我们可以看到,如果移动第二列,可以得到显示 1 - true 和 0 - fals 的行号:
1
5 1
6 0
8 0
12 0
15 1
21 1
0
我们开始做吧:
awk '/bar/ {A[NR]=0} /foo/ {A[NR]++} END {for(i in A) {if(A[l]) print i; l = i}}' file
5
15
21
胜利!我们将显示第一行并将其转换为所需的形式 - 格式化输出:
awk '
BEGIN {printf "linenumbersfoo:"}
/bar/ {A[NR]=0}
/foo/ {A[NR]++; printf FS NR}
END {printf "\nlinenumbersbar:"
for(i in A) {if(A[l]) printf FS i
l = i}
print ""
}
' file
linenumbersfoo: 1 12 15
linenumbersbar: 5 15 21
答案2
编辑:添加改进以匹配您的编辑...
awk 的一个建议:
BEGIN {
ffoo=0; ffoos=""; fbars="";
}
/foo/ {
ffoo=1; ffoos=ffoos" "NR;
}
/bar/ {
if ((match($0, "foo") == 0) && (ffoo!=0)) {
fbars=fbars" "NR;
ffoo=0;
}
}
END {
print "linenumbersfoo: "ffoos"\n";
print "linenumbersbar: "fbars"\n";
}
答案3
不要在 shell 循环中执行此操作,awk
我们会为您执行此操作。
这是一个awk
脚本,您可以将其存储在脚本文件中并调用awk -f script.awk filename
(修改为与问题的最近编辑一起使用):
BEGIN {
follows["foo"] = "bar"
follows["bar"] = "foo"
}
{
for (i = 1; i <= NF; ++i)
if (lookfor == "") {
if ($i in follows)
lookfor = follows[$i]
} else if ($i == lookfor) {
record[$i] = (record[$i] == "" ? "" : record[$i] OFS ) FNR
lookfor = follows[$i]
}
}
END {
for (i in record)
printf "%s:\t%s\n", i, record[i]
}
在您的示例数据上运行:
$ awk -f script.awk file
foo: 1 12 15
bar: 5 15 21
该脚本设置一个follows
关联列表。该列表表明,当foo
已找到时,我们需要查找bar
,而当bar
已找到时,我们有兴趣foo
再次查找。
该awk
脚本在 中查找字符串lookfor
。最初,它查找数组中的任何键follows
,然后使用该数组设置为lookfor
要查找下一个的字符串。每次它找到要查找的字符串时,都会将当前行号存储在record
相应字符串的关联数组中。
最后record
输出收集到的行号。
看起来时髦的线条
record[$i] = (record[$i] == "" ? "" : record[$i] OFS ) FNR
将行号添加到数组中行号字符串的末尾record
。如果字符串为空,则仅将其设置为当前行号,但如果它已包含某些内容,则在现有字符串和行号之间插入逗号。
答案4
为了富:
for i in `awk '/foo/{print NR}' filename`; do sed -n "$i,/bar/{;=;p}" filename|sed "N;s/\n/ /g"| awk '/foo|bar/'; done|awk '/bar/{print $1}'|perl -pne "s/\n/ /g"| awk '{print "linenumbersfoo: "$0}'
输出:
linenumbersfoo: 1 12
为了酒吧:
for i in `awk '/foo/{print NR}' filename`; do sed -n "$i,/bar/{;=;p}" o1|sed "N;s/\n/ /g"| awk '/foo|bar/'; done|awk '/bar/{print $1}'|perl -pne "s/\n/ /g"| awk '{print "linenumbersfoo: "$0}'
输出:
linenumbersbar: 5 18