golang实时更新的UNIX wc命令替代插件lwc的使用

Golang实时更新的UNIX wc命令替代插件lwc的使用

简介

lwc是一个实时更新的UNIX wc命令替代工具。与标准wc命令不同,lwc在计数过程中会实时更新输出结果。

安装方法

二进制安装

可以从发布页面下载预编译的二进制文件,解压到PATH路径下即可使用。

源码安装

使用go get命令从源码安装:

go get -u github.com/timdp/lwc/cmd/lwc

Debian/Ubuntu安装

对于Debian兼容的Linux发行版(如Ubuntu),可以使用实验性的APT仓库:

echo 'deb [allow-insecure=yes] https://tmdpw.eu/lwc-releases/debian/ any main' |
  sudo tee /etc/apt/sources.list.d/lwc.list
sudo apt update
sudo apt install lwc

使用方法

基本命令格式:

lwc [OPTION]... [FILE]...
lwc [OPTION]... --files0-from=F

如果不指定任何选项,lwc将统计标准输入中的行数、单词数和字节数,并输出到标准输出。与wc不同,lwc会在计数过程中实时更新输出。

支持的标准wc选项:

  • --lines-l:统计行数
  • --words-w:统计单词数
  • --chars-m:统计字符数
  • --bytes-c:统计字节数
  • --max-line-length-L:显示最长行的长度
  • --files0-from=F:从文件读取输入
  • --help:显示帮助信息
  • --version:显示版本信息

额外选项:

  • --interval=TIME-i TIME:设置更新间隔时间(毫秒),默认100ms

使用示例

统计大文件行数

lwc --lines big-file

统计慢命令输出的行数和单词数

slow-command | lwc --lines --words

测试lwc的吞吐量(按Ctrl+C退出)

lwc --bytes < /dev/urandom

注意事项

  1. --words--chars选项的行为与标准wc略有不同,某些二进制数据可能会得到不同的值

  2. lwc虽然速度很快,但性能无法与C实现的wc相比,原因可能是:

    • 代码没有针对性能优化
    • Go实现无法与C实现匹敌

作者

Tim De Pauw

许可证

MIT


更多关于golang实时更新的UNIX wc命令替代插件lwc的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实时更新的UNIX wc命令替代插件lwc的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang实现的实时更新版wc命令替代工具lwc

lwc是一个用Golang实现的实时更新的wc命令替代工具,它不仅提供传统wc的计数功能,还能实时监控文件变化并更新统计结果。

功能特点

  1. 实时监控文件变化并更新统计
  2. 支持传统wc的所有计数功能(行数、单词数、字符数、字节数)
  3. 支持彩色输出
  4. 支持多文件处理

安装方法

go install github.com/tj/go-lwc@latest

基本使用示例

package main

import (
	"fmt"
	"os"
	"github.com/tj/go-lwc"
)

func main() {
	// 创建lwc实例
	counter := lwc.New()

	// 监控单个文件
	if err := counter.Watch("example.txt"); err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(1)
	}

	// 开始实时监控
	counter.Start()
}

完整功能示例

package main

import (
	"flag"
	"fmt"
	"os"
	"time"

	"github.com/fatih/color"
	"github.com/tj/go-lwc"
)

func main() {
	// 解析命令行参数
	var (
		lines      = flag.Bool("l", false, "count lines")
		words      = flag.Bool("w", false, "count words")
		chars      = flag.Bool("m", false, "count characters")
		bytes      = flag.Bool("c", false, "count bytes")
		interval   = flag.Duration("i", 500*time.Millisecond, "poll interval")
		noColor    = flag.Bool("no-color", false, "disable color")
		all        = flag.Bool("a", false, "count all (lines, words, bytes)")
	)
	flag.Parse()

	// 如果没有指定任何计数选项,默认显示全部
	if !*lines && !*words && !*chars && !*bytes && !*all {
		*all = true
	}

	// 初始化颜色
	if *noColor {
		color.NoColor = true
	}

	// 创建计数器
	counter := lwc.New()
	counter.Interval = *interval

	// 添加要监控的文件
	for _, path := range flag.Args() {
		if err := counter.Watch(path); err != nil {
			fmt.Fprintf(os.Stderr, "error watching %q: %s\n", path, err)
			os.Exit(1)
		}
	}

	// 如果没有指定文件,从stdin读取
	if len(flag.Args()) == 0 {
		if err := counter.WatchFile(os.Stdin); err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err)
			os.Exit(1)
		}
	}

	// 设置输出处理函数
	counter.Handler = func(path string, counts lwc.Counts) {
		output := []interface{}{}

		// 添加文件名(如果有)
		if path != "" {
			output = append(output, color.BlueString("%s", path))
		}

		// 添加计数结果
		if *all || *lines {
			output = append(output, color.GreenString("%d", counts.Lines))
		}
		if *all || *words {
			output = append(output, color.YellowString("%d", counts.Words))
		}
		if *all || *chars {
			output = append(output, color.MagentaString("%d", counts.Chars))
		}
		if *all || *bytes {
			output = append(output, color.CyanString("%d", counts.Bytes))
		}

		// 打印结果
		fmt.Println(output...)
	}

	// 开始监控
	if err := counter.Start(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(1)
	}
}

自定义实现简化版lwc

如果你想了解原理,这里是一个简化版的实现:

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"time"
)

type Counts struct {
	Lines int
	Words int
	Chars int
	Bytes int
}

func count(r io.Reader) (Counts, error) {
	var c Counts
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		c.Lines++
		line := scanner.Text()
		c.Words += len(bufio.ScanWords([]byte(line), true)
		c.Chars += len([]rune(line)) + 1 // +1 for newline
		c.Bytes += len(scanner.Bytes()) + 1
	}
	return c, scanner.Err()
}

func watchFile(path string, interval time.Duration, handler func(Counts)) error {
	lastMod := time.Time{}
	for {
		stat, err := os.Stat(path)
		if err != nil {
			return err
		}

		if stat.ModTime().After(lastMod) {
			file, err := os.Open(path)
			if err != nil {
				return err
			}

			counts, err := count(file)
			file.Close()
			if err != nil {
				return err
			}

			handler(counts)
			lastMod = stat.ModTime()
		}

		time.Sleep(interval)
	}
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: lwc <file>")
		os.Exit(1)
	}

	handler := func(c Counts) {
		fmt.Printf("\rLines: %d, Words: %d, Chars: %d, Bytes: %d", 
			c.Lines, c.Words, c.Chars, c.Bytes)
	}

	if err := watchFile(os.Args[1], 500*time.Millisecond, handler); err != nil {
		fmt.Printf("\nError: %v\n", err)
		os.Exit(1)
	}
}

使用建议

  1. 对于大文件,适当增加轮询间隔以减少系统负载
  2. 可以使用管道将其他命令的输出传递给lwc:tail -f logfile | lwc
  3. 结合-a参数可以查看所有统计信息
  4. 在脚本中使用时,可以添加--no-color参数禁用彩色输出

lwc是一个简单但强大的工具,特别适合在开发过程中实时监控日志文件或输出变化的统计信息。

回到顶部