C++ parsing a command line - c++

I am trying to run two of the command lines in a C++ program, but landing in a strange error. The command lines that i want to run are
vlc -vvv dshow:// :dshow-vdev='USB Video Device' :dshow-adev="" :live-caching=50 :sout=#transcode{vcodec=WMV2,vb=800,acodec=wma2,ab=128,channels=2,samplerate=44100}:duplicate{dst=udp{dst=localhost:1234},dst=display} :sout-keep
vlc -vvv udp://#localhost:1234:network-caching=50
They both run fine on command prompt. But when in use a C++ system shell call to run these, the first one fails, where as second one works. The way i run these in C++ is as follows:
system( "\"G:/Program Files/VideoLAN/VLC/vlc\" -vvv dshow:// :dshow-vdev=\"USB Video Device\" :dshow-adev=\"none\" :live-caching=50 :sout=#transcode{vcodec=WMV2,vb=800,acodec=wma2,ab=128,channels=2,samplerate=44100}:duplicate{dst=udp{dst=localhost:1234},dst=display}:sout-keep");
system( "\"G:/Program Files/VideoLAN/VLC/vlc\" -vvv udp://#localhost:1234:network-caching=50");
The first command throws an error "G:/Program is not recognized as an internal or external command, operable program or batch file.", which is strange since the way both commands handle path to the file is the same. Please let me know the reason for this.
The computer is running on Windows XP and i am using Microsoft Visual Studio 2010.

Replace
system( "\"G:/Program Files/VideoLAN/VLC/vlc\" -vvv dshow:// :dshow-vdev=\"USB Video Device\" :dshow-adev=\"none\" :live-caching=50 :sout=#transcode{vcodec=WMV2,vb=800,acodec=wma2,ab=128,channels=2,samplerate=44100}:duplicate{dst=udp{dst=localhost:1234},dst=display}:sout-keep");
system( "\"G:/Program Files/VideoLAN/VLC/vlc\" -vvv udp://#localhost:1234:network-caching=50");
with
system( "G:\\\"Program Files\"\\VideoLAN\\VLC\\vlc -vvv dshow:// :dshow-vdev=\"USB Video Device\" :dshow-adev=\"none\" :live-caching=50 :sout=#transcode{vcodec=WMV2,vb=800,acodec=wma2,ab=128,channels=2,samplerate=44100}:duplicate{dst=udp{dst=localhost:1234},dst=display}:sout-keep");
system( "G:\\\"Program Files\"\\VideoLAN\\VLC\\vlc -vvv udp://#localhost:1234:network-caching=50");

using system() to run commands has the following caveats and switch requirements for what you are attempting (from cmd documentation) as it effectively runs cmd /C *mycommandhere*:
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
If you reformat your commands as:
system("cmd /S /C \"\"c:\\testDir\"\"\\dir with spaces\"\"\\myexe.exe");
that should work:) ( in the previous version I had forgotten some escape characters).
There is also a related question here.
Or if it is for windows only You could utilise ShellExecute or ShellExecuteEx with some documentation on the aforementioned at msdn, here
Hope this helps, as I just lost connection to my home environment and cannot get a fixed version for my previous fix at present, will do so tonight however.

Related

C++ System(); function not working as expected / Windows console commands in C++

