System.Diagnostics.Process pipe (vertical bar) not accepted as argument - c#

I'm trying to execute this code using System.Diagnostics.Process. It works fine in command line. But in C# it's failing on the | character.
var myProcess = new Process();
var p = new ProcessStartInfo();
var sArgs = " -i emp.mp3 -f wav - | neroAacEnc -ignorelength -q 0.5 -if - -of emp.mp4";
p.FileName = "ffmpeg.exe";
p.CreateNoWindow = false;
p.RedirectStandardOutput = false;
p.UseShellExecute = false;
p.Arguments = sArgs;
myProcess.StartInfo = p;
myProcess.Start();
myProcess.WaitForExit();
It gives the following error:
Unable to find a suitable output format for '|': Invalid argument
I've looked around on stackoverflow and found the following hint but it is also not working:
var psi = new ProcessStartInfo("ffmpeg.exe");
psi.Arguments =
"\"-i emp.mp3 -f wav -\" | \"neroAacEnc -ignorelength -q 0.5 -if - -of emp.mp4\"";
psi.CreateNoWindow = false;
psi.UseShellExecute = false;
var process = new Process { StartInfo = psi };
process.Start();
process.WaitForExit();
gives the following error:
Unrecognized option 'i emp.mp3 -f wav -'
Failed to set value '|' for option 'i emp.mp3 -f wav -'

Thanks to Lee his comments, the problem has been resolved. Just invoke cmd.exe and pass it the full command:
var myProcess = new Process();
var p = new ProcessStartInfo("cmd.exe");
var sArgs = "/C ffmpeg.exe -i emp.mp3 -f wav - | neroAacEnc -ignorelength -q 0.5 -if - -of emp.mp4";
p.CreateNoWindow = false;
p.RedirectStandardOutput = false;
p.UseShellExecute = false;
p.Arguments = sArgs;
myProcess.StartInfo = p;
myProcess.Start();
myProcess.WaitForExit();

Related

Cannot access the file because it is being used by another process using ffmpeg

