Tree55Topz
Tree55Topz

Reputation: 1142

Bash - Printing out rows that match parameters

I have a file that looks like this

3 5 4 0
0 0 0 0 
1 3 0 2

What I want is my bash script to only print rows that are not all zeroes. So print out would be

3 5 4 0
1 3 0 2 

This is what I have, and it runs with no errors but will not print anything

    #!/bin/bash
    awk '{total=0; for(i=1;i<NR;i++)$i+=total
    if (total!=0) {for(i=1;i<NR;i++) printf("%d ", $i)}}total=0'

Upvotes: 2

Views: 126

Answers (5)

Jotne
Jotne

Reputation: 41456

Some short awk:

awk 'NF!=gsub(/0/,"&")' file
3 5 4 0
1 3 0 2

Another one, even shorter:

awk -F"[0 ]*" 'NF>2' file
3 5 4 0
1 3 0 2

Just for fun, some extra:

awk '{a=$0;gsub(/ /,"")} $0+0 {print a}' file
3 5 4 0
1 3 0 2

The regex Ed uses:

awk '/[^0 ]/' file
3 5 4 0
1 3 0 2

And the winner is anubhava

I did a test of the different solution using a large file and time how long it takes. This is the result:

2.071s          awk '{k=0; for(i=1; i<=NF; i++) if ($i>0) {k=1;break}} k' large.txt >output
4.284s          awk 'NF!=gsub(/0/,"&")' large.txt >output
4.645s          awk '{a=$0;gsub(/ /,"")} $0+0 {print a}'  large.txt  >output
5.103s          awk 'NF!=gsub(/0/,"&")' large.txt >output
6.954s          grep '[^0 ]' large.txt >output
7.368s          awk '/[^0 ]/' large.txt  >output
9.374s          awk '{s=0;for(i=1;i<=NF;i++)if($i!=0)s=1}s' large.txt >output
12.007s         perl -lne '$s=0;map{$s+=$_}$_=~/([0-9]+)/g;print $_ if $s>0;' large.txt >output
25.575s         awk  -F"[0 ]*" 'NF>2' large.txt >output

Upvotes: 2

jaypal singh
jaypal singh

Reputation: 77095

Since awk and other suggestions are already posted, here is way of doing it with perl:

$ perl -lne '$s=0;map{$s+=$_}$_=~/([0-9]+)/g;print $_ if $s>0;' file
3 5 4 0
1 3 0 2

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 203324

Your script is printing nothing because total=0 is an assignment whose result is zero which is a false condition. Looks like you're back to confusing NR with NF again too.

Anyway, to do what you now say you want is just:

$ grep '[^0 ]' file
3 5 4 0
1 3 0 2

Upvotes: 2

user000001
user000001

Reputation: 33317

With awk you can do:

awk '{s=0;for(i=1;i<=NF;i++)if($i!=0)s=1}s' file 

Or in a bit more readable format:

#!/usr/bin/awk -f
{
    s = 0 # flag is initialized to zero
    for (i = 1; i <= NF; i++) # For all fields
        if ($i != 0) # If we find a field that is not zero
            s = 1    # then set the flag to 1
}
s # Prints the current line (default action) if the flag is 
  # not zero (and not an empty string)

Upvotes: 2

anubhava
anubhava

Reputation: 785058

You can use this egrep:

egrep -v "^(\<0\> *)+$" file
3 5 4 0
1 3 0 2

Using awk:

awk '{k=0; for(i=1; i<=NF; i++) if ($i>0) {k=1;break}} k' file
3 5 4 0
1 3 0 2

Upvotes: 2

Related Questions