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 examplesh
orbash
.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
:-c
andls -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, thenls
never sees any'
- they are removed by the calling shell.ls
just 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.