Bash input/output in C++ - c++

I'm writing program in C++ (for XAMPP communication) and I want to execute command which I have in strings (I know that this is simply system("command")) but I want to get the output from bash to C++ to string. I've founded several threads about this, but no which solved Bash -> C++.

You can call the FILE *popen(const char *command, const char *mode) function. Then, you can read the file it returns to get the output of your call.
It's like using a pipe to redirect the output of the command you used to a file in the hard drive and then read the file, but you don't get to create a file in the hard drive.
The documentation of the popen() is here.

You need to call the popen function, and read the output from the FILE it returns.

You can try Standard Output Redirection to redirect the standard output to a file stream
and then use it to read to a string.
Dup()

Related

Check/list all bash commands in C++?

Basically, is there a simple way to get a list of all bash commands in the PATH environment variable in C++? My current solution is to run a command beforehand that lists all the commands into a .txt, which is then read into the C++ program. I want to be able to cut out this step, if possible.
ls ${PATH//:/ } > commands.txt
If you do NOT need to use stdin in your C++ program
This is the easy solution. Just pipe the output of the ls command to your C++ program. Then, in your C++ program, read the contents of the file from stdin like you would read from a normal file. Literally use stdin wherever you need to provide a file descriptor. So, your command would look something like
ls ${PATH//:/ } | ./a.out
The | denotes a pipe in bash. It takes stdout from the first program (here ls) and redirects it to stdin of the second program (here your C++ program).
If you do need to use stdin in your C++ program
This is going to be tricky. You essentially need to make your C++ program do everything itself. The first way to this that comes to mind is
Read $PATH using getenv().
Parse $PATH by replacing all occurrences of : with (a blank space). This is easy enough to do in a loop, but you could also use std::replace.
Now that you have the directory paths from $PATH, you simply need the contents of each directory. This post will help you get the contents of a directory.
UPDATE: Another Approach
I've thought of another way to approach your problem that allows you to use IO redirection (ie. use the pipe), and also use stdin at the same time. The problem is that it is probably not portable.
The basic idea is that you read the output of ls from stdin (using the pipe operator in bash). Next, you essentially reset stdin using freopen. Something along the lines of
#include <stdio.h>
int main(void)
{
char buf[BUFSIZ];
puts("Reading from stdin...");
while(fgets(buf, sizeof(buf), stdin))
fputs(buf, stdout);
freopen("/dev/tty", "rw", stdin);
puts("Reading from stdin again...");
while(fgets(buf, sizeof(buf), stdin))
fputs(buf, stdout);
return 0;
}
The above code is from here. It reads stdin, resets stdin, and reads from stdin again. I would suggest not using this approach for anything important, or for something that needs to work on several platforms. While it is more convenient since it allows you to use IO redirection while retaining the ability to use stdin, it is not portable.

Will File I/O In Current Working Directory Ever Fail?

On my home Linux laptop, I like to write wrapper programs and GUI helpers for things I use frequently. However, I don't like Bash scripting very much, so I do a lot of stuff in C++. However, a lot of times, this requires me to use the system() function from the cstdlib.
This system() command is awesome, but I wanted a way to call system() and receive the stdout/stderror. The system() command only returns the return code from the command. So, in a Bash script, one can do:
myVar=$(ls -a | grep 'search string')
echo $myVar
and myVar will output whatever the stdout was for the command. So I began writing a wrapper class that will add a pipe-to-file to the end of the command, open the file, read all of the piped stdout, and return it as either one long string or as a vector of strings. The intricacies of the class are not really relevant here (I don't think anyway), but the above example would be done like this:
SystemCommand systemCommand;
systemCommand.setCommand("ls -a | grep \'search string\' ");
systemCommand.execute();
std::cout << systemCommand.outputAsString() << std::endl;
Behind the scenes, when systemCommand.execute() is called, the class ensures that the command will properly pipe all stdout/stderr to a randomly generated filename, in the current working directory. So for example, the above command would end up being
"ls -a | grep 'search string' >> 1452-24566.txt 2>&1".
The class then goes attempts to open and read from that file, using ifstream:
std::ifstream readFromFile;
readFromFile.open(_outputFilename);
if (readFromFile.is_open()) {
//Read all contents of file into class member vector
...
readFromFile.close();
//Remove temporary file
...
} else {
//Handle read failure
}
So here is my main question will std::ifstream ever fail to open a recently created file in the current working directory? If so, what would be a way to make it more robust (specifically on Linux)?
A side/secondary question: Is there a very simplified way to achieve what I'm trying to achieve without using file pipes? Perhaps some stuff available in unistd.h? Thanks for your time.
So here is my main question will std::ifstream ever fail to open a recently created file in the current working directory?
Yes.
Mount a USB thumb drive (or some other removable media)
cd to the mount
Execute your program. While it's executing, remove the drive.
Watch the IO error happen.
There's a ton of other reasons too. Filesystem corruption, hitting the file descriptor limit, etc.
If so, what would be a way to make it more robust (specifically on Linux)?
Make temporary files in /tmp, whose entire purpose is for temporary files. Or don't create a file at all, and use pipes for communication instead (Like what popen does, like harmic suggested). Even so, there are no guarantees; try to gracefully handle errors.

Write to a file steam without a file existing on the hard drive in C

Is this possible in the C language? Or even C++? I prefer to know for C.
For example, say I had a function that reads a text file and does something with it. If the user did not specify an input text file and I wanted to use that function for stdin; Is it possible to write stdin to a file stream as if it were coming from a file read so it can be used in the same method that normally just takes input files?
A way around this of course is that I could take stdin, write it to a temp file, then pass the temp file to the function that normally would take an input file. I've searched online and asked tutors at university but am not getting any solutions. Has anyone ever accomplished this?
If your function has a prototype say
void add(FILE *fp,<rest of the argument>)
{
}
The you can directly pass
add(stdin,<rest of the arguments>);
Because stdin is of type FILE *
FILE *stdin;
No need to read from stdin and store it in some file and and later send that file pointer to your API.
STDIN is open for you automatically, so just read from STDIN. There are several ways of doing it, but basically STDIN is file descriptor 0.
int filedes = 0;
if(/* argv[1] is a file name */)
filedes = open(argv[1], flags);
read(filedes, bufr, size);

How to read the disk usage (du) in a C variable

I would like to do the following in a "c" program.
I need to get the disk usage of the following directory and should be able to read it in a variable.
du -sb /home/mann | awk '{print$1}'
I would like to do the above in C program and copy the output in a variable. I need to do this for this directory alone not for the "/" or "/home".
Pipe the output of your command to a file on the disk. Run your command using system
Read the file using standard C functions
Update your variable
Another option is to use popen/pclose to launch your command. This will return a file descriptor from which you can read.
Yet another option is to hunt your system for any library function that provides the information you desire

launch app, capture stdout and stderr in c++

How do I launch an app and capture the output via stdout and maybe stderr?
I am writing an automated build system and I need to capture the output to analyze. I'd like to update the svn repo and grab the revision number so I can move the files in autobuild/revNumber/ if successful. I also would like to build using make and upload the compile text to my server for everyone to see the warnings and errors on a failed build.
I can't find the system() function, but I found the CreateProcess() function on MSDN. I am able to launch what I need but I have no idea how to capture the stderr and stdout. I notice the process launches separately unless I set a breakpoint and keep my app exiting which it then will keep all the text in my app console window. I would also want to wait until all processes are finished and then scan the data it produced to do any additional operations I need. How do I do any of this?
In real shells (meaning, not sea shells - I mean, not in C Shell or its derivatives), then:
program arg1 arg2 >/tmp/log.file 2>&1
This runs program with the given arguments, and redirects the stdout to /tmp/log.file; the notation (hieroglyph) '2>&1' at the end sends stderr (file descriptor 2) to the same place that stdout (file descriptor 1) is going. Note that the sequence of operations is important; if you reverse them, then standard error will go to where standard output was going, and then standard output (but not standard error) will be redirected to the file.
The choice of file name shown is abysmal for numerous reasons - you should allow the user to choose the directory, and probably should include the process ID or time stamp in the file name.
LOG=${TMPDIR:-/tmp}/log.$$.$(date +%Y%m%d-%H%M%S)
program arg1 arg2 >$LOG 2>&1
In C++, you can use the system() function (inherited from C) to run processes. If you need to know the file name in the C++ program (plausible), then generate the name in the program (strftime() is your friend) and create the command string with that file name.
(Strictly, you also need getenv() to get $TMPDIR, and the POSIX function getpid() to get the process ID, and then you can simulate the two-line shell script (though the PID used would be of the C++ program, not the launched shell).
You could instead use the POSIX popen() function; you'd have to include the '2>&1' notation in the command string that you create to send the standard error of the command to the same place as standard output goes, but you would not need a temporary file:
FILE *pp = popen("program arg1 arg2 2>&1", "r");
You can then read off the file stream. I'm not sure whether there's a clean way to map a C file stream into a C++ istream; there probably is.
You need to fill up the STARTUP_INFO structure, which has hStdInput, hStdOutput and hStdError. Remember to inherit handles when you CreateProcess.
/* Assume you open a file handle or pipe called myoutput */
STARTUP_INFO si_startinfo;
ZeroMemory(&si_startinfo, sizeof(STARTUP_INFO));
si_startinfo.cb = sizeof(STARTUP_INFO);
si_startinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si_startinfo.hStdOutput = myoutput;
si_startinfo.hStdError = myoutput;
si_startifno.dwFlags != STARTF_USEHANDLES;
PROCESS_INFORMATION pi_procinfo;
ZeroMemory(&pi_procinfo, sizeof(PROCESS_INFORMATION);
CreateProcess(NULL, cmdline, NULL, NULL, true, 0, NULL, pathname, &si_startinfo, &pi_procinfo);
I have not shown the error handling aspects, which you will need to do. The 5th argument is set to true to inherit the handles. Others have explained how to create pipes so I won't repeat it here.
Microsoft's CRTs and the MSDN library do include the system function and the _popen function.