Skip to content

It is not possible to pass command-line arguments starting with an at-sign to fsx scripts run with "dotnet fsi" #16092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
F8enjoyer opened this issue Oct 8, 2023 · 8 comments

Comments

@F8enjoyer
Copy link

Command-line arguments to "dotnet fsi {script}.fsx" that start with "@" are not taken literally, and are interpreted as an instruction to read the argument value from a file with the name following the "@".

This behavior is recursive; if the file contents are a single line starting with "@", then the rest of the line is taken as the name of another file to read, and so on.

This leads to two problems:

  1. It does not appear to be possible to pass command-line arguments starting with "@" to fsx scripts.
  2. If cycles exist in files that reference each other with "@" syntax, the interpreter will loop infinitely if any are passed on the command-line using "@" syntax.

Reproduction steps

Provide the steps required to reproduce the problem:

  1. Create script "echo_args.fsx" with content:
    System.Environment.GetCommandLineArgs() |> Seq.iter (printfn "- [%s]")
  2. Create test input files
    echo Contents of test>test
    echo @loop>loop
    echo @two>one
    echo @one>two
  3. Check behavior
    dotnet fsi echo_args.fsx test
    dotnet fsi echo_args.fsx @test
    dotnet fsi echo_args.fsx @loop
    dotnet fsi echo_args.fsx @one

Unless I have simply missed it, this behavior appears to be undocumented.
I have tried using backslash and "@@" to attempt to escape the "@" character, but neither works.

Expected behavior

  1. It should be possible to pass a command-line argument to an fsx script starting with "@".
  2. Cycles in files referenced using "@" syntax should not result in an infinite loop if specified on the command-line.

Actual behavior

  1. It does not appear to be possible to pass a command-line argument that starts with "@"
  2. Infinite looping occurs if cycles exist in files referenced with "@"

Known workarounds

None at present.

Related information
This behavior does not appear to be documented in any of the following documentation:
https://learn.microsoft.com/en-us/dotnet/fsharp/tools/fsharp-interactive/
https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet

  • Operating system: Windows 10
  • .NET Runtime kind: dotnet SDK 7.0.401
  • Editing Tools: N/A
@abonie
Copy link
Member

abonie commented Oct 9, 2023

This depends on where you run the script from. I am guessing you are trying to run this from powershell - there @ has a special meaning; I don't know much about powershell, but I think it understands @test as you wanting to splat variable test, but since there is no such variable, it expands to nothing. Just like echo @test does not print anything.

Usually you could escape it with quotations, like echo "@test", but that won't work with dotnet fsi, because then it thinks it is a response file. So what you have to do is dotnet fsi echo_args.fsx -- "@test".

@F8enjoyer
Copy link
Author

Thank you for the response.

Powershell can be ruled out; this behavior occurs when running directly from cmd.exe.

However, I can confirm that both:

  • dotnet fsi echo_args.fsx -- "@test"
  • dotnet fsi echo_args.fsx -- @test

... do successfully pass the argument @test, not the contents of file "test".

Are you able to shed any light on the origin of this behavior, and the source code for it?
It's not clear if this is a feature of dotnet, fsi, or something else.

I think "--" is a good workaround for most use-cases, but not all.
In particular, if you are taking advantage of this feature, and want to pass the contents of a file as an argument, there does not appear to be a way to stop "@" directives being interpreted inside those files.

So to summarize, the remaining issues as I see it are:

  1. Identifying the source of this behavior.
  2. The lack of (obvious?) documentation that "@" is special, and that "--" can be used as a workaround.
  3. The infinite loop if cycles exist.
  4. The inability to break out of "@" handling from within an argument file.

@baronfel
Copy link
Member

baronfel commented Oct 9, 2023

The response file handling is a feature of the System.CommandLine library that the dotnet CLI is built with. It applies response file handling to every command. Can you try escaping the @ with another @?

@F8enjoyer
Copy link
Author

F8enjoyer commented Oct 9, 2023

@baronfel Using @@test results is reading a file called @test

@F8enjoyer
Copy link
Author

F8enjoyer commented Oct 9, 2023

Searching "System.CommandLine library" revealed the following documentation:
https://learn.microsoft.com/en-us/dotnet/standard/commandline/syntax#response-files

Althougth this documentation is just over a year old, and suggests that "System.CommandLine" is in "preview"?

@F8enjoyer
Copy link
Author

F8enjoyer commented Oct 9, 2023

... and now that I know what to look for, running dotnet fsi --help does mention:
-- ... Treat remaining arguments as command line arguments, accessed using fsi.CommandLineArgs

(Although it does not mention @)

It probably didn't help me that I was originally using the dotnet 6 SDK, which had a bug that caused dotnet fsi --help to not work correctly, and only upgraded to 7 to confirm the behavior was still present.

@baronfel
Copy link
Member

baronfel commented Oct 9, 2023

The -- behavior is a very common CLI usage pattern specifically for this use case - when you must pass through some tokens un-touched to the running program. It's definitely not a hack or workaround, rather it's the established way to communicate intent when there can be ambiguity in the semantics of a CLI application.

@F8enjoyer
Copy link
Author

Indeed; this is POSIX behavior.

So, from my earlier list of remaining issues:

  1. Identifying the source of this behavior.
    a. Now identified as System.CommandLine
  2. The lack of (obvious?) documentation that "@" is special, and that "--" can be used as a workaround.
    a. "--" is documented; "@" is not.
  3. The infinite loop if cycles exist.
    a. This is something for System.CommandLine, not this project.
  4. The inability to break out of "@" handling from within an argument file.
    a. Again, for System.CommandLine.

So, one minor documentation gripe about not spelling-out "@" behavior in "dotnet fsi --help" and https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/fsharp-interactive-options , and everything else is for System.CommandLine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: New
Development

No branches or pull requests

4 participants