Hello friendly people of stack overflow!
I am currently working on a project using an Arduino Uno. Because i create all my files and sketches using a c++ program, i want to eliminate the Arduino IDE from my workflow. For that i can very easily use avrdude (which the IDE uses anyway) and some windows console commands.
These are the commands that i am using:
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avrdude" "-CC:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf" -v -patmega328p -carduino -PCOM4 -b115200 -D -Uflash:w:C:\Users\Jzargo\AppData\Local\Temp\arduino_build_766345/EPaper_TestDither.ino.hex:i
"EPaper_TestDither.ino" is the arduino Sketch i want to compile and upload. When using the console and manually inserting the above commands, everything works as expected.
And here comes the part I am struggeling with:
Because i also dont want the user to manually open the console and type in some gibberish code, i want to integrate this command into my c++ program using the system(); function:
system("\"C:\\Program Files(x86)\\Arduino\\hardware\\tools\\avr/bin/avrdude\" \" - CC:\\Program Files(x86)\\Arduino\\\hardware\\tools\\avr/etc/avrdude.conf\" -v -patmega328p -carduino -PCOM4 -b115200 -D -Uflash:w:C:\\Users\\Jzargo\\AppData\\Local\\Temp\\arduino_build_766345/EPaper_TestDither.ino.hex:i");
When executing this function, the command cannot be executed because "Der Befehl "C:\Program" ist entweder falsch geschrieben oder konnte nicht gefunden werden.", which roughly translates to "The Command "C:\Program" is not written correctly or cant be found".
I do not understand why the console accepts the command when manually inserting it, but not when using the system(); function.
I hope you can help me figure this out.
Edit: By using
subst H: "C:\Program Files(x86)\Arduino\hardware\tools\avr\bin" and
system("\"H:/avrdude \"-CC:/Program Files (x86)/Arduino/hardware/tools/avr/etc/avrdude.conf\"\" -v -patmega328p -carduino -PCOM4 -b115200 -D -Uflash:w:C:/Users/Jzargo/AppData/Local/Temp/arduino_build_833906/EPaper_TestDither.ino.hex:i");
I was able to upload my sketch. Note the changed Placement of \".
But for some reason, this does not work when using C:\Program Files(x86)\Arduino\hardware\tools\avr\bin instead of H:.
Kindest regards
J'zargo
The command looks messed up with respect to the parameters, although I don't see how exactly that triggers your specific error.
The beginning is OK. The path is properly quoted (double quotes, protected by backslashes from the C compiler). But why do you have slashes and backslashes mixed? In some online examples I saw that people use forward slashes in Windows paths (C:/whatever...) ; that seems to work and is easier than using double backslashes all the time (but it should not trigger your — or any — error).
So system("\"C:\\Program Files(x86)\\Arduino\\hardware\\tools\\avr/bin/avrdude\" ... should call the right executable. Why don't you try that on its own (without parameters) to see whether the error persists?
I suspect that \" - CC:\\Program Files(x86)\\ ... is not correct though. avrdude expects a parameter -C<path>, not - C<path> (note the badly placed spaces before and after the dash).
As an aside, it may not hurt to quote parameters that contain funny characters like colons which may have special meanings.
The general advice for this kind of trouble:
Work in and with paths that do not contain spaces, brackets, or other non-identifier characters. If you don't want to change the avrdude installation path you can use the DOS subst command to create a drive whose root is C:\Program Files(x86) or even C:\Program Files(x86)\Arduino\hardware\tools\avr\bin, e.g. subst H: "C:\Program Files(x86)\Arduino\hardware\tools\avr\bin". The command would then be H:/avrdude :-).
If confronted with a bug you don't understand, simplify the problem radically until a toy version works; then add complexity bit by bit until you encounter the error; that should make it easier to recognize what triggered it.
Edit: I'm not sure this example is valid because I used the msys2 development environment and ran the example in a bash shell; I'm not even sure cmd is called as the system shell by the syste call!
In order to check the system call semantics I wrote the following minimal example (which uses mixed slashes/backslashes as a test). The current directory has a sub directory called "some dir" containing a minimal program showargs which simply writes its command line parameters to stdout:
$ ls -l "some dir" && echo && cat cmdline.c && echo && gcc -o cmdline cmdline.c && ./cmdline.exe
total 56
-rwxr-xr-x 1 Peter None 56097 Apr 16 17:23 showargs.exe
#include <stdlib.h>
int main(int argc, char **argv)
{
system("\".\\some dir/showargs\" 1 2 3");
}
->.\some dir/showargs<-
->1<-
->2<-
->3<-

How to run multiple commands parallel in windows cmd prompt?

I know one can run two commands in one line in Windows CMD like this:
dir & echo foo
But how could one run two commands parallel? I also know that one can achieve this by using START. But then you have to put those commands into a batch file. I would want to launch them parallel from the command line itself.
What I would like to achieve is something like this:
set NODE_ENV=development&& nodemon -e js,jsx,cjsx,css,scss,html,coffee --watch ./app/ server/server.js & set NODE_ENV=development&& node server/hotLoadServer.js
If I run the commands separately in separate windows, they work perfect. But I cannot seem to get them run as a one liner in one cmd prompt. What happens is, the first one is run, the second is not. The first one will remain open, and the second one is never executed.
This executes two tasks in parallel and open one window for each:
# powershell
start ping google.com; start ping example.com
# cmd
start ping google.com & start ping example.com
This does the same, but the /B option prevents any new window from opening (in cmd):
start /B ping google.com & start ping example.com
I didn't find any direct equivalent in powershell, although starting this in powershell does the trick:
cmd /C 'start /B ping google.com & start /B ping example.com'
Note also that powershell's Start-Job cmdlet allows users to start background jobs.
You can run parallel threads in one cmd session. use 'cmd' command with /c parameter, it will Carries out the command specified by string and then stops.
e.g
cmd /c echo done
for more reference :https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cmd.mspx?mfr=true

system("history") not working

I've run into a snag, I'm trying to implement a linux shell program of sorts with C++ and many of my commands seem to work, however, when I try to get the history(list all recently executed commands) I get an error of "sh: 1: history: not found" the below line is all that runs in the area, what is the issue?
system("history"); //produces the error above ^
If I do
$ history
from the command line it's fine...why is it not fine in C++?
system executes a program using /bin/sh, but history is a bash builtin.
You might look at the contents of ~/.bash_history instead. (Note (by leemes) .bash_history is only updated after closing a previous bash session, as well as it is not updated by executing a command with system.)
Because it's a bash shell builtin not necessarily accessible through /bin/sh -c` (which may be the bourne shell).

How do I open a terminal window with C++ in Ubuntu?

I recently decided to start teaching myself C++ and thought a simple encryption project would be a good place to start, since it covers most of the basics (cout, cin, opening files, etc). Is there a way to have the code open a terminal window similar to the one opened when I compile and run from sublime text?
I have tried this so far, but it hasn't changed anything.
string cmd = "gnome-terminal-x sh-c 'ls-l; exec bash'";
system(cmd.c_str());
Essentially, I would like to be able to run the program by clicking the .exe, and have the terminal where all of the input and output goes pop up.
You don't need to write any code, you just need to configure the shortcut to launch the program in a terminal. Here's a Gnome dialog that shows that option:
Problem seems to be gnome-terminal, or then just my failure to give it the right arguments. For example gnome-terminal -x sh -c 'ls -l ; exec bash' from command line in another terminal just opens an empty gnome-terminal and spits out a bunch of glib warnings to original terminal... (Note to readers: if you can give the right command that works for gnome-terminal, please let me know in comments or just edit this paragraph.)
However, using xterm works, for example xterm -e sh -c 'ls -l; exec bash', or a line for your code:
string cmd = "xterm -e sh -c 'ls -l; exec bash'";
As a side note, the command to open the default x terminal window of the DE is x-terminal-emulator, but it quite often has the practical problem of different terminals taking different arguments, so sadly you're probably better of using a specific terminal, like that xterm, and requiring that to be installed, or letting user to configure what terminal to use, with what arguments (though letting user to specify any command to be run can also be a security risk, if user is not always trusted).
Just be very careful with escaping. For example, when you test the command form command line, and then copy-paste it to C++ string literal, you need to escape every " and \ one more time for C++. If you have trouble with this, check out C++11 raw strings.
Escaping becomes extra important if you construct the command string at runtime, and especially if you accept user input and add that to the string. In that case, better search for and use some existing library like GLib, or sanitize the user input very carefully (ie. just paranoidically reject anything with chars, which may have a special meaning in shell in some context).
If you are actually asking, how can my program open a console window for itself similar to how Windows console programs behave, and redirect it's own stdin, stdout and stderr there, as if it was launched from command line, that that is not very easy from the same binary, and it is not commonly done like that in Unix.
If you want a behaviour like that, you could create a desktop shortcut, but more general way is to write a wrapper shell script, which starts your binary in a terminal. What kind of script exactly, depends on how you want it to behave exactly: what will it do with stdio, will it return or wait for program to exit, how do you want it to find the binary, how does it behave when run from command line instead of double-clicking from GUI, etc.

What is the difference between calling a script from the shell and using system()?

I have built a bash script to start up some processes in my system. It simply calls the process and associated config file. Same as I would call from the command line.
#!/bin/bash
# Start specified process in a new session
setsid $1 &>/dev/null &
So to start up someprocess, I would call from the command line:
root#supercomputer:~# start someprocess
This works like a charm. Every process, every time. But when I make a system call from a different running C++ process, someprocess never starts up.
system( "start someprocess" )
This approach for 90% of my processes, except for one. The only difference in the working and not working processes is that the non-working one uses proprietary libraries underneath. I recently added the setsid option to the bash script in hopes that starting a new session would help, but it made no difference. I've also tried popen, and execv. No change.
So my question is what is the difference between calling something with system() and just making that same call from the command line?
All processes are written in C++ on Linux.
.bashrc is only invoked if bash is run as interactive, non-login shell. If it's invoked as non-interactive shell, as when using system() on a script with a bash shebang, it only reads the configuration file pointed to by $BASH_ENV.
That means you have the following options:
add -l to the shebang - causes the shell to read ~/.profile at startup
set $BASH_ENV to the script you want sourced before calling system()
add -i to the shebang - invokes bash as interactive shell and causes it to read ~/.bashrc, but will also effect how bash handles input/output.
I'd recommend the first option.
You can find a detailed explanation of how bash reads it's startup files here. I'm not sure this will solve your problem completely, but it may at leas shed some light on that part of the issue.
Check the environment variables that are used in the system() call. For example, call system to print out some of the variables, and see if they match what you see from the command line.
Likely they are not being sourced correctly.