How to read a file into a C program on Linux? [closed] - c

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
What is the difference between running an already compiled C program with a.out file_name_here and a.out < file_name_here?
I remember something about Linux pipelines, but I cannot remember how to make the a.out file accept a file using the < symbol.
Basically what I am asking is this: how does the C code look for a C program that:
file_name_here is a text file with "hello world" as content
terminal gets "a.out < file_name_here" in command line
terminal shows output: "hello world"

a.out file_name_here passes "file_name_here" as an argument.
a.out < file_name_here is processed by the shell and presents the contents of "file_name_here" to the program on its "stdin".

Note that when you type a.out < filename, the shell handles the I/O redirection. The program is run with its standard input coming from the named file instead of from the terminal. When you type a.out filename, the program must deal with opening the file, reading it (and preferably closing it too). Neither of these examples uses a pipe. You could write cat file1 file2 file3 | a.out which would use a pipe and supply the contents of the three files as the standard input to the program.
Many programs on Unix systems are filters. If they are given file names to process, those are read. If they are given no file names, then they read standard input instead. An example of such a program is grep; other examples include cat and sort.
The general solution, in outline, is:
extern void process_file(FILE *fp); // Where the real work is done
int main(int argc, char **argv)
{
int rc = EXIT_SUCCESS;
if (argc == 1)
process_file(stdin);
else
{
for (int i = 1; i < argc; i++)
{
FILE *fp = fopen(argv[i], "r");
if (fp == 0)
{
fprintf(stderr, "%s: failed to open file %s for reading\n",
argv[0], argv[i]);
rc = EXIT_FAILURE;
}
else
{
process_file(fp);
fclose(fp);
}
}
}
return rc;
}
This will process any command line arguments as files to be read, resorting to reading standard input if no files are specified on the command line. There are legions of extra tweaks you can make to this outline. You can easily add option processing with getopt() (or getopt_long() if you're using GNU), and you can treat a file name of - as standard input if you wish. You can exit on failure to open a file if you think that's appropriate (sometimes it is; sometimes it isn't — grep doesn't, for example). You can pass the file name to the process_file() function. You can have the process_file() function report success failure, and track whether everything worked, exiting with zero only if all the operations were successful.

Just realized the problem I had. The < symbol means that the shell replaces normal user input in C with the content of the file, so all the normal calls such as fgets and sscanf work on it.

Related

C Program - How to get the output of a shell command and compare it with a variable? [duplicate]

I've got a utility that outputs a list of files required by a game. How can I run that utility within a C program and grab its output so I can act on it within the same program?
UPDATE: Good call on the lack of information. The utility spits out a series of strings, and this is supposed to be portable across Mac/Windows/Linux. Please note, I'm looking for a programmatic way to execute the utility and retain its output (which goes to stdout).
As others have pointed out, popen() is the most standard way. And since no answer provided an example using this method, here it goes:
#include <stdio.h>
#define BUFSIZE 128
int parse_output(void) {
char *cmd = "ls -l";
char buf[BUFSIZE];
FILE *fp;
if ((fp = popen(cmd, "r")) == NULL) {
printf("Error opening pipe!\n");
return -1;
}
while (fgets(buf, BUFSIZE, fp) != NULL) {
// Do whatever you want here...
printf("OUTPUT: %s", buf);
}
if (pclose(fp)) {
printf("Command not found or exited with error status\n");
return -1;
}
return 0;
}
Sample output:
OUTPUT: total 16
OUTPUT: -rwxr-xr-x 1 14077 14077 8832 Oct 19 04:32 a.out
OUTPUT: -rw-r--r-- 1 14077 14077 1549 Oct 19 04:32 main.c
For simple problems in Unix-ish environments try popen().
From the man page:
The popen() function opens a process by creating a pipe, forking and invoking the shell.
If you use the read mode this is exactly what you asked for. I don't know if it is implemented in Windows.
For more complicated problems you want to look up inter-process communication.
popen is supported on Windows, see here:
http://msdn.microsoft.com/en-us/library/96ayss4b.aspx
If you want it to be cross-platform, popen is the way to go.
Well, assuming you're on a command line in a windows environment, you can use pipes or command line redirects. For instance,
commandThatOutputs.exe > someFileToStoreResults.txt
or
commandThatOutputs.exe | yourProgramToProcessInput.exe
Within your program, you could use the C standard input functions to read the other programs output (scanf, etc.): http://irc.essex.ac.uk/www.iota-six.co.uk/c/c1_standard_input_and_output.asp . You could also use the file example and use fscanf. This should also work in Unix/Linux.
This is a very generic question, you may want to include more details, like what type of output it is (just text, or a binary file?) and how you want to process it.
Edit: Hooray clarification!
Redirecting STDOUT looks to be troublesome, I've had to do it in .NET, and it gave me all sorts of headaches. It looks like the proper C way is to spawn a child process, get a file pointer, and all of a sudden my head hurts.
So heres a hack that uses temporary files. It's simple, but it should work. This will work well if speed isn't an issue (hitting the disk is slow), or if it's throw-away. If you're building an enterprise program, looking into the STDOUT redirection is probably best, using what other people recommended.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
FILE * fptr; // file holder
char c; // char buffer
system("dir >> temp.txt"); // call dir and put it's contents in a temp using redirects.
fptr = fopen("temp.txt", "r"); // open said file for reading.
// oh, and check for fptr being NULL.
while(1){
c = fgetc(fptr);
if(c!= EOF)
printf("%c", c); // do what you need to.
else
break; // exit when you hit the end of the file.
}
fclose(fptr); // don't call this is fptr is NULL.
remove("temp.txt"); // clean up
getchar(); // stop so I can see if it worked.
}
Make sure to check your file permissions: right now this will simply throw the file in the same directory as an exe. You might want to look into using /tmp in nix, or C:\Users\username\Local Settings\Temp in Vista, or C:\Documents and Settings\username\Local Settings\Temp in 2K/XP. I think the /tmp will work in OSX, but I've never used one.
In Linux and OS X, popen() really is your best bet, as dmckee pointed out, since both OSs support that call. In Windows, this should help: http://msdn.microsoft.com/en-us/library/ms682499.aspx
MSDN documentation says
If used in a Windows program, the _popen function returns an invalid file pointer that causes the program to stop responding indefinitely. _popen works properly in a console application. To create a Windows application that redirects input and output, see Creating a Child Process with Redirected Input and Output in the Windows SDK.
You can use system() as in:
system("ls song > song.txt");
where ls is the command name for listing the contents of the folder song and song is a folder in the current directory. Resulting file song.txt will be created in the current directory.
//execute external process and read exactly binary or text output
//can read image from Zip file for example
string run(const char* cmd){
FILE* pipe = popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[262144];
string data;
string result;
int dist=0;
int size;
//TIME_START
while(!feof(pipe)) {
size=(int)fread(buffer,1,262144, pipe); //cout<<buffer<<" size="<<size<<endl;
data.resize(data.size()+size);
memcpy(&data[dist],buffer,size);
dist+=size;
}
//TIME_PRINT_
pclose(pipe);
return data;
}

