Read output in terminal and compare it with a string - c++

How to check whether a program like 'fortune' is already installed programatically?
This is my code:
if(choice==1)
{
cout<<"Need to Install program first? [y/n]: ?"<<endl;
cin>>yn;
if(yn=='y' || yn=='Y')
{
cout<<"Installing..."<<endl;
cout<<"Enter password if asks:"<<endl;
system(" sleep 2");
system("sudo apt-get install fortune");
}
I have tried this, but couldn't get what I want.
dpkg-query -1W fortune 2>&1 | read line ; do echo $line | say ; done
UPDATE: I have solved this long back and thanks to #John Zwinck

If you want to know if a program like fortune is installed, you can simply check if it exists!
if (access("/usr/bin/fortune", R_OK | X_OK) == 0)
printf("we have good fortune\n");
If you have a program which should be somewhere in $PATH but you don't know where, you could try to run it:
if (system("fortune --help") != -1)
printf("we have good fortune\n");

Related

How to check if a drive is connected (mounted)?

is it possible wit Qt Qprocess to detect if a mounted Loacation(maybe NAS) is connected?
Generally i would check in /proc/mounts if there is an entry, but if i disconnect to the NAS the file doesn't realizes it.
with the df command i can check if a mountpoint is available. But if the connection is disconnected the df process doesn't gives an output. Maybe infinite.
I tried it with
QProcess p;
p.start("bash", QStringList() << "-c" <<
"df -P -T /media/storage/ | grep QIS | awk -F ' ' '{print $1}'");
if (p.waitForFinished(2))
{
qDebug() << "Nothing";
p.close();
}
But nothing happens.
It seems that my program "freezes" when i try to df to a directory which ist'n mounted. Is it possible to cancel the process if there is no answer from the df process after, for example, 2 seconds?
Regarding QProcess, QProcess::waitForFinished takes msec as argument, not sec. Furthermore, it is better to connect to QProcess::finished signal instead of blocking the event loop.
That being said, why using QProcess, when there is a QStorageInfo with a mountedVolumes method:
for (const auto &storage : QStorageInfo::mountedVolumes()) {
if (storage.isValid() && storage.isReady()) {
if (!storage.isReadOnly()) {
// ...
}
}
}

QThread doesn't provide output from called shellscript

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.

Bash variable substitution in a function

I have a function read_command defined as:
function read_command {
local __newline __lines __input __newstr __tmp i;
exec 3< "$*";
__newline=$'\n';
__lines=();
while IFS= read <&3 -r __line && [ "$__line" != '####' ]; do
echo "$__line";
__lines+=("$__line");
done
while IFS= read <&3 -r __line && [ "$__line" != '####' ]; do
read -e -p "${__line#*:}$PS2" __input;
local ${__line%%:*}="$__input";
done
__command="";
for i in "${__lines[#]}"; do
__tmp=$(echo "${i}");
__command="${__command} ${__newline} ${__tmp}";
done
echo -e "$__command";
}
In the current directory there is a file named "test", with the following
content:
greet ${a:-"Bob"}
greet ${b:-"Jim"}
####
a: name of friend a
b: name of friend b
####
In the terminal, the command executed is
read_command test
With no input, I am expecting the output of the last statement to be:
greet Bob
greet Jim
But what I get is:
greet ${a:-"Bob"}
greet ${b:-"Jim"}
What is wrong here?
Edit: As suggested by David, adding eval works in some cases except the following one.
j=1;i="export DISPLAY=:0 && Xephyr :${j}&";k=$(eval echo "$i");
echo $k
export DISPLAY=:0
I am expecting k to be "export DISPLAY=:0 && Xephyr :1&", what's wrong here?
Edit: I tried with the following
k=$(eval "echo \"$i\"")
This is the link to the script I am working on.
https://gist.github.com/QiangF/565102ba3b6123942b9bf6b897c05f87
During the first while loop, in echo "$__line", you have __line='greet ${a:-"Bob"}'. When you try to print that, Bash won't be expanding ${a:-"Bob"} into Bob. (Even if you remove the quotes around $__line this won't happen.) To get that effect, you need to add eval, as in, e.g., eval echo "$__line". Unfortunately eval comes with its can of worms, you have to start worrying about interactions between quoting levels and such.

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)