I am executing a system() function which returns me a file name. Now I dont want to display the output on the screen(ie the filename) or pipe to a newfile. I just want to store it in a variable. is that possible? if so, how?
thanks
A single filename? Yes. That is certainly possible, but not using system().
Use popen(). This is available in c and c++, you've tagged your question with both but are probably going to code in one or the other.
Here's an example in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fpipe;
char *command = "ls";
char c = 0;
if (0 == (fpipe = (FILE*)popen(command, "r")))
{
perror("popen() failed.");
exit(EXIT_FAILURE);
}
while (fread(&c, sizeof c, 1, fpipe))
{
printf("%c", c);
}
pclose(fpipe);
return EXIT_SUCCESS;
}
Well,There is one more easy way by which you can store command output in a file which is called redirection method. I think redirection is quite easy and It will be useful in your case.
so For Example this is my code in c++
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
int main(){
system("ls -l >> a.text");
return 0;
}
Here redirection sign easily redirect all output of that command into a.text file.
You can use popen(3) and read from that file.
FILE *popen(const char *command, const char *type);
So basically you run your command and then read from the FILE returned. popen(3) works just like system (invokes the shell) so you should be able to run anything with it.
Here is my C++ implementation, which redirects system() stdout to a logging system. It uses GNU libc's getline(). It will throw an exception if it can't run the command, but will not throw if the command runs with non-zero status.
void infoLogger(const std::string& line); // DIY logger.
int LoggedSystem(const string& prefix, const string& cmd)
{
infoLogger(cmd);
FILE* fpipe = popen(cmd.c_str(), "r");
if (fpipe == NULL)
throw std::runtime_error(string("Can't run ") + cmd);
char* lineptr;
size_t n;
ssize_t s;
do {
lineptr = NULL;
s = getline(&lineptr, &n, fpipe);
if (s > 0 && lineptr != NULL) {
if (lineptr[s - 1] == '\n')
lineptr[--s ] = 0;
if (lineptr[s - 1] == '\r')
lineptr[--s ] = 0;
infoLogger(prefix + lineptr);
}
if (lineptr != NULL)
free(lineptr);
} while (s > 0);
int status = pclose(fpipe);
infoLogger(String::Format("Status:%d", status));
return status;
}
Related
Is there any way to store output of system command into char array, since system command is returning only int.
There's no way to retrieve the output of system(3). Well, you could redirect the output of whatever command is executed to a file and then open and read that file, but a more sane approach is to use popen(3).
popen(3) replaces system(3) and it allows you to read the output of a command (or, depending on the flags you pass it, you can write to the input of a command).
Here's an example that executes ls(1) and prints the result:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *ls_cmd = popen("ls -l", "r");
if (ls_cmd == NULL) {
fprintf(stderr, "popen(3) error");
exit(EXIT_FAILURE);
}
static char buff[1024];
size_t n;
while ((n = fread(buff, 1, sizeof(buff)-1, ls_cmd)) > 0) {
buff[n] = '\0';
printf("%s", buff);
}
if (pclose(ls_cmd) < 0)
perror("pclose(3) error");
return 0;
}
Is there any way to store output of system command into char array, since system command is returning only int.
There's no way to retrieve the output of system(3). Well, you could redirect the output of whatever command is executed to a file and then open and read that file, but a more sane approach is to use popen(3).
popen(3) replaces system(3) and it allows you to read the output of a command (or, depending on the flags you pass it, you can write to the input of a command).
Here's an example that executes ls(1) and prints the result:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *ls_cmd = popen("ls -l", "r");
if (ls_cmd == NULL) {
fprintf(stderr, "popen(3) error");
exit(EXIT_FAILURE);
}
static char buff[1024];
size_t n;
while ((n = fread(buff, 1, sizeof(buff)-1, ls_cmd)) > 0) {
buff[n] = '\0';
printf("%s", buff);
}
if (pclose(ls_cmd) < 0)
perror("pclose(3) error");
return 0;
}
Can someone tell me what am i doing wrong here i am getting an error saying getline() not declared in this scope.........any help would be appreciated.
no matching function for call to getline(char**, size_t*, FILE*&)
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
char *s;
int main(int argc, char *argv[])
{
FILE* fd = fopen("input.txt", "r");
if(fd == NULL)
{
fputs("Unable to open input.txt\n", stderr);
exit(EXIT_FAILURE);
}
size_t length = 0;
ssize_t read;
const char* backup;
while ((read = getline(&s, &length, fd) ) > 0)
{
backup = s;
if (A() && *s == '\n')
{
printf("%sis in the language\n", backup);
}
else
{
fprintf(stderr, "%sis not in the language\n", backup);
}
}
fclose(fd);
return 0;
}
You'll need to use C++ style code in order to use getline in a cross platform way.
#include <fstream>
#include <string>
using namespace std;
std::string s;
bool A() { return true; }
int main(int argc, char *argv[])
{
ifstream myfile("input.txt");
if(!myfile.is_open())
{
fprintf(stderr, "Unable to open input.txt\n");
return 1;
}
size_t length = 0;
size_t read;
std::string backup;
while (getline(myfile, s))
{
backup = s;
if (A() && s == "\n")
{
printf("%s is in the language\n", backup.c_str());
}
else
{
fprintf(stderr, "%s is not in the language\n", backup.c_str());
}
}
return 0;
}
What are you trying to do with getline(&s, &length, fd)? Are you trying to use the C getline?
Assuming you have opened the file correctly, in c++ your getline should look something like this: getline(inputStream, variableToReadInto, optionalDelimiter).
You didn't include <stdio.h> but you did include <fstream>. Maybe use ifstream fd("input.txt");
What's A()
If you ARE trying to use the C getline, the using namespace std may be interfering
Why are you using printf and fprintf and not cout << xxxxxx and fd << xxxxxx
You seem to be a bit confused with various getline function signatures.
The standard C++ std::getline signature is
template< class CharT, class Traits, class Allocator >
std::basic_istream<CharT,Traits>& getline( std::basic_istream<CharT,Traits>& input,
std::basic_string<CharT,Traits,Allocator>& str,
CharT delim );
It takes an input stream object, a string and a character delimiter (there's an overload without the delimiter too).
The posix getline signature is
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
with the delimiter optional again.
now in your code your passing arguments as if calling the posix version without delimiter. If you want to use the standard one you'll have to change the arguments (i.e. istream object instead of FILE*). I don't know if the posix one is even available for you, since posix is different from any C++ standard.
Note that the fputs, FILE*, fprintf are C filehandling functions, not the C++ ones.
I'm calling a LINUX command from within a C++ programme which creates the following output. I need to copy the first column of the output to a C++ variable (say a long int). How can I do it?? If that is not possible how can I copy this result into a .txt file with which I can work with?
Edit
0 +0
2361294848 +2361294848
2411626496 +50331648
2545844224 +134217728
2713616384 +167772160
I have this stored as a file, file.txt and I'm using the following code to
extract the left column with out the 0 to store it at integers
string stringy="";
int can_can=0;
for(i=begin;i<length;i++)
{
if (buffer[i]==' ' && can_can ==1) //**buffer** is the whole text file read in char*
{
num=atoi(stringy.c_str());
array[univ]=num; // This where I store the values.
univ+=1;
can_can=1;
}
else if (buffer[i]==' ' && can_can ==0)
{
stringy="";
}
else if (buffer[i]=='+')
{can_can=0;}
else{stringy.append(buffer[i]);}
}
I'm getting a segmentation error for this. What can be done ?
Thanks in advance.
Just create a simple streambuf wrapper around popen()
#include <iostream>
#include <stdio.h>
struct SimpleBuffer: public std::streambuf
{
typedef std::streambuf::traits_type traits;
typedef traits::int_type int_type;
SimpleBuffer(std::string const& command)
: stream(popen(command.c_str(), "r"))
{
this->setg(&c[0], &c[0], &c[0]);
this->setp(0, 0);
}
~SimpleBuffer()
{
if (stream != NULL)
{
fclose(stream);
}
}
virtual int_type underflow()
{
std::size_t size = fread(c, 1, 100, stream);
this->setg(&c[0], &c[0], &c[size]);
return size == 0 ? EOF : *c;
}
private:
FILE* stream;
char c[100];
};
Usage:
int main()
{
SimpleBuffer buffer("echo 55 hi there Loki");
std::istream command(&buffer);
int value;
command >> value;
std::string line;
std::getline(command, line);
std::cout << "Got int(" << value << ") String (" << line << ")\n";
}
Result:
> ./a.out
Got int(55) String ( hi there Loki)
It is popen you're probably looking for. Try
man popen
.
Or see this little example:
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
FILE *in;
char buff[512];
if(!(in = popen("my_script_from_command_line", "r"))){
return 1;
}
while(fgets(buff, sizeof(buff), in)!=NULL){
cout << buff; // here you have each line
// of the output of your script in buff
}
pclose(in);
return 0;
}
Unfortunately, it’s not easy since the platform API is written for C. The following is a simple working example:
#include <cstdio>
#include <iostream>
int main() {
char const* command = "ls -l";
FILE* fpipe = popen(command, "r");
if (not fpipe) {
std::cerr << "Unable to execute commmand\n";
return EXIT_FAILURE;
}
char buffer[256];
while (std::fgets(buffer, sizeof buffer, fpipe)) {
std::cout << buffer;
}
pclose(fpipe);
}
However, I’d suggest wrapping the FILE* handle in a RAII class to take care of resource management.
You probably want to use popen to execute the command. This will give you a FILE * that you can read its output from. From there, you can parse out the first number with (for example) something like:
fscanf(inpipe, "%d %*d", &first_num);
which, just like when reading from a file, you'll normally repeat until you receive an end of file indication, such as:
long total = 0;
while (1 == fscanf(inpipe, "%l %*d", &first_num))
total = first_num;
printf("%l\n", total);
I'm writing a simple program to browse the local network and pass on filenames to mplayer using "system". However, sometimes filenames contain spaces or quotes.
Obviously I could write my own function to escape those, but I'm not sure exactly what characters do or do not need escaping.
Is there a function available in the CRT or somewhere in the linux headers to safely escape a string to pass to the command line ?
Other answers include this fork and exec solution, but I claim that this is the only right way to do it.
Escaping shell arguments is prone to bugs and a waste of time, just as trying to escape SQL parameters is a silly idea when safer and more efficient parameter binding APIs exist.
Here is a sample function:
void play(const char *path)
{
/* Fork, then exec */
pid = fork();
if( pid < 0 ) {
/* This is an error! */
return;
}
if( pid == 0 ) {
/* This is the child */
freopen( "/dev/null", "r", stdin );
freopen( "/dev/null", "w", stdout );
freopen( "/dev/null", "w", stderr );
execlp( "mplayer", "mplayer", path, (char *)0 );
/* This is also an error! */
return;
}
}
There isn't a single solution that works everywhere because different shells have different ideas of what special characters are and how they are interpreted. For bash, you could probably get away with surrounding the entire filename in single quotes after replacing every single quote in the file name with '"'"' (the first single quote stops the sequence, the "'" appends the literal single quote to the string, the final single quote starts the quoted sequence again). A better solution would be to find a way to call the program without using system, such as by using fork with one of the exec functions so there is no shell interpolation.
While i don't know a function that does this, you can surround each of your arguments with '...', and replace any ' in the original argument by '"'"' . like
system("mplayer 'foo'\"'\"' bar'"); will give a single argument to mplayer which is foo'bar and which is allowed to contain strange things like " or \n . Note the escaping before " above (\") is only to make it valid C++.
You should consider using a function that accepts the arguments each separate, thus avoiding such issues. Wikipedia has a good article on this about the famous fork-and-exec pattern. http://en.wikipedia.org/wiki/Fork-exec
And now here is a complete solution to the shell escape problem. Although this
doesn't answer the exact question of escaping a string for shell. It solves the problem of passing arguments to program. This solution is a POSIX portable way to execute commands with arguments properly passed into the command without worrying about needing to escape them.
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <sys/stat.h>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
std::vector<std::string> split(std::string delimiter, std::string str){
std::size_t nextPos = 0;
std::size_t delimiterSize = delimiter.size();
std::vector<std::string> list;
while(true){
std::size_t pos = str.find(delimiter, nextPos);
std::string subStr;
if(pos == std::string::npos){
list.push_back(str.substr(nextPos));
break;
}
subStr = str.substr(nextPos, pos - nextPos);
list.push_back(subStr);
nextPos = pos + delimiterSize;
}
return list;
}
bool isFileExecutable(const std::string &file)
{
struct stat st;
if (stat(file.c_str(), &st) < 0)
return false;
if ((st.st_mode & S_IEXEC) != 0)
return true;
return false;
}
std::string ensureEndsWithSlash(std::string path){
if(path[path.length()-1] != '/'){
path += "/";
}
return path;
}
std::string findProgram(std::string name){
// check if it's relative
if(name.size() > 2){
if(name[0] == '.' && name[1] == '/'){
if(isFileExecutable(name)){
return name;
}
return std::string();
}
}
std::vector<std::string> pathEnv = split(":", getenv("PATH"));
for(std::string path : pathEnv){
path = ensureEndsWithSlash(path);
path += name;
if(isFileExecutable(path)){
return path;
}
}
return std::string();
}
// terminal condition
void toVector(std::vector<std::string> &vector, const std::string &str){
vector.push_back(str);
}
template<typename ...Args>
void toVector(std::vector<std::string> &vector, const std::string &str, Args ...args){
vector.push_back(str);
toVector(vector, args...);
}
int waitForProcess(pid_t processId){
if(processId == 0){
return 0;
}
int status = 0;
int exitCode = -1;
while(waitpid(processId, &status, 0) != processId){
// wait for it
}
if (WIFEXITED(status)) {
exitCode = WEXITSTATUS(status);
}
return exitCode;
}
/**
Runs the process and returns the exit code.
You should change it so you can detect process failure
vs this function actually failing as a process can return -1 too
#return -1 on failure, or exit code of process.
*/
template<typename ...Args>
int mySystem(Args ...args){
std::vector<std::string> command;
toVector(command, args...);
command[0] = findProgram(command[0]);
if(command[0].empty()){
// handle this case by returning error or something
// maybe std::abort() with error message
return -1;
}
pid_t pid = fork();
if(pid) {
// parent wait for child
return waitForProcess(pid);
}
// we are child make a C friendly array
// this process will be replaced so we don't care about memory
// leaks at this point.
std::vector<char*> c_command;
for(int i = 0; i < command.size(); ++i){
c_command.push_back(strdup(command[i].c_str()));
}
// null terminate the sequence
c_command.push_back(nullptr);
execvp(c_command[0], &c_command[0]);
// just incase
std::abort();
return 0;
}
int main(int argc, char**argv){
// example usage
mySystem("echo", "hello", "world");
}