Change specific word in file using C unix command or C [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a file that contains:
<Ip_Adress> <User_Id> <User_Name>
When a user wants to change his name he specifics a new one. That new name should replace the in the File. I can do it in two ways: by using C code or with a unix command. I don't have any idea about how to do it using unix but I will prefer that solution. I have tried do it by using C but I get a Segmentation error. I will paste the code. (In the function references the ip address of the user that will change his name)
void change_name(char* ip,char* new_name){
FILE *f1,*f2;
//Attending to one answer I have changed the var to array but the error persists
char buffer[30],ip_address[30],user_id[30],user_name[30];
f1 = fopen ( "data.txt", "r" );
f2 = fopen ( "temporal.txt", "w");
if (f1==NULL){
perror ("Error opening the file data.txt");
fclose(f1);
}
if (f2==NULL){
perror ("Error opening the file temporal.txt");
fclose(f2);
}
while (feof(f1)==0)
{
fscanf(f1,"%s %s %s",ip_address,user_id,user_name);
if(strcmp(ip,ip_address)==0){
fprintf(f2,"%s %s %s\n",ip_address,user_id,new_name);
}else{
fprintf(f2,"%s %s %s\n",ip_address,user_id,user_name);
}
}
fclose (f1);
fclose (f2);
remove(f1);
rename("temporar.txt","data.txt");
}
An example of data.txt would be:
100.100.1.31 af9a67fa8 Guest
200.200.1.31 a43fji462 Guest
so the problem would be change the specific Guest that matchs with the specific ip given
Example: User with 100.100.1.31 ip address wants to change his name to Superman so the data.txt file will resoult:
100.100.1.31 af9a67fa8 Superman
200.200.1.31 a43fji462 Guest
That command would work
sed -i 's/\(100.100.1.31 .\{9\} \)Guest/\1Superman/g' data.txt
The problem now is to pass it to C with execlp or another command like that.
Your segmentation fault comes from your char * that you use in fscanf.
If you malloc them (or declare them as arrays), it would work.
But, I think that the best way to do it is by using sed. Please, refer to other answers for commands that works
EDIT: You could use asprintf() to simply format your sed regex, and use system() or any derivate you want to call it (system() is the better, it allow you to exec shell commands without forking first).
As I told you in response to your comment, your code doesn't segfaults for me. You could just set ip_address to 16 (255.255.255.255 = 16 char) and user_id to 9, for a better memory usage.
EDIT2:
Here is your code that I modified to make it work. I added comments to let you know what and why I did it.
#include <stdlib.h>
#include <stdio.h>
void change_name(char* ip,char* new_name){
FILE *f1,*f2;
//Attending to one answer I have changed the var to array but the error persists
char ip_address[16],user_id[9],user_name[30]; //Better memory managment
f1 = fopen ( "data.txt", "r" );
if (f1==NULL){
perror ("Error opening data.txt file");
exit(EXIT_FAILURE); //If you can't open first file, exit. File isn't openned, so don't close it.
}
f2 = fopen ( "temporal.txt", "w");
if (f2==NULL){
perror ("Error opening temporal.txt file");
fclose(f1); //Close first file, because you openned it
exit(EXIT_FAILURE); //Then exit
}
while (fscanf(f1,"%s %s %s",ip_address,user_id,user_name)==3) //fscanf returns the number of args read. If not 3, there is a problem.
{ // Directly verify of fscanf avoids the last line double read problem
if(strcmp(ip,ip_address)==0){
fprintf(f2,"%s %s %s\n",ip_address,user_id,new_name);
}else{
fprintf(f2,"%s %s %s\n",ip_address,user_id,user_name);
}
}
remove((const char *)f1);
rename("temporal.txt","data.txt");
fclose(f1); //Close your files at end, so you will avoid problems when manipulating them
fclose(f2);
}
int main() // Simple test main
{
change_name("100.100.1.31", "Superman");
return (0);
}
Unix commandline, using SED:
sed -i 's/\(100.100.1.31 .\{9\} \)Guest/\1Superman/g' data.txt
That is a regular expression that specifies the IP Address any 9 characters for the UserID, and the Username.
Let's break down that expression:
s/ - Substitute Text
\( - Begin capturing the following text into Param #1
100.100.1.31 - The IP Address you want to match
.\{9\} - Any character (9 times) for the UserID
\) - End the capture to Param #1
Guest - Username you want to match
/ - End the "Search" part, Begin the "Replace" part
\1 - Put Param #1 (IP Address + UserID) here
Superman - Put the new username here
/g - Do this Search-Replace *Globally*
It gets replaced by the same IP Address and 9 characters, but with the username Superman instead of Guest.

how to write the console output to a file in c [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
hi i have the following code
int main()
{
system("netsh interface ip show addresses");
}
and the output in the console to be written to a text file or else to a variable. pleaase help me out with this. THANKS in ADVANCE
if you use Linux, try this:
system("netsh interface ip show addresses > /path/to/file 2>&1 ");
void do_popen()
FILE *pf;
char command[200];
// Execute a process listing
sprintf(command, "netsh interface ip show addresses");
// Setup our pipe for reading and execute our command.
if(!(pf= popen(command, "r"))){
exit(EXIT_FAILURE);
}
if (pclose(pf) != 0)
fprintf(stderr," Error: Failed to close command stream \n");
return;
}
Here we are using popen which internally creates a process and run the command given to it. It returns an I/O stream from where the data can be fetched later. read and write system calls are being used while reading from the given command buffer or writing into the file back
To make it more generic, you can pass the command in the function parameter and return the data stored into the file in a dynamic array.
Although it is done nicely using popen but it creates a separate process where it run these commands as sh commands,and then put it in the file and before returning the file pointer, it closes all the process.
I would rather implement my own child process using fork() and then use exec and implement my own SIGCHILD handler to remove it from zombie and keep on processing other work in parallel instead of blocking the process
Hope the below code will help to solve your issue. Look at the man pages for the details of popen and pclose APIs.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *in;
char buff[512];
if(!(in = popen("netsh interface ip show addresses", "r"))){
return -1;
}
while(fgets(buff, sizeof(buff), in)!=NULL){
printf("%s", buff);
}
pclose(in);
return 0;
}

