Unix & Linux Asked on December 1, 2020
I want to get the linenumbers of the first appearance of “bar” after the apperance of “foo”.
This should run in a while loop, for the whole file. Like this:
test_file:
foo
xxx
xxx
xxx
bar
bar
xxx
bar
xxxx
xxx
xx
foo
xxx
xxx
xxx
xxx
xxx
bar
It should return:
linenumbersfoo: 1 12
linenumbersbar: 5 18
My code:
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[@]}"
I get:
linenumbersfoo: 1 12
linenumbersbar: 1 1
The problem seems to be the variable “number”, if I write e.g. 5 instead of $number, it works.
Any help is very appreciated!
EDIT: The test file must look like this:
bar foo
xxx
xxx
xxx
bar
bar
xxx
bar
xxxx
xxx
xx
bar foo
xxx
xxx
xxx
xxx
xxx
bar
means, i must find the first bar after the foo, but NOT in the line with the foo
EDIT: Sorry for this, but test file didn’t show all cases, last try:
bar foo
xxx
xxx
xxx
bar
bar
xxx
bar
xxxx
xxx
xx
bar foo
xxx
xxx
bar foo
xxx
xxx
xxx
xxx
xxx
bar
expected output:
linenumbersfoo: 1 12 15
linenumbersbar: 5 15 21
If there are following to “bar foo” i want it to be found. Line 15 isn’t found.
EDIT: adding an improvement to match your EDIT...
one suggestion with 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";
}
Answered by tonioc on December 1, 2020
Don't do this in a shell loop, awk
will do it for you.
This is an awk
script that you can store in a script file and invoke with awk -f script.awk filename
(modified to work with recent edit of the question):
BEGIN { lookfor[0] = "foo"; lookfor[1] = "bar"; i = 0 }
$0 ~ lookfor[i] {
lines[lookfor[i]] = lines[lookfor[i]] ? lines[lookfor[i]] ", " NR : NR
i = (i + 1) % 2
}
END { for (n in lines) printf("%st%sn", n, lines[n]) }
Running this on your example data:
$ awk -f script.awk file
foo 1, 12
bar 5, 18
The awk
script looks for the strings in the lookfor
array. It first looks for the first string (foo
) and when it finds it, it starts looking for the second string (bar
), and then the first again in an alternating fashion. Each time it finds a string, it stores the current line number in the associative array lines
for the corresponding string.
At the end, the collected line numbers in lines
are outputted.
The funky-looking line
lines[lookfor[i]] = lines[lookfor[i]] ? lines[lookfor[i]] ", " NR : NR
adds the line number to the end of the string of line numbers in the lines
array. If the string is empty, it just sets it to the current line number, but if it already contains something, a comma is inserted between the existing string and the line number.
You could change this to the simpler
lines[lookfor[i]] = lines[lookfor[i]] " " NR
which will insert a space between the line numbers (and in front of the first line number).
Answered by Kusalananda on December 1, 2020
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP