First of all, forgive my awful english.....
This is the prototype
FILE *popen(const char* cmd_string, const char* type);
Here is my question, the book says that when popen function is called, it will call exec to get a shell to execute the cmd_string we give to popen, but I'm not sure which shell will exec get, so can anyone give me an answer?
/bin/sh : From the doc:
The command argument is a pointer to a null-terminated string
containing a shell command line. This command is passed to /bin/sh
using the -c flag; interpretation, if any, is performed by the shell.
Let's try and see:
$ cat test.c
#include <stdio.h>
int main() {
FILE *fp;
char var[5];
fp = popen("echo $0", "r");
fgets(var, 5, fp);
printf("%s", var);
}
$ gcc -Wall test.c
$ ./a.out
sh
Related
I'm using Qt and bash over it, need to execute something like:
bash: cat file | grep string
in Qt:
QString cmd = "cat file | grep string";
QProcess *process = new QProcess;
process->start(cmd);
process->waitForBytesWritten();
process->waitForFinished();
qDebug() << process->readAll();
The problem is in pipe ("|"), and process returs nothing. If there is no ("|"), like
"cat file"
everything is ok.
I tried smth. like
"cat file \\| grep string",
"cat file \| grep string"
but result is the same. If I copy the command and run it in bash everything is ok.
QString::toAscii().data()
and other transforms also have bad result.
The problem is you cannot run a system command with QProcess, but only a single process. So the workaround will be to pass your command as an argument to bash:
process.start("bash", QStringList() << "-c" << "cat file | grep string");
The quick and dirty hack would be this:
QString cmd = "/bin/sh -c \"cat file | grep string\"";
You could also avoid the escaping in there with C++11's R"", but the point is that do not use bash in there because that will make it only work with bash. It will not work on embedded with busybox without bash, just ash, or any other common desktop shell.
/bin/sh is usually a symlink to the shell interpreter used, so that will eventually work.
BUT!
I think you are thinking a bit too low-level when using a high-level C++/OOP framework such as Qt. I would not recommend to invoke the commands in the low-level way when you run it from bash. There is some dedicated high-level convenience API for this use case.
Based on the official documentation, QProcess is supposed to work for pipe'd commands:
void QProcess::setStandardOutputProcess(QProcess * destination)
Pipes the standard output stream of this process to the destination process' standard input.
In other words, the command1 | command2 shell command command can be achieved in the following way:
QProcess process1;
QProcess process2;
process1.setStandardOutputProcess(&process2);
process1.start("cat file");
process2.start("grep string");
process2.setProcessChannelMode(QProcess::ForwardedChannels);
// Wait for it to start
if(!process1.waitForStarted())
return 0;
bool retval = false;
QByteArray buffer;
while ((retval = process2.waitForFinished()));
buffer.append(process2.readAll());
if (!retval) {
qDebug() << "Process 2 error:" << process2.errorString();
return 1;
}
qDebug() << "Buffer data" << buffer;
This is not the main point, but a useful suggestion: do not use QString::toAscii(). That API has been deprecated in Qt 5.
The problem is that when you call process->start(cmd), the commands following the the call to cat are all interpreted as arguments to cat, so the pipe is not doing what you're expecting. If you start with a call to bash with a parameter of a string, you should get what you want: -
QString cmd = "bash -c \"cat file | grep string\"";
Alternatively, you could just call "cat file" and do the search on the returned QString when you read the output from the QProcess
how about this :
QString program = "program";
QStringList arguments;
download = new QProcess(this);
download->start(program, arguments);
If Google brought you here and you are using PyQt5 or PySide2
process1 = QProcess()
process2 = QProcess()
process1.setStandardOutputProcess(process2)
process1.start(cat, [file])
process2.start(grep, [string])
In my project I need to create QObject derived classes (with Q_OBJECT and signals) using a macro. The macro resides in a separate file. Here is a simplified example:
The macro is declared in the file CreateQtClass.h:
#ifndef __CREATEQTCLASS_H__
#define __CREATEQTCLASS_H__
#define CREATE_QT_CLASS( ClassName ) \
class ClassName : public QObject \
{ \
Q_OBJECT \
\
signals: \
Q_SIGNAL void mySignal( void ); \
};
#endif //__CREATEQTCLASS_H__
I use the macro to create my class in the file MyQtClass.h
#ifndef __MYQTCLASS_H__
#define __MYQTCLASS_H__
#include <QObject>
#include "CreateQtClass.h"
CREATE_QT_CLASS( MyQtClass );
#endif //__MYQTCLASS_H__
In my .qbs file, I add MyQtClass.h to the files property, like this:
import qbs
QtApplication {
name: "HelloWorld-Qt"
files: [ "main.cpp", "MyQtClass.h" ]
}
Now, when running qbs build, qbs doesn't run 'moc' on MyQtClass.h. It looks like it doesn't do the scanning correctly, and doesn't detect the Q_OBJECT inside the macro.
(I may note that if the macro declaration and usage are in the same file, everything works fine).
My question:
Is there a way for the user to manually force qbs to run 'moc' on a file?
Maybe we need something like a "force_moc" fileTag (the opposite of "unmocable") which I can apply to a group containing MyQtClass.h.
Addition:
I am adding a simple Makefile and main.cpp to demonstrate that moc works well with the above approach:
The file main.cpp:
#include <QDebug>
#include "MyQtClass.h"
static void mySlot( void )
{
qDebug() << "Hello slot";
}
int main( void )
{
MyQtClass c;
QObject::connect( &c, &MyQtClass::mySignal, &mySlot );
emit c.mySignal();
return 0;
}
The Makefile:
CXX = /usr/bin/g++
MOC = /home/user/programs/Qt5.11.2/5.11.2/gcc_64/bin/moc
INCLUDES = \
-I/home/user/programs/Qt5.11.2/5.11.2/gcc_64/include \
-I/home/user/programs/Qt5.11.2/5.11.2/gcc_64/include/QtCore \
-I/home/user/programs/Qt5.11.2/5.11.2/gcc_64/mkspecs/linux-g++ \
-I/usr/include
LINK_FLAGS = \
-Wl,-m,elf_x86_64,-rpath,/home/user/programs/Qt5.11.2/5.11.2/gcc_64/lib \
-L/home/user/programs/Qt5.11.2/5.11.2/gcc_64/lib \
-m64 /home/user/programs/Qt5.11.2/5.11.2/gcc_64/lib/libQt5Core.so.5.11.2 \
-lpthread
C_FLAGS = \
-g \
-O0 \
-Wall \
-Wextra \
-m64 \
-pipe \
-fexceptions \
-fvisibility=default \
-fPIC \
-DQT_CORE_LIB \
$(INCLUDES) \
-std=c++11
SOURCES = main.cpp
OBJS = $(SOURCES:%.cpp=%.cpp.o)
HEADERS_THAT_NEED_MOC = MyQtClass.h
MOC_OBJS = $(HEADERS_THAT_NEED_MOC:%.h=moc_%.cpp.o)
all: HelloWorld-Qt
HelloWorld-Qt: $(OBJS) $(MOC_OBJS)
$(CXX) $^ $(LINK_FLAGS) -o $#
%.cpp.o : %.cpp
$(CXX) $(C_FLAGS) -c $^ -o $#
moc_%.cpp: %.h
$(MOC) -DQT_CORE_LIB $(INCLUDES) $^ -o $#
clean:
rm -f *.cpp.o HelloWorld-Qt moc_*.cpp
I don't think your approach can work, independent of the build tool you use. Keep in mind that moc looks for the Q_OBJECT macro. No such macro can ever be found in MyQtClass.h, because neither moc nor the build tool supporting it will expand the CREATE_QT_CLASS macro, because macro expansion would also expand away Q_OBJECT.
Note that if you add CreateQtClass.h to your qbs file, you will notice that qbs does run moc -- but on the CreateQtClass file. That's the correct behavior, because that's where the Q_OBJECT macro occurs.
I double-checked with qmake and cmake, and they all behave the same way: If you do not list CreateQtClass in the project file, they will not run moc. If you do list it, moc is run on that file.
If you want to keep using your macro, you'll have to make sure to reference Q_OBJECT at the calling site, e.g. as a macro parameter. But even then, I'm not sure moc itself will be fond of that construct.
I created a reproduction sample for this:
#include <iostream>
#include <QtCore/QLoggingCategory>
#include <QtCore/QDebug>
#include <QtCore/QtCore>
using namespace std;
int main () {
int i;
QLoggingCategory::setFilterRules("*.debug=true\n");
QLoggingCategory LogO(NULL);
if (LogO.isDebugEnabled()) {
cout << "QDebug enabled\n";
} else {
cout << "QDebug disabled!\n";
}
cout << "Start!\n";
qDebug() << "qStart!";
cerr << "print to stderr.\n";
qWarning() << "qWarning";
return 0;
}
Build steps:
g++ -c -fPIC -I/usr/include/qt5 main.cpp -o main.o
g++ -fPIC main.o -L /usr/lib64 -lQt5Core -o testapp
When executing the application in an interactive shell, output redirection works as expected:
Setup:
./testapp > out 2> err
Output:
>>cat out:
QDebug enabled
Start!
>>cat err:
qStart!
print to stderr.
qWarning
However, it does not work if the application is executed as a cronjob, the output of qDebug() and qWarning() is missing:
Setup:
* * * * * username /home/username/temp/build/testapp 1> /home/username/temp/log/out 2> /home/username/temp/log/err
Output:
>>cat /home/username/temp/log/out
QDebug enabled
Start!
>>cat home/username/temp/log/err
print to stderr.
Enviroment vars
The output of env in the interative shell is as follows:
LS_COLORS=*long string*
SSH_CONNECTION=*censored*
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
HOSTNAME=*censored*
XDG_SESSION_ID=492
USER=username
SELINUX_ROLE_REQUESTED=
PWD=/home/username/temp/build
HOME=/home/username
SSH_CLIENT=*censored*
SELINUX_LEVEL_REQUESTED=
SSH_TTY=/dev/pts/0
MAIL=/var/spool/mail/username
TERM=xterm
SHELL=/bin/bash
SELINUX_USE_CURRENT_RANGE=
SHLVL=1
LOGNAME=username
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
PATH=/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/username/.local/bin:/home/username/bin
HISTSIZE=1000
LESSOPEN=||/usr/bin/lesspipe.sh %s
_=/usr/bin/env
OLDPWD=/home/username/temp/build/logs
The output of env when called via cronjob is as follows:
LS_COLORS=*long string*
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
HOSTNAME=*censored*
XDG_SESSION_ID=995
USER=username
PWD=/home/username
HOME=/home/username
MAIL=/var/spool/mail/username
TERM=xterm
SHELL=/bin/bash
SHLVL=1
LOGNAME=username
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
PATH=/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/username/.local/bin:/home/username/bin
LESSOPEN=||/usr/bin/lesspipe.sh %s
_=/usr/bin/env
The issue is that qt behaves differently depending if it thinks that it is running in an (interactive?) terminal or not.
Quote:
One pitfall to be aware of: the destination of logging depends on an environment variable. If the variable QT_LOGGING_TO_CONSOLE is set to 1, the message functions will always log to the console. If set to 0, they will not log to the console, and will instead log to syslog, if enabled. When the environment variable is not set, the message functions log to a console if one is present (i.e. if the program is attached to a terminal). Thus, to ensure that the output of our example program goes to syslog, I set the environment variable to 0 within the program.
Therefore, the output of qDebug, QWarning etc. when executed from cron was not output via stderr, but directly handed over to journald.
TL;DR: quickfix: add QT_LOGGING_TO_CONSOLE=1 to /etc/crontab
.
.
PS: note if you need to debug an issue with QDebug:
be aware of this: https://bugzilla.redhat.com/show_bug.cgi?id=1227295
you can add QT_LOGGING_DEBUG=1 as an environment variable to make
qt output changes in logging behavior during execution.
cronjob redirects output and err to email address.
add >> /tmp/myscript.log 2>&1 in your crontab entry.
see this answer
I would like to include the header nmath.h for my C code (within an R package) to find R_FINITE and ML_ERR_return_NAN. I found that one cannot include nmath.h directly. For R_FINITE to be found, I could include R_ext/libextern.h. But I don't know what to include so that ML_ERR_return_NAN is found. Any ideas? I found here that Prof. Brian Ripley referred to Writing R Extensions, but I couldn't find nmath.h being addressed there (where exactly?)
On Debian or Ubuntu:
sudo apt-get install r-mathlib
after which you can build test programs such as this:
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4;
// compile-command: "gcc -s -Wall -O3 \
// -I/usr/share/R/include -o rmath_rnorm \
// rmath_rnorm.c -lRmath -lm" -*-
// Compare to
// $ Rscript -e "RNGkind('Marsaglia'); \
// .Random.seed[2:3] <- c(123L, 456L); rnorm(2)"
// [1] -0.2934974 -0.3343770
#include <stdio.h>
#define MATHLIB_STANDALONE 1
#include <Rmath.h>
int main(void) {
set_seed(123, 456);
printf("rnorm: %f %f\n", rnorm(0.0, 1.0), rnorm(0.0, 1.0));
return 0;
}
Note: The first four lines should be one-line in the file you safe, then M-x compile build the program for your. Ditto for the Rscript invocation: one line.
Edit: Drats. Answered the wrong question :) nmath.h appears to not be exported from src/nmath/nmath.h but this R Mathlibrary is what is exported by R Core for use by others. Where as the nmath.h file has
/* Private header file for use during compilation of Mathlib */
#ifndef MATHLIB_PRIVATE_H
#define MATHLIB_PRIVATE_H
so you are not supposed to rely on it.
I would like to change a program to automatically detect whether a terminal is color-capable or not, so when I run said program from within a non-color capable terminal (say M-x shell in (X)Emacs), color is automatically turned off.
I don't want to hardcode the program to detect TERM={emacs,dumb}.
I am thinking that termcap/terminfo should be able to help with this, but so far I've only managed to cobble together this (n)curses-using snippet of code, which fails badly when it can't find the terminal:
#include <stdlib.h>
#include <curses.h>
int main(void) {
int colors=0;
initscr();
start_color();
colors=has_colors() ? 1 : 0;
endwin();
printf(colors ? "YES\n" : "NO\n");
exit(0);
}
I.e. I get this:
$ gcc -Wall -lncurses -o hep hep.c
$ echo $TERM
xterm
$ ./hep
YES
$ export TERM=dumb
$ ./hep
NO
$ export TERM=emacs
$ ./hep
Error opening terminal: emacs.
$
which is... suboptimal.
A friend pointed me towards tput(1), and I cooked up this solution:
#!/bin/sh
# ack-wrapper - use tput to try and detect whether the terminal is
# color-capable, and call ack-grep accordingly.
OPTION='--nocolor'
COLORS=$(tput colors 2> /dev/null)
if [ $? = 0 ] && [ $COLORS -gt 2 ]; then
OPTION=''
fi
exec ack-grep $OPTION "$#"
which works for me. It would be great if I had a way to integrate it into ack, though.
You almost had it, except that you need to use the lower-level curses function setupterm instead of initscr. setupterm just performs enough initialization to read terminfo data, and if you pass in a pointer to an error result value (the last argument) it will return an error value instead of emitting error messages and exiting (the default behavior for initscr).
#include <stdlib.h>
#include <curses.h>
int main(void) {
char *term = getenv("TERM");
int erret = 0;
if (setupterm(NULL, 1, &erret) == ERR) {
char *errmsg = "unknown error";
switch (erret) {
case 1: errmsg = "terminal is hardcopy, cannot be used for curses applications"; break;
case 0: errmsg = "terminal could not be found, or not enough information for curses applications"; break;
case -1: errmsg = "terminfo entry could not be found"; break;
}
printf("Color support for terminal \"%s\" unknown (error %d: %s).\n", term, erret, errmsg);
exit(1);
}
bool colors = has_colors();
printf("Terminal \"%s\" %s colors.\n", term, colors ? "has" : "does not have");
return 0;
}
Additional information about using setupterm is available in the curs_terminfo(3X) man page (x-man-page://3x/curs_terminfo) and Writing Programs with NCURSES.
Look up the terminfo(5) entry for the terminal type and check the Co (max_colors) entry. That's how many colors the terminal supports.