dotnet / command-line-api

Command line parsing, invocation, and rendering of terminal output.
https://github.com/dotnet/command-line-api/wiki
MIT License
3.34k stars 375 forks source link

Feature request: Support POSIX standard of using single hyphen "-" to mean standard input. #2432

Open moh-hassan opened 1 month ago

moh-hassan commented 1 month ago

Posix support of using single hyphen "-" to mean standard input. ref: https://pubs.opengroup.org/onlinepubs/9699919799/

example

cd ~ && wget -O - "https://path/to/file" | tar xzf -

The- argument passed to tar after xzf means to read from standard input instead of from a named file. The - argument passed to wget after -O means to write to standard output instead of to a named file.

Here OS will prompt the user to enter fileName from keyboard

It is nice if this feature is supported and system prompt the user to enter filename.

elgonzo commented 1 month ago

How exactly would you imagine this working / looking like in the source code? Considering that it is the application logic and not the System.CommandLine library code that is doing the reading/writing from/to some (named) file (or stream), how would you see System.CommandLine being able to exert influence on the application logic and make it read from stdin / write to stdout instead of a file without you needing to implement this stuff in the application logic anyway...?


It is nice if this feature is supported and system prompt the user to enter filename.

That's not what Posix stipulates. Posix establishes the hyphen operand as an (optional) convention to command reading from stdin / writing to stdout instead from/to a file, Posix does not define it to be a request for prompting for a file name.

moh-hassan commented 1 month ago

That's not what Posix stipulates. Posix establishes the hyphen operand as an (optional) convention to command reading from stdin / writing to stdout instead from/to a file, Posix does not define it to be a request for prompting for a file name.

The section 12.1 Utility Argument Syntax

Guideline 13:
For utilities that use operands to represent files to be opened for either reading or writing, the '-' operand should be used to mean only standard input (or standard output when it is clear from context that an output file is being specified) or a file named -.

Note the term 'should be used' i.e it is not optional.

So, the single '-' operand is used to read a VALUE from STDIN (in my example of file name, it is a value from stdin that represent filename. it can be represent any value as i show in the examples below).

When using the command myutility -, the system will prompt the user to enter a value from the STDIN keyboard. The - operand indicates that the input should come from standard input (stdin). User can then provide the necessary input interactively by typing it via the keyboard.

In case of STDIN is redirected like: The command echo "data" | myutility -. myutility will receive the string "data" as its input through stdin.

In both cases the system is using STDIN and interpret the single dash as READ STDIN.

How exactly would you imagine this working / looking like in the source code

The parser is aware of the option and its value. If the value EQUAL_TO '-' , prompt the user to enter value from stdin (in interactive keyboared) or input pipeline). So the implementation of the single dash can be in the core of the library like the implementation of using @ for response file.

As POC, the parser is aware that single dash is a VALUE like:

myapp [diagram] project history --token - 

the parser output is:
[ myapp [ project [ history [ --token <-> ]  ] ] ]

Currently I implement this feature from within Incremental generator and hook the code to read from stdin in SetAction method.

Suggested Solution: I think i can use the built-in CustomParser property to implement single-dash. I will try it and feedback.

KalleOlaviNiemitalo commented 1 month ago

I have a few applications that read or write binary data (e.g. compressed formats) rather than text, and I want them to support - for reading from stdin or writing to stdout. In such cases:

Other notes:

In the System.CommandLine API then, I think this would minimally be a validator that can be put in CliArgument\<string> and CliOption\<string>. One could also think about some metadata for shell integration but I haven't been keeping track of how that works on the Powderhouse branch.

moh-hassan commented 1 month ago

I find that System.CommandLine already can support this feature without modification by using CustomParser 👍 I tried the next tests to check single dash and all tests are passed

public class SinglDashTest
{

    [Fact]
    public void Argument_with_single_dash_can_read_from_stdin()
    {
        var argument = new CliArgument<string>("arg")
        {
            CustomParser = x => x.Tokens[0].Value == "-" ? readStdin() : x.Tokens[0].Value,
        };

        var result = new CliRootCommand { argument }.Parse("-");

        result.GetValue(argument)
            .Should()
            .Be("abc");
    }

    [Fact]
    public void Option_with_single_dash_can_read_from_stdin()
    {
        var argument = new CliOption<string>("--token")
        {
            CustomParser = x => x.Tokens[0].Value == "-" ? readStdin() : x.Tokens[0].Value,
        };

        var result = new CliRootCommand { argument }.Parse("--token -");

        result.GetValue(argument)
            .Should()
            .Be("abc");
    }

    string readStdin()
    {
      //show user a meaning prompt 
        Console.WriteLine("Enter Token");
        Console.SetIn(new StringReader("abc"));
        return Console.In.ReadToEnd();
    }
}

No need for new feature :)

elgonzo commented 1 month ago

Guideline 13: For utilities that use operands to represent files to be opened for either reading or writing, the '-' operand should be used to mean only standard input (or standard output when it is clear from context that an output file is being specified) or a file named -.

Note the term 'should be used' i.e it is not optional.

Pay attention to the quoted guideline ending with "or a file named -." Posix does not require the single hyphen to mean a request to use stdin/stdout, it is left for the application developer to decide whether their app wants to treat the hyphen as a file name or a stdin/stdout redirect.

In case of STDIN is redirected like: The command echo "data" | myutility -. myutility will receive the string "data" as its input through stdin.

That is an extremely simple use case. However, stdin/stdout redirects are not limited to simple short text values, data piped through stdin or stdout can encompass very large amounts of data that is not necessarily text. That was one of the motivations of my question of how you would imagine S:CL being involved/helpful in what is essentially the application's task to deal with. Anyway, since you found a solution for your use case, i consider my question answered :-)