QThread doesn't provide output from called shellscript - c++

I have a function that executes system calls and writes the output into a QTextEdit.
string SystemCallFactory::runSysCallWithoutButton(unique_ptr<SystemCall> sysCall)
{
cout << "Running " << sysCall->getCommand() << endl;
textEdit->setText("");
textEdit->repaint();
QProcess process;
process.start(QString::fromStdString(sysCall->getCommand()));
process.waitForFinished();
QString output(process.readAllStandardOutput());
textEdit->append(output);
textEdit->repaint();
return output.toStdString();
}
The problem is that this works when getCommand() is a real command, e.g. ls /etc but does not work correctly when it refers to a shellscript. In my calls, the call that does not work looks like
/home/turtle10000/tilematching.sh /some/folder /some/specific.file
The script gets executed and does what it's supposed to do, but readAllStandardOutput() returns an empty string. When I run it in a terminal, it shows the expected output.
This is the shellscript:
#!/bin/sh -v
WORKSPACE=$1
SVPFILE=$2
cd $WORKSPACE
ls -1 *.all > datalist.0.mb-1
mbset -I datalist.0.mb-1 -PSVPMODE:1 -PSVPFILE:$SVPFILE
mbprocess -I datalist.0.mb-1
ls -1 *p.mb58 > datalist.1.mb-1
mbset -I datalist.1.mb-1 -PSONAROFFSETX:-0.079 -PSONAROFFSETY:0.196 -PSONAROFFSETZ:0.048 -PVRUOFFSETX:-0.4473 -PVRUOFFSETY:0.000 -PVRUOFFSETZ:-0.3395 -PROLLBIAS:0.1 -PPITCHBIAS:1.32
mbprocess -I datalist.1.mb-1
ls -1 *pp.mb58 > datalist.2.mb-1
mblist -I datalist.2.mb-1 -MA -O^X^Y-z -JU > output.xyz
#remove broken lines (error in input files)
sed -ie '/ /d' output.xyz
Edit: as Botje guessed, some of output appears in stderr instead of stdout.

As Botje suggested, I checked if the output went to stderr and it did. For whatever reason, the output of mbset and mbprocess, tools from the mb-system package, goes to stderr.
In this case, I changed the line
QString output(process.readAllStandardOutput());
to
QString output(process.readAllStandardError());
Another option would probably be to channel the stderr output to stdout in the script.

Related

Popen giving some strange character in output when running multiple command in it

