runtime: Problem parsing on single quotes in argument for Process.Start (dotnet Core, Linux console)
(2019-07-21: rewrote this issues to simplify)
I’m executing console programs in Linux using
I’m executing programs on Linux with Process.Start. Sometimes I need to provide single quotes in the arguments but I’ve not been able to succeed no matter how I escape the character. A simplified example:
using System;
using System.Diagnostics;
namespace Execute_test
{
class Program
{
static void Main(string[] args)
{
Process proc = new System.Diagnostics.Process();
ProcessStartInfo pi = new ProcessStartInfo("ls");
pi.Arguments = "-l '/tmp/'";
proc.StartInfo = pi;
proc.Start();
do { System.Threading.Thread.Sleep(50); } while (proc.HasExited == false);
Environment.Exit(0);
}
}
}
I do know I don’t have to surround /tmp/ in single quote, but it’s just to make a simple example (please don’t suggest alternatives, that’s not the issue!)
The err.out from this example is ls: cannot access "'/tmp/'": No such file or directory
I’ve tried to run this code in .net Core 2.2 and the newest .net Core 3.0.100-preview6-012264 in both C# and VB.
I also tried to use the ProcessStartInfo.ArgumentList it doesn’t parse single quotes any better.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 29 (10 by maintainers)
OMG!!!
ProcessStartInfo pi = new ProcessStartInfo("ls"){ ArgumentList = {"'","/tmp/","'"} };Pure beauty, thaaaaanks@jnm2 I’m confused, shouldn’t it be
ArgumentList = { "-W", "-f= ${db:Status-Status} ", "mariadb*" }and
ArgumentList = { "qemu-agent-command", "SRV01", "{\"execute\":\"guest-ping\"}" }?If you execute
dpkg-query -W -f=' ${db:Status-Status} ' mariadb*in bash, the'are not passed to the executable, as you can easily test by puttingprintf '%s\n'before the commands. Runningprintf '%s\n' dpkg-query -W -f=' ${db:Status-Status} ' mariadb*in bash givesas output, so
'is not contained in the arguments, ifdpkg-query -W -f=' ${db:Status-Status} ' mariadb*is executed in bash.@MrM40
Why aren’t you doingArgumentList = { "-W", "-f=' ${db:Status-Status} '", "mariadb*" }?AndArgumentList = { "qemu-agent-command", "SRV01", "'{\"execute\":\"guest-ping\"}'" }?works fine for me. If you want
'to be considered a quote, you need some executable, that considers it a quote - for exampleshorbash.You want to start the application from .NET Core which you start on the command line as:
Let’s first figure out how many arguments are involved when starting the application. We’ll use strace and trace for the execve call:
As we can see in the output, two arguments are passed to
bash:-candls -l /etc/ > /tmp/list.txt.We need a way of passing the second argument so it gets treated as a whole (that is, not split at the spaces).
For bash, there are a number of options. One is to use single quotes, like
/bin/bash -c 'ls -l /etc/ > /tmp/list.txt'.For
ProcessStartInfo.Arguments, we need to use double quotes.prints out:
ProcessStartInfo pi = new ProcessStartInfo("ls"){ ArgumentList = {"/tmp/"} };is enough - you don’t need a'in that case.If you execute
ls -l '/tmp/' '/path/with space/'in bash or sh, thenlsnever sees any'- they are removed by the calling shell.lsjust gets an array ofNo no no! This is equivalent of executing
ls "'" "/tmp/" "'"in bash. It works, but does not do what you want. It lists the files of a folder named'(twice) and lists the contents of/tmp/.Please delete (or edit) your comment https://github.com/dotnet/corefx/issues/23592#issuecomment-514241549 as it could heavily confuse newcomers.
.NET Core added an ArgumentsList on ProcessStartInfo. You don’t need to deal with escaping if you are using that. You can Add the ‘-c’ and ‘ls -l /etc/ > /tmp/list.txt’ to the ArgumentsList.