Data
Data

Reputation: 215

Output matching pattern whilst retaining the line they existed on - bash

I'm having a tedious issue that can't seem to figure out and I am sure it is pretty simple, despite searching and trying for a while.

I have a file:

$ cat test.txt
shdh blah blah balg blah 0.44d 0.55d 0.33d
shdh blah blahdf fvalg blah 6.442d 1.515d 1.23d
3858 shdh blah blah balg blah 2.46d 9.35d 0.83d
shdh blah blah balg blah 4.46d
7 hh 4.5 5.34d 5.55d
t y 6.02d
88 2.7d
0.004d
shdh blah blah balg blah 0.96d 1.113d
6 yjryjh 423.99d 0.1d blah blah 0.9d 0.117d

I'd like to match all *d values, filtering out the rest while retaining the line they reside on. ie. To return a desired output like this:

0.44d 0.55d 0.33d
6.442d 1.515d 1.23d
2.46d 9.35d 0.83d
4.46d
5.34d 5.55d
6.02d
2.7d
0.004d
0.96d 1.113d
423.99d 0.1d 0.9d 0.117d

I'm able to match the pattern, but the problem is that each value is then returned on a new line, which is not what I want:

$ cat test.txt | grep -Eo '[0-9]+\.[0-9]+d'
0.44d
0.55d
0.33d
6.442d
1.515d
1.23d
2.46d
9.35d
0.83d
4.46d
5.34d
5.55d
6.02d
2.7d
0.004d
0.96d
1.113d
423.99d
0.1d
0.9d
0.117d

Does anyone have an idea on how to accomplish and return the desired output? Possibly with tr? Although I'd assume with this method each line would then concatenate to one line, again not the desired output.

Upvotes: 6

Views: 118

Answers (4)

glenn jackman
glenn jackman

Reputation: 246764

Perl oneliner:

perl -lane 'print join " ", grep {/d$/} @F' test.txt

The -e flag gives the next argument as the code to execute.
The -n flag tells perl to wrap the given code in a loop, iterating over the files of the given file(s)/stdin, without automatically printing the line.
The -a flag splits the line into fields stored in the @F array.
The -l flag handles automatically removing and re-adding the EOL newline.

Upvotes: 3

Ed Morton
Ed Morton

Reputation: 203229

With GNU awk for FPAT:

$ awk -v FPAT='\\S*d\\>' '{for (i=1; i<=NF; i++) printf "%s%s", $i, (i<NF ? OFS : ORS)}' test.txt
0.44d 0.55d 0.33d
6.442d 1.515d 1.23d
2.46d 9.35d 0.83d
4.46d
5.34d 5.55d
6.02d
2.7d
0.004d
0.96d 1.113d
423.99d 0.1d 0.9d 0.117d

or with any awk:

$ awk '{sep=""; for (i=1; i<=NF; i++) if ($i ~ /d$/) { printf "%s%s", sep, $i; sep=OFS } print "" }' test.txt
0.44d 0.55d 0.33d
6.442d 1.515d 1.23d
2.46d 9.35d 0.83d
4.46d
5.34d 5.55d
6.02d
2.7d
0.004d
0.96d 1.113d
423.99d 0.1d 0.9d 0.117d

In comparison with other answers the above will not print a trailing blank char at the end of each output line.

Upvotes: 2

xhienne
xhienne

Reputation: 6134

Here is a solution with sed:

sed -E 's/[^[:space:]]*[^d]([[:space:]]|$)//g'

I just inverted your initial logic: instead of displaying fields that end with d, I remove fields that don't.

Upvotes: 3

karakfa
karakfa

Reputation: 67467

awk to the rescue!

$ awk '{for(i=1;i<=NF;i++) if($i~/d$/) printf "%s ",$i; print ""}' file

0.44d 0.55d 0.33d
6.442d 1.515d 1.23d
2.46d 9.35d 0.83d
4.46d
5.34d 5.55d
6.02d
2.7d
0.004d
0.96d 1.113d
423.99d 0.1d 0.9d 0.117d

Upvotes: 3

Related Questions