cobra icon indicating copy to clipboard operation
cobra copied to clipboard

How to read stdin as the parameter of my command built on cobra?

Open brightzheng100 opened this issue 2 years ago • 4 comments

Hi folks, just wanted to learn how my cli built on cobra can read stdin as the parameter.

For example:

my_cli -c a.config

should be the same as:

cat a.conf | my_cli -c -

where a.conf is a config file that feeds the parameter of c.

brightzheng100 avatar Jul 03 '22 04:07 brightzheng100

An alternative and similar way that many linux commands use (sed for example) is a --file option which would allow for multiple command lines. Is there a way to do that as well?

tjayrush avatar Jul 22 '22 00:07 tjayrush

no, that's not what I'm looking for, instead, I'm looking for a "native" way to build this feature on top of cobra.

You know, it's now very common of doing so like kubectl apply -f <file> or cat <file> | kubectl apply -f -. Maybe I have to learn how the Kubernetes folks do for this feature by checking out the kubectl source code.

brightzheng100 avatar Jul 22 '22 09:07 brightzheng100

Yeah. Both of those things are sort of related. In the first case, the <file> is serving sort of the same feature as the stdin in the second case. It feels like the feature would have to live "above" the regular command line processing since the "commands" in the "file" are all legitimate command lines as well. There may be some way to capture the command with --file in it and run across a loop calling back into the same process.

tjayrush avatar Jul 27 '22 18:07 tjayrush

Hi, I am working on a CLI tool where I am facing the same issue. I need to implement the same behaviour in a subcommand with cobra.

Searching I found the method InOrStdin()

Unfortunately, there doesn't seem to be much documentation on it, other than this phrase

InOrStdin returns the input to stdin

But, looking at the implementation (here, here and here) , I could see that it (by default) ends up returning an instance of File with the file /dev/stdin open.

This instance implements the interface io.Reader. So that, we can use it to process it as a read buffer.

In the same way, we can use os.Open() to access any other file and treat it as a read buffer too.

In the end, it only remains to implement a method to process this buffer, it does not matter if it comes from a file or from stdin.

I share with you an example based on the implementation that I working on for my project. I believe that this is what you are searching for. Could adapt easily to use it with flags.

var myappCmd = &cobra.Command {
	Use:   "myapp [FILE]",
	Short: "do stuff with a [FILE]",
	Long:  `With no FILE, or when FILE is -, read standar input.`,

	// we guarantee that only recive one argument o none
	Args: cobra.MaximumNArgs(1),

	RunE: func(cmd *cobra.Command, args []string) error {

		// this does the trick
		var inputReader io.Reader = cmd.InOrStdin()

		// the argument received looks like a file, we try to open it
		if len(args) > 0 && args[0] != "-" {
			file, err := os.Open(args[0])
			if err != nil {
				return fmt.Errorf("failed open file: %v", err)
			}
			inputReader = file
		}

		// we process the input reader, wherever to be his origin
		err :=	processInput(inputReader)
		if err != nil {
			return fmt.Errorf("failed process input: %v", err)
		}

		return nil
	},
}

mauroalderete avatar Aug 24 '22 03:08 mauroalderete

The Cobra project currently lacks enough contributors to adequately respond to all issues. This bot triages issues and PRs according to the following rules:

  • After 60d of inactivity, lifecycle/stale is applied. - After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied and the issue is closed. You can:
  • Make a comment to remove the stale label and show your support. The 60 days reset. - If an issue has lifecycle/rotten and is closed, comment and ask maintainers if they'd be interseted in reopening

github-actions[bot] avatar Oct 24 '22 00:10 github-actions[bot]