cmd

package
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 31, 2025 License: GPL-3.0 Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Command = &cobra.Command{
	Use:   "field [--flags] ...<range>",
	Short: "Extract and print selected fields from each input line",
	Example: `
# Extract the second field from ps output (PID) and kill those processes
ps aux | grep bad-process | field 2 | xargs kill

# Print only the usernames (first field) from /etc/passwd and ignore empty lines
cat /etc/passwd | field -i -d: 1

# Show just the command (limit number of field 11) from ps output
ps aux | field -n 11 11

# Shows the PID and the command from ps command with <PID>:<COMMAND> format
ps aux | field -n 11 -f "{2}:{11}"

# Extract multiple fields (user and PID) and print them
ps aux | field 1 2

# Extract a directory and get all the deleted files
rm -vrf bad-directory | field -s -- -1
`,
	Args: MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		writter := bufio.NewWriter(os.Stdout)

		var template *fasttemplate.Template
		if cmd.Flags().Changed("format") {
			t, err := fasttemplate.NewTemplate(format, "{", "}")
			if err != nil {
				return err
			}
			template = t
		}

		ranges := make([]*Range, len(args))
		for i, a := range args {
			r, err := ParseRange(a, false)
			if err != nil {
				return err
			}
			ranges[i] = r
		}

		const size = 500 * (2 << 19) // 500 MiB
		reader := bufio.NewReader(os.Stdin)

		buf := bytes.NewBuffer(nil)

		for {
			b, prefixed, err := reader.ReadLine()
			if err != nil {
				if errors.Is(err, io.EOF) {
					break
				}
				return err
			}

			if buf.Len()+len(b) > size {
				return fmt.Errorf("line is too big")
			}

			if prefixed {
				buf.Write(b)
				continue
			}

			if buf.Len() > 0 {
				b = buf.Bytes()
				buf.Reset()
			}

			var fields []string
			if shell {
				s, err := shlex.Split(string(b))
				if err != nil {
					slog.Error("Failed to parse qouted field", "error", err)
					continue
				}
				fields = s.Strings()
			} else if cmd.Flags().Changed("delimiter") {
				fields = FieldN(b, delimiter, limit.Int())
			} else {
				fields = FieldNFunc(b, unicode.IsSpace, limit.Int())
			}

			selected := make([]string, 0, 10)
			for r := range slices.Values(ranges) {
				selected = append(selected, r.Select(fields)...)
			}

			if template == nil {
				if ignoreEmpty && len(selected) == 0 {
					continue
				}

				fprintlnStr(writter, selected)
				if err := writter.Flush(); err != nil {
					return err
				}
				continue
			}

			selector := func(w io.Writer, tag string) (int, error) {
				r, err := ParseRange(tag, false)
				if err != nil {
					return 0, err
				}
				return fprintlnStr(w, r.Select(fields))
			}

			if _, err := template.ExecuteFunc(writter, selector); err != nil {
				slog.Error("Failed execute format template", "error", err)
				continue
			}

			if err := writter.Flush(); err != nil {
				return err
			}
		}

		return nil
	},
}

Command is root command

Functions

func FieldN

func FieldN(s []byte, delimiter string, n int) []string

FieldN takes a string and a delimiter and returns n numbers of fields seperated by the delimiter. If n is negative the returns all fields.

func FieldNFunc added in v0.1.3

func FieldNFunc(s []byte, pred Pred, n int) []string

FieldNFunc splits s into at most n fields, separated by runes where pred(r) == true. If n < 0, it returns all fields. Consecutive separators are treated as one (like strings.Fields).

func MinimumNArgs

func MinimumNArgs(n int) cobra.PositionalArgs

MinimumNArgs returns an error if there is not at least N args.

Types

type Pred

type Pred func(rune) bool

Pred is a function that returns true if the rune should be treated as a separator.

type Range

type Range struct {
	Reversed   bool
	Exact      bool
	Start, End int
}

Range is data type the indicates a range of item for a string slice

func ParseRange

func ParseRange(str string, reversed bool) (*Range, error)

ParseRange parses a string into a Range

func (*Range) Select

func (r *Range) Select(s []string) []string

Select selects item of a []string according to the bound

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL