how to popen xterm on osx from c++ application? - c++

I do this:
popen("xterm -e ' some bash script ' ","r");
and it works fine if I launch my application from a terminal command line.
but if I double click in the finder to launch it (i.e. non terminal), the application runs, but the xterm doesn't appear.
(xterm is maybe not the right solution on osx, what I want to do is to open a terminal from popen, interact with the user inside the terminal, and return the result of this interaction to the main program)

The output shown in xterm's window (or likely other terminals) will not be read by popen, so that part is unclear. However, you say that works from a terminal window.
Another problem is that the DISPLAY variable needed to run xterm may not be set in the environment where the finder is running. You can work around that by adding a suitable -display option to the command-line. For instance, if your application is running and displaying on the local machine (likely), you could try
popen("xterm -display :0.0 -e ' some bash script ' ","r");
When capturing output from xterm, there are two types of output to consider:
error messages from xterm itself are written to the standard error
the program running inside xterm, e.g., 'some bash script', will write to the xterm window.
For your example, you could capture the error messages in the pipe (from popen directly by redirecting the standard error in the command to xterm's standard output, e.g.,
popen("xterm -display :0.0 -e ' some bash script ' 2>&1 ","r");
Capturing the output of the bash script is harder. You could redirect the output of the bash script itself, e.g.,
popen("xterm -display :0.0 -e ' some bash script >mylogfile ' ","r");
but that interferes with interaction. A better solution might be to use the script program, doing something like this:
popen("xterm -display :0.0 -e script mylogfile ' some bash script ' ","r");

Related

Calling multiple commands via system() under windows doesn't work

So basiclly im trying to use this:
int main()
{
system("adb kill-server \n"
"adb devices \n"
"adb start-server & \n"
"var=$(adb shell \"pidof com.rok\")\n"
"AFTER=`echo $var | sed 's/\\r//g'`\n"
"echo \"$AFTER\"\n"
"adb shell \"kill -STOP $AFTER\"\n"
"adb shell sleep 2\n"
"adb shell \"kill -CONT $AFTER\"");
return 0;
}
thing is this works in Clion without any error, but i must do this in visual studio and in visual studio i cannot do it like that i have to do every system command alone like:
system("adb kill-server");
system("adb devices");
system("adb start-server");
system("var=$(adb shell \"pidof com.rok\")");
system("AFTER=`echo $var | sed 's/\\r//g'`");
system("adb shell \"kill -STOP $AFTER\"");
so now the thing is when i run it like this everything works except this two lines:
system("var=$(adb shell \"pidof com.rok\")");
system("AFTER=`echo $var | sed 's/\\r//g'`");
even though they perfectly works on clion they dont in visual studio, i cannot find a way to solve this problem, this is the error:
'var' is not recognized as an internal or external command,
operable program or batch file.
'AFTER' is not recognized as an internal or external command,
operable program or batch file.
can anyone explain why this happens? and how can i solve this problem?
Each call of system() creates it's own shell as a subprocess, that's why multiple subsequent system() calls don't work if you e.g. try to set shell variables or do a cd command (expecting subsequent commands running in a specific directory).
The easiest way to do it, is to create a little temporary script file containing all the commands and execute this one with a single system() call:
// A raw string literal to make escaping easier
// (see https://en.cppreference.com/w/cpp/language/string_literal)
std::string cmds = R"xxx(
adb kill-server
adb devices
adb start-server &
var=$(adb shell "pidof com.rok")
AFTER=`echo $var | sed 's/\r//g'`
echo "$AFTER"
adb shell "kill -STOP $AFTER"
adb shell sleep 2
adb shell "kill -CONT $AFTER"
)xxx";
std::ofstream cmdFile("tempCmdFile.cmd");
cmdFile << cmds;
cmdFile.close();
system("tempCmdFile.cmd");
You probably should tidy up the tempCmdFile.cmd up afterwards (i.e. remove it). But I hope you grasp what the code above does.
Also I am not so sure that
AFTER=`echo $var | sed 's/\r//g'`
will work in a windows shell, as you expect it to do. You probably need a different solution for that, or a *nix like shell to run it (e.g. MinGw provides one).

Want to run a cpp executable in a new terminal and then send a file into the input stream

I would like to run a c++ executable in a new linux terminal, which I am doing using:
xterm -e executable options &disown
and this works. However, I also need to parse a text file through the command line. Normally, the file would be parsed by:
./executable options < inputFile.txt
and then the file is handled by the c++ code using this function:
void parse_lines(istream &in){
verify_version_number(in);
read_variables(in);
...
}
However the following line does not work:
xterm -e executable options < inputFile.txt &disown
How can I run the executable in a new terminal and then send the contents of inputFile.txt into the istream?
Thanks!
If you put quotes around the command, it will be sent to the shell as a single command, and the special characters < and & will be interpreted in the shell running within xterm rather than in the shell where you start xterm:
xterm -e "executable options < inputFile.txt &disown"
Try x-terminal-emulator instead of xterm. Perhaps it works.

Process gets killed after xterm terminates

I want to run xterm terminal in C++ to create a Linux process like this
system("xterm -e adb start-server")
The adb process is created but after that command it gets killed. I was trying to solve this problem by using nohup and screen but nothing works. I know that I have to put the adb process into background, but how to do that with xterm?
Edit:
I'm loking for solution that will terminate/close the xterm window, but not the adb process. Later I want to use multiple commands in the same xterm window like
system("xterm -e \"adb start-server; adb connect 192.168.X.XXX;\"");
and all output (and eventually errors) I want to see in the same xterm.
You can do it like this:
xterm -e /bin/bash -c "adb start-server; /bin/bash"