I write code to fetch the fragmented packet by using a unique Identification field from pcap file. So I run scripting command in my C++ program.
First tshark command will fetch all the identification field from the packet with the callID mentioned in the filter and the second one will fetch all the fragmented packet identification field in that pcap.
And awk command compare then and find the unique identification field present in both the tshark command output.
Command will be like---
cmd = (awk 'FNR==NR{a[$0]=1;next}($0 in a)' <((/usr/sbin/tshark -r
/data/traces/TRACES.pcap 'sip.Call-ID=="1-4740#10.133.0.1" or
sip.Call-ID=="57b116c-5b20924e-93dcd"' -T fields -e ip.id)
2>/dev/null) <((/usr/sbin/tshark -r /data/traces/TRACES.pcap
'ip.flags.mf==1' -T fields -e ip.id) 2>/dev/null)) 2>/dev/null
Reading data by
FILE * stream = popen(cmd.c_str(), "r");
if (!stream)
{
LOG_DEBUG("popen failed");
}
fflush(stream);
NOTE:: I tried with fflush and without fflush still giving me strange
character.
while(fgets(buffer, 40, stream) != NULL)
{
data = buffer;
result += data + '\n';
}
if(data.empty()) {
data = buffer;
result = data + '\0';
}
NOTE:: Tried with the system() command also but this also returns me a strange Character
OUTPUT will be like --> 0^_iÏO^?
I notice a strange thing that when I execute tshark command individually and save the output in a different file and then using awk command on that files then it will give the correct output.
And Command is correctly running in the terminal also.

How can I get the return value of `wget` from a sh script into an `int` variable

OS: Linux raspberrypi 4.19.58-v7l+ #1245 SMP Fri Jul 12 17:31:45 BST 2019 armv7l GNU/Linux
Board: Raspberry Pi 4
I have a script:
#!/bin/bash
line=$(head -n 1 /var/www/html/configuration.txt)
file=/var/www/html/4panel/url_response.txt
if [ -f "$file" ]; then
wget_output=$(wget -q -i "$line" -O $file --timeout=2)
echo "$?"
else
echo > $file
chown pi:pi $file
fi
which I call from a C++ program using:
int val_system = 0;
val_system = system("/var/www/html/4panel/get_page.sh");
std::cout<<"System return value: "<<val_system<<std::endl;
If there is something wrong with the script, echo "$?" will output the return value of wget, but val_system will always be 0.
Does system() returns the value of echo "$?" ? In which case 0 is correct. And if that is the case how can I put the return value of wget in val_system ?
I have taken a situation in which echo "$?" always returns 8, basically I've entered an incorrect URL and:
I have tried deleting echo "$?" but val_system still returned 0;
With echo "$?" deleted I have changed the wget line to wget -q -i "$line" -O $file --timeout=2 and val_system now returns 2048.
None of my attempts bared any fruit and I have come here to seek guidance. How can I make val_system / system() return what echo "$?" returns ?
How can I get the return value of wget from the script into an int variable that's inside the C++ program that calls the script ?
The integer value system() returned contains extra information about executed command's status along with its exit code, see system() and Status Information. You need to extract exit code using WEXITSTATUS macro, like:
std::cout << "System return value: " << WEXITSTATUS(val_system) << std::endl;
If you want to echo the status and return it, you will need to save the value of $? to a variable, and exit with it explicitly.
wget_output=$(wget -q -i "$line" -O $file --timeout=2)
status=$?
...
echo $status
...
exit $status
If you don't need to execute echo or any other command between the call to wget and the end of the script, you can rely on the script exiting with the last status (i.e the one corresponding to the call to `wget) implicitly.

Avoid line return when calling AINSI escape sequence

I made this function who change the title of a terminal window by using ainsi escape sequence but after the call of this function a line is jumped in console, how avoid this ?
void setConsoleTitle(std::string const& title)
{
m_title = title;
std::string cmd1 = "echo \"\033]0;";
cmd1 += title;
cmd1 += "\007\"";
system(cmd1.c_str());
}
Thanks.
ReallY DON'T use system here (it starts a new process, in which a shell is run, and then runs echo in that shell, and tears down that new process - which is a lot of work to output a handful of characters to the screen, that can just as well be output with cout or similar - system is acceptable to use if you, say, need to run a compiler or unpack a zip file - something that isn't easy to do in your own program). But if you insist on using system, then use echo -n ..., where man echo explains it as:
-n do not output the trailing newline
However, just using cout will do fine here:
cout << "\033]0;" << title << "\a";
(\a is "alarm", the same as \007 but portable in case your system doesn't use character number 7 for "ring the bell")
Why you want to print "noise" is beyond me, but the above does the same thing as your "echo" command.

Audit bash commands for bash RPG

I want to be able to write a program that when you type in commands, it will do things like count the amount of times you've used cd. Something similar to this:
[ : ~ $] cd public_html
Congratulations! You've earned the Badge 'cd master!'. Level up!
All my C++ file consists of so far is:
#include <iostream>
int main(int argc, char* argv[]) {
int counter = 0;
for (int i = 1; i < argc; i++) {
std::cout << argv[i] << std::endl;
if (argv[i] == "cd")
std::cout << "Badge earned 'cd master!' +5120 experience points" << std::endl;
}
return 0;
}
As it reflects one attempted solution involving:
#!/bin/sh
bash | tee ./main
and
bind 'RETURN: "echo $(!!) | tee ~/.main \n"'
I've decided to go with
export PROMPT_COMMAND='history | tail -n1'
But that would mean having to parse the output.
What's the easiest way of accomplishing this?
edit
Here's what I've managed to produce:
#!/bin/sh
export COUNTER=0
export MAXWIDTH=10
export TNL=1000
update_prompt() {
export PS1="> "
}
cd() {
COUNTER=$(($COUNTER + 25));
echo +25;
builtin cd $#;
}
help() {
echo "custom commands are: score";
}
score() {
echo $COUNTER"/"$TNL
BAR=$(yes "#" | head -n 10 | tr -d '\n')
OVERLAY=$(yes "%" | head -n 10 | tr -d '\n')
WIDTH=$(echo "$COUNTER*$MAXWIDTH/$TNL" | bc)
FIRST=${BAR:0:WIDTH}
SECOND=${OVERLAY:0:$((MAXWIDTH-WIDTH))}
echo "["$FIRST$SECOND"]"
}
exit() {
echo "Bye bye";
builtin exit $#;
}
export -f update_prompt
export -f cd # export the function
export -f help
export -f score
export -f exit
bash # run subshell with the exported functions
update_prompt
An easy solution is to overwrite the cd command of your shell inside the shell itself. For example, in Bash or ZSH:
cd() {
echo "Congratulations";
builtin cd $#;
}
(This is for example used in projects like autoenv.)
You can do the same for all other commands. You can also call your C++ code from there.
If you want to put that into a script, e.g. name it learn-bash.sh:
cd() { ... }
export -f cd # export the function
bash # run subshell with the exported functions
Another solution, where you have much more power, but which is way more involved: take the source code of Bash (it's C) and extend it (by C or C++). Then you can basically do whatever you want. And you have everything directly there, i.e. the parsed commands, etc.
After every command COMMAND_PROMPT is executed within bash. You could use that with history to see the last command used.
You can read here on how PS1, PS2, PS3 and COMMAND_PROMPT work in bash.
There are a few answers on exactly this question already on SO:
How can I intercept commands that contain a certain string?
bash: how to intercept every command
bash: How to intercept command line and do various actions based on the contents?
I've done something similar a while ago, and here's the solution I've found.
You want to add the following lines to .bashrc:
hook() {
whatever "$#"
}
invoke_hook() {
[ -n "$COMP_LINE" ] && return
[ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return
local command=`history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//g"`;
hook "$command"
}
trap 'invoke_hook' DEBUG
Replace whatever with your C++ program. This will execute your hook before each command, and will pass the original command as the arguments.

How to use dtrace to detect file transfer

I want to use "dtrace" to track file tranfer in OSX 10.8 , like when command "mv /folder1/file1 /folder2" is run .
I know there're probes like create/link/unlink/rename/chdir can be used in the form of
dtrace -n 'syscall::create:entry { printf("%s %s", execname, copyinstr(arg0)); }'
but how to trace this "mv" command ?
rename is the function you are after:
dtrace -n 'syscall::rename:entry { printf("mv %s %s\n",copyinstr(arg0),copyinstr(arg1)); }'
(Add sudo infront if required)