capture the "stdin redirected file location string" in c [duplicate]

This question already has answers here:
In C how do I print filename of file that is redirected as input in shell
(9 answers)
Closed 7 years ago.
I am not still sure about the wording in the question, anyway --
I have an executable that takes some values as command line argument and also takes a file from stdin like this:
user#pc:~$./executable 0.12345 0.12345 < some/directory/somefile.txt
now is there any way I can grab the file location some/directory/somefile.txt inside the code ?
what I can do is to modify the code to take the file location as another command line argument, but in that case I need to change a lot of things.
So, it would be better if I could do something like this --
int main(int argc, char **argv)
{
char cmd_prompt[80];
char file_location[80];
grab_command_prompt(cmd_prompt);
split_and_grab_last_token(cmd_prompt, file_location);
/* this line below should print: "some/directory/somefile.txt" */
printf("%s\n", file_location);
}
is it possible ?
No. The shell interprets your commandline and, seeing a < opens the file for reading, does a fork(2) and in the child process, replaces stdin with this filehandle using dup2(2) before actually executing your program.

Is there a API (like dup) to duplicate fstream so it can

I want to write a stream into one FILE *fp at the same time the stream should be copied onto another fp too is there a better way to write my debug function by eliminating one fprintf?
const int logflag=1;
#define debug(args ...) if (logflag) { FILE *flog = fopen("test.log", "a+"); fprintf( flog, args); fclose(flog); } fprintf(stderr, args);
int main()
{
debug("test"); // writes test into both stderr and flog
debug("test2");
}
The short answer is no, it's two different file pointers and you can only write to one at a time. Actually, dup still doesn't help you because it closes the duplicated file descriptor:
"dup2() makes newfd be the copy of oldfd, closing newfd first if necessary"
from the dup2 man-pages
However, if your goal is to have both a log to the screen and to a file, you are better served by using the tools Linux already provides you. A generally good practice (I don't remember the source for this) is to have a program print its output and debugging to a stdout/stderr and let the calling user determine how to handle the output.
Following this, if all of your output goes to stderr, you can do the following when executing the program:
$ ./program 2>&1 | tee file.log

Resources