I am getting the error:
Cannot access the file because it is being used by another process
I have a C# desktop app.
I am using the Process class to convert images to a video file by using FFMPEG.
This is my code:
using (Process serverBuild = new Process())
{
serverBuild.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
string args = " -f image2 -i " + {path} + "\\img%05d.jpg -s 352x288 -filter:v \"setpts=5.0*PTS\" -y " + {path}\\File.mp4;
serverBuild.StartInfo.Arguments = args;
serverBuild.StartInfo.FileName = "ffmpeg.exe";
serverBuild.StartInfo.UseShellExecute = false;
serverBuild.StartInfo.RedirectStandardOutput = true;
serverBuild.StartInfo.RedirectStandardError = true;
serverBuild.StartInfo.CreateNoWindow = true;
serverBuild.Start();
// string output = serverBuild.StandardOutput.ReadToEnd();
//Log.Instance.Debug(serverBuild.StandardError.ReadToEnd());
serverBuild.WaitForExit();
serverBuild.Close();
}
Directory.Delete(ExportRoute + FFMPEGPacket.LicenseKey + "\\" + FFMPEGPacket.Guid, true);
//which raise the error..
The images are all deleted but the File.Mp4 is not and that is the error. The error says that the newly created MP4 file cannot be deleted.
NB
This is partial code to illustrate the error
You may try the following code to create the file (it worked for me):
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = exe_path;
// replace your arguments here
psi.Arguments = string.Format(#" arguments ")
psi.CreateNoWindow = true;
psi.ErrorDialog = true;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = false;
psi.RedirectStandardError = true;
Process exeProcess = Process.Start(psi);
exeProcess.PriorityClass = ProcessPriorityClass.High;
string outString = string.Empty;
exeProcess.OutputDataReceived += (s, e) =>
{
outString += e.Data;
};
exeProcess.BeginOutputReadLine();
string errString = exeProcess.StandardError.ReadToEnd();
Trace.WriteLine(outString);
Trace.TraceError(errString);
exeProcess.WaitForExit();
exeProcess.Close();
exeProcess.Dispose();
FFMPEG might still be rendering the creation of video from images after it closes, so it might be worth if you place a Threading.Thead.Sleep(5000) 5 secs; before delete.
Try that:
File.WriteAllBytes(path, new byte[0]);
File.Delete(path);

C# run batch file with argument with spaces

I need to run batch file, which has path (can contains spaces) as argument.
Batch file is really simple:
echo off
echo %1 > echotest.txt
Csharp code I am using to run this batch file:
ProcessStartInfo info = new ProcessStartInfo();
info.UserName = KIM_USER;
info.Password = ConvertToSecureString(KIM_USER_PASSWORD);
info.FileName = theTask.Path;
info.Arguments = "\"" + TranslateParameter(theTask.Parameter) + "\"";
info.Domain = Environment.MachineName;
info.WorkingDirectory = Path.GetDirectoryName(theTask.Path);
info.UseShellExecute = false;
info.CreateNoWindow = true;
Process batProcess = Process.Start(info);
batProcess.WaitForExit();
Basically in parameter comes e.g {Test_Path} and this is in TranslateParameter converted to real path, e.g: D:\Test Path\ (contains spaces)
This does not work for me, it returns me exit code 1 everytime.
If i remove \" from info.Arguments, it works, but in output file is just D:\Test
Any suggestions?
Regards
Can you try this if that works:
ProcessStartInfo info = new ProcessStartInfo();
info.UserName = KIM_USER;
info.Password = ConvertToSecureString(KIM_USER_PASSWORD);
info.FileName = theTask.Path + " \"" + TranslateParameter(theTask.Parameter) + "\"";
//info.Arguments = "\"" + TranslateParameter(theTask.Parameter) + "\"";
info.Domain = Environment.MachineName;
info.WorkingDirectory = Path.GetDirectoryName(theTask.Path);
info.UseShellExecute = false;
info.CreateNoWindow = true;
Process batProcess = Process.Start(info);
batProcess.WaitForExit();

Run Bash Commands from Mono C#

I am trying to make a directory using this code to see if the code is executing but for some reason it executes with no error but the directory is never made. Is there and error in my code somewhere?
var startInfo = new
var startinfo = new ProcessStartInfo();
startinfo.WorkingDirectory = "/home";
proc.StartInfo.FileName = "/bin/bash";
proc.StartInfo.Arguments = "-c cd Desktop && mkdir hey";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start ();
Console.WriteLine ("Shell has been executed!");
Console.ReadLine();
This works best for me because now I do not have to worry about escaping quotes etc...
using System;
using System.Diagnostics;
class HelloWorld
{
static void Main()
{
// lets say we want to run this command:
// t=$(echo 'this is a test'); echo "$t" | grep -o 'is a'
var output = ExecuteBashCommand("t=$(echo 'this is a test'); echo \"$t\" | grep -o 'is a'");
// output the result
Console.WriteLine(output);
}
static string ExecuteBashCommand(string command)
{
// according to: https://stackoverflow.com/a/15262019/637142
// thans to this we will pass everything as one command
command = command.Replace("\"","\"\"");
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = "-c \""+ command + "\"",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
proc.WaitForExit();
return proc.StandardOutput.ReadToEnd();
}
}
This works for me:
Process.Start("/bin/bash", "-c \"echo 'Hello World!'\"");
My guess is that your working directory is not where you expect it to be.
See here for more information on the working directory of Process.Start()
also your command seems wrong, use && to execute multiple commands:
proc.StartInfo.Arguments = "-c cd Desktop && mkdir hey";
Thirdly you are setting your working directory wrongly:
proc.StartInfo.WorkingDirectory = "/home";

bash pipes - I am trying to call script from c#

I have a cygwin bash scripts that works:
#!/bin/sh
cd myc
cp Stats.txt Stats.txt.cpy;
cat Stats.txt.cpy | sort -n -k1 | gawk '{sum+=$2; print $0,sum}' > Stats.txt
I want to "call" it from C#:
string cmd="myscript.sh";
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo psi =
new System.Diagnostics.ProcessStartInfo(#"C:\Cygwin\bin\bash.exe");
psi.Arguments = cmd;
psi.WorkingDirectory = "C:\\cygwin\\home\\Moon";
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
proc.StartInfo = psi;
proc.Start();
string error = proc.StandardError.ReadToEnd();
string output = proc.StandardOutput.ReadToEnd();
this.textBox1.AppendText(error);
this.textBox1.AppendText(output);
It works fine from cygwin terminal BUT from C# I get:
Input file specified two times.
I suspect this is a pipes thing - can anyone help?
It was a path issue.
You need to set path in the script - otherwise it uses a different "non-cygwin" path and gets wrong commands.

What is wrong in how I start the process?

When I run the following from cmd it runs ok
>mysql -h 134.86.157.132 -u sas vm < c:\vm.sql
When I try to do the same from code it does not work
ProcessStartInfo info = new ProcessStartInfo("mysql");
info.Arguments = #"-h 134.86.157.132 -u sas vm < c:\vm.sql";
info.Domain = "134.86.157.132";
info.UserName = "sas";
info.Arguments = #"vm < c:\vm.sql";
info.UseShellExecute = false;
Process.Start(info);
What am I doing wrong here? It does not work and I get some wrong password exception?
Edit:
I run it like this now
ProcessStartInfo info = new ProcessStartInfo("mysql");
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.Arguments = #"-h 134.86.157.132 -u sas vm < c:\vm.sql";
Process.Start(info);
and get following error The system cannot find the file specified
"-h 134.86.157.132 -u sas vm" are the arguments, don't use domain and username.
You also need to redirect the standard input stream to pass your vm.sql file in. See this example: ProcessStartInfo.RedirectStandardInput Property
Try it like this:
ProcessStartInfo info = new ProcessStartInfo("mysql");
info.Arguments = #"-h 134.86.157.132 -u sas vm < c:\vm.sql";
info.UseShellExecute = false;
Process.Start(info);
You're setting UseShellExecute to false, but it's the shell that interprets the "<" part to redirect stdin from a file.
Unless there's a specific reason why you need UseShellExecute to be false, set it to true. Alternatively, redirect standard input for the new process, and give it the data directly.
EDIT: As specified in other answers, keep the original arguments, and don't set Domain/UserName on the ProcessStartInfo. Those refer to Windows usernames and domains, not MySQL ones.
At that point you'll be able to set UseShellExecute to true with no ill effects, with any luck.
How about something like from this post:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = new StreamWriter(p.StandardInput))
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("mysql -h 134.86.157.132 -u sas vm < c:\vm.sql");
}
}

Categories

Resources