0

I have some problems calling commands from a Linux .net core consol application.

Sub Main()
    Dim PI As New ProcessStartInfo

    Using Proc As New Process
        With PI
            .FileName = "cat"
            .Arguments = "/etc/*-release"
            .RedirectStandardOutput = True
            .UseShellExecute = False
            .CreateNoWindow = True
        End With
        Proc.StartInfo = PI
        Proc.Start()
        PI = Nothing
        Console.Write(Proc.StandardOutput.ReadToEnd)
    End Using
End Sub

I get this error:

cat: '/etc/*-release': No such file or directory

It work if I disable redirection and set UseShellExecute = True, but I would like to be able to use the output in my code.

2
  • 2
    If you want to avoid using a shell, then you'll have to replicate the work the shell does to expand /etc/*-release. Not that familiar with the language, but perhaps it has a wrapper or equivalent for the Unix C glob() function? Commented Feb 20, 2018 at 22:28
  • I didn't put to much thought about what was really happening. I just expected ´cat´ to do the "file search" and not the shell......but I see the logic now, thanks. Commented Feb 21, 2018 at 7:49

2 Answers 2

1

When you run a command like

cat /etc/*-release

The linux shell (bash, probably) evaluates each argument, then calls the program with the evaluated arguments. Simple words evaluate to themselves, but variables (like $SOME_ARGUMENT) and patterns (like *) evaluate to the values and file names. So the shell really evaluates the above into (assuming there is just one file):

cat /etc/os-release

And so the cat program just gets that one argument - without any globs like *.

If you want to emulate that behaviour in your program, you need to set UseShellExecute to True.

Or, perhaps you can do the evaluation yourself. APIs like Directory.EnumerateFiles let you do that:

 Dim textFiles = Directory.EnumerateFiles("/etc/", "*-release")

Then you need to walk this collection and use the exact file name as your .Arguments value.

Edit: But to go a bit further, why are you even trying to do this? If you have read the file completely, why call cat. Why not just Console.WriteLine() the file itself rather than calling cat?

Sign up to request clarification or add additional context in comments.

1 Comment

I'm making a admin tool which will call a lot of different commands, and I made a function to call whenever I want to fire a command CallCMD(EXE as string, Args as strings()) as string. The output need to be saved to a string for further handling. That doesn't seem possible setting UseShellExecute to True. cat /etc/*-release is just an example....I would like it to support any command that I work in the bash shell.
0

Ahhh....got it!

I just have to use bash -c ""cat ""/etc/*-release""""

    Sub Main()
    Dim PI As New ProcessStartInfo

    Using Proc As New Process
        With PI
            .FileName = "bash"
            .Arguments = "-c ""cat ""/etc/*-release"""""
            .RedirectStandardOutput = True
            .UseShellExecute = False
            .CreateNoWindow = True
        End With
        Proc.StartInfo = PI
        Proc.Start()
        PI = Nothing
        Console.Write(Proc.StandardOutput.ReadToEnd)
    End Using
End Sub

1 Comment

Not sure what those quotes really mean, but they look wacky. The string you pass to -c should be cat /etc/*-release without any additional internal quotes. In e.g. Python, this would be subprocess.call(['bash', '-c', 'cat /etc/*-release']) if that helps to see what I'm trying to say.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.