如何从存储在变量中的特定行号运行 awk

如何从存储在变量中的特定行号运行 awk

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 

相关内容