Capture entire output of bash commands while in ruby?

I have a Ruby script that I have developed that allows me to install and build multiple C++ packages. I am able to execute the Ruby script and install the packages with no errors.
However, I would like to be able to capture all of the output, including cerr, to a "log" file of my choosing. I am able to redirect Ruby's cerr and standard output, but I cannot capture the bash commands: qmake, make, or make install cerr. The output still flows to the terminal.
I want to be able to run the Ruby script and not see any debug messages from any qmake, make, or make install bash commands, but be able to check a log file later for build results.
you can do
require 'open3'
log = File.new("#{your_log_dir}/script.log", "w+")
command = "make"
Open3.popen3(command) do |stdin, stdout, stderr|
log.puts "[OUTPUT]:\n#{stdout.read}\n"
unless (err = stderr.read).empty? then
log.puts "[ERROR]:\n#{err}\n"
end
end
%x[#insert bash command here] captures the response. If you need to handle STDERR you'll want to pipe it to STDOUT I believe.
To directly dump stdout and stderr of a child process to files:
cmd = ['ls', '-ahl', '/my/directory'] # example directory listing
pid = Process.spawn *cmd, out: '/path/to/stdout/log', err: '/path/to/stderr/log'
Process.wait pid
You may also pass file descriptors instead of path strings.
If you're on Mac OS or Linux, you can use standard redirection and a simple shell call if you want to capture the STDOUT and STDERR to a variable in your script:
asdf = `ls foo 2>&1`
asdf # => "ls: foo: No such file or directory\n"
2>&1 simply redirects STDERR in the command output to STDOUT, which is captured when the program runs.
If you want to redirect both STDOUT and STDERR to the same file for later, use:
`ls foo > output.log 2>&1`
The STDOUT has to be redirected before &2>1 will take effect, but that will capture both.
For more information see the "Redirect" section of man sh.

Use GDB to debug a C++ program called from a shell script

I have a extremely complicated shell script, within which it calls a C++ program I want to debug via GDB. It is extremely hard to separate this c++ program from the shell since it has a lot of branches and a lot of environmental variables setting.
Is there a way to invoke GDB on this shell script? Looks like gdb requires me to call on a C++ program directly.
In addition to options mentioned by #diverscuba23, you could do the following:
gdb --args bash <script>
(assuming it's a bash script. Else adapt accordingly)
There are two options that you can do:
Invoke GDB directly within the shell script. This would imply that you don't have standard in and standard out redirected.
Run the shell script and then attach the debugger to the already running C++ process like so: gdb progname 1234 where 1234 is the process ID of the running C++ process.
If you need to do things before the program starts running then option 1 would be the better choice, otherwise option 2 is the cleaner way.
Modify the c++ application to print its pid and sleep 30 seconds (perhaps based on environment or an argument). Attach to the running instance with gdb.
I would probably modify the script to always call gdb (and revert this later) or add an option to call gdb. This will almost always be the easiest solution.
The next easiest would be to temporarily move your executable and replace it with a shell script that runs gdb on the moved program. For example, in the directory containing your program:
$ mv program _program
$ (echo "#!/bin/sh"; echo "exec gdb $PWD/_program") > program
$ chmod +x program
Could you just temporarily add gdb to your script?
Although the answers given are valid, sometimes you don't have permissions to change the script to execute gdb or to modify the program to add additional output to attach through pid.
Luckily, there is yet another way through the power of bash
Use ps, grep and awk to pick-out the pid for you after its been executed. You can do this by either wrapping the other script with your own or by just executing a command yourself.
That command might look something like this:
process.sh
#!/usr/bin/env bash
#setup for this example
#this will execute vim (with cmdline options) as a child to bash
#we will attempt to attach to this process
vim ~/.vimrc
To get gdb to attach, we'd just need to execute the following:
gdb --pid $(ps -ef | grep -ve grep | grep vim | awk '{print $2}')
I use ps -ef here to list the processes and their arguments. Sometimes, you'll have multiple instances of a program running and need to further grep down to the one you want
the grep -ve grep is there because the f option to ps will include the next grep in its list. If you don't need the command arguments for additional filtering, don't include the -f option for ps and ignore this piece
grep vim is where we're finding our desired process. If you needed more filtering, you could just do something like grep -E "vim.*vimrc" and filter down to exactly the process that you're trying to attach to
awk '{print $2}' simply outputs just the process' pid to stdout. Use $1 if you're using ps -e instead of ps -ef
My normal setup is to run such script that starts my process in 1 tmux pane and having typed something similar to the above in a bottom pane. That way if I need to adjust the filtering (for whatever reason), I can do it pretty quickly.
Usually though, it will be the same for a specific instance and I want to just attach automatically after its been started. I'll do the following instead:
runGdb.py
#!/usr/bin/env bash
./process.sh &
PID=$(ps -ef | grep -ve grep | grep -E "vim.*vimrc" | awk '{print $2}')
#or
#PID=$(ps -e | grep vim | awk '{print $1}')
gdb --pid $PID
This assumes that the original process can be safely run in the background.