Miguel
Miguel

Reputation: 356

Wildcard symbol with grep -F

I have the following file

0 0
0 0.001
0 0.032
0 0.1241
0 0.2241
0 0.42
0.0142 0
0.0234 0
0.01429 0.01282
0.001 0.224
0.098 0.367
0.129 0
0.123 0.01282
0.149 0.16
0.1345 0.216
0.293 0
0.2439 0.01316
0.2549 0.1316
0.2354 0.5
0.3345 0
0.3456 0.0116
0.3462 0.316
0.3632 0.416
0.429 0
0.42439 0.016
0.4234 0.3
0.5 0
0.5 0.33
0.5 0.5

Notice that the two columns are sorted ascending, first by the first column and then by the second one. The minimum value is 0 and the maximum is 0.5.

I would like to count the number of lines that are:

0 0

and store that number in a file called "0_0". In this case, this file should contain "1".

Then, the same for those that are:

0 0.0*

For example,

0 0.032

And call it "0_0.0" (it should contain "2"), and this for all combinations only considering the first decimal digit (0 0.1*, 0 0.2* ... 0.0* 0, 0.0* 0.0* ... 0.5 0.5).

I am using this loop:

for i in 0 0.0 0.1 0.2 0.3 0.4 0.5
do
    for j in 0 0.0 0.1 0.2 0.3 0.4 0.5
    do
        grep -F ""$i" "$j"" file | wc -l > "$i"_"$j"
    done
done

rm 0_0 #this 0_0 output is badly done, the good way is with the next command, which accepts \n
pcregrep -M "0 0\n" file | wc -l > 0_0

The problem is that for example, line

0.0142 0

will not be recognized by the iteration "0.0 0", since there are digits after the "0.0". Removing the -F option in grep in order to consider all numbers that start by "0.0" will not work, since the point will be considered a wildcard symbol and therefore for example in the iteration "0.1 0" the line

 0.0142 0

will be counted, because 0.0142 is a 0"anything"1.

I hope I am making myself clear!

Is there any way to include a wildcard symbol with grep -F, like in:

for i in 0 0.0 0.1 0.2 0.3 0.4 0.5
do
    for j in 0 0.0 0.1 0.2 0.3 0.4 0.5
    do
        grep -F ""$i"* "$j"*" file | wc -l > "$i"_"$j"
    done
done

(Please notice the asterisks after the variables in the grep command).

Thank you!

Upvotes: 1

Views: 200

Answers (1)

Ed Morton
Ed Morton

Reputation: 203169

Don't use shell loops just to manipulate text, that's what the guys who invented shell also invented awk to do. See why-is-using-a-shell-loop-to-process-text-considered-bad-practice.

It sounds like all you need is:

awk '{cnt[substr($1,1,3)"_"substr($2,1,3)]++} END{ for (pair in cnt) {print cnt[pair] > pair; close(pair)} }' file

That will be vastly more efficient than your nested shell loops approach.

Here's what it'll be outputting to the files it creates:

$ awk '{cnt[substr($1,1,3)"_"substr($2,1,3)]++} END{for (pair in cnt) print pair "\t" cnt[pair]}' file
0.0_0.3 1
0_0.4   1
0.5_0   1
0.2_0.5 1
0.4_0.3 1
0.0_0   2
0.1_0.0 1
0.3_0   1
0.1_0.1 1
0.1_0.2 1
0.3_0.0 1
0_0     1
0.1_0   1
0.5_0.3 1
0.4_0   1
0.3_0.3 1
0.2_0.0 1
0_0.0   2
0.5_0.5 1
0.3_0.4 1
0.2_0.1 1
0.0_0.0 1
0_0.1   1
0_0.2   1
0.4_0.0 1
0.2_0   1
0.0_0.2 1

Upvotes: 2

Related Questions