github.com/fhs/u-root@v7.0.0+incompatible/cmds/core/uniq/uniq.go (about)

     1  // Copyright 2013-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Uniq removes repeated lines.
     6  //
     7  // Synopsis:
     8  //     uniq [OPTIONS...] [FILES]...
     9  //
    10  // Description:
    11  //     Uniq copies the input file, or the standard input, to the standard
    12  //     output, comparing adjacent lines. In the normal case, the second and
    13  //     succeeding copies of repeated lines are removed. Repeated lines must be
    14  //     adjacent in order to be found.
    15  //
    16  // Options:
    17  //     –u:      Print unique lines.
    18  //     –d:      Print (one copy of) duplicated lines.
    19  //     –c:      Prefix a repetition count and a tab to each output line.
    20  //              Implies –u and –d.
    21  //     –f num:  The first num fields together with any blanks before each are
    22  //              ignored. A field is defined as a string of non–space, non–tab
    23  //              characters separated by tabs and spaces from its neighbors.
    24  //     -cn num: The first num characters are ignored. Fields are skipped before
    25  //              characters.
    26  package main
    27  
    28  // TODO(aam): -num and +num are not implemented. they're easy to do, just not exactly the
    29  // way that the plan9 uniq does them as we want to avoid polluting the flag parsing libs with
    30  // outdated flags.
    31  
    32  import (
    33  	"bufio"
    34  	"bytes"
    35  	"flag"
    36  	"fmt"
    37  	"io"
    38  	"log"
    39  	"os"
    40  )
    41  
    42  var uniques = flag.Bool("u", false, "print unique lines")
    43  var duplicates = flag.Bool("d", false, "print one copy of duplicated lines")
    44  var count = flag.Bool("c", false, "prefix a repetition count and a tab for each output line")
    45  
    46  //var fnum = flag.Int("f", 0, "ignore num fields from beginning of line")
    47  //var cnum = flag.Int("cn", 0, "ignore num characters from beginning of line")
    48  
    49  func uniq(f *os.File) {
    50  	br := bufio.NewReader(f)
    51  
    52  	var err error
    53  	var oline, line []byte
    54  	cnt := 1
    55  	isLast := false
    56  	for {
    57  		line, err = br.ReadBytes('\n')
    58  		if err == io.EOF {
    59  			isLast = true
    60  		} else if err != nil {
    61  			log.Printf("Can't read the %v line of %v file: %v", line, f, err)
    62  		}
    63  		if oline == nil {
    64  			oline = line
    65  			continue
    66  		}
    67  		if !bytes.Equal(line, oline) {
    68  			if *count {
    69  				fmt.Printf("%d\t%s", cnt, oline)
    70  				goto skip
    71  			}
    72  			if cnt > 1 && *uniques {
    73  				goto skip
    74  			}
    75  			if cnt == 1 && *duplicates {
    76  				goto skip
    77  			}
    78  			fmt.Printf("%s", oline)
    79  		skip:
    80  			oline = line
    81  			cnt = 1
    82  		} else {
    83  			cnt++
    84  		}
    85  		if isLast {
    86  			break
    87  		}
    88  	}
    89  	if cnt > 1 && *uniques {
    90  		return
    91  	}
    92  	if cnt == 1 && *duplicates {
    93  		return
    94  	}
    95  	fmt.Printf("%s", line)
    96  }
    97  
    98  func main() {
    99  	flag.Parse()
   100  
   101  	if flag.NArg() > 0 {
   102  		for _, fn := range flag.Args() {
   103  			f, err := os.Open(fn)
   104  			if err != nil {
   105  				log.Printf("open %s: %v\n", fn, err)
   106  				os.Exit(1)
   107  			}
   108  			uniq(f)
   109  			f.Close()
   110  		}
   111  	} else {
   112  		uniq(os.Stdin)
   113  	}
   114  }