cobra
cobra copied to clipboard
How to read stdin as the parameter of my command built on cobra?
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
.
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?
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.
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.
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
},
}
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