Call bash command within C file with a variable - c

I hope my question is clear. I need to read a file in C, store the contents of the file and then use this variable in a bash script.
For example, there is a file called "test.txt" which contains "aaa". Here is the call in C:
#include <signal.h>
#include <time.h>
char ch;
FILE *fp;
int main(int argc, char **argv) {
fp = fopen("test.txt", "r");
char contents[9] = "";
if( fp == NULL ) {
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
int i = 0;
while( ( ch = fgetc(fp) ) != EOF ) {
contents[i]=ch;
i++;
}
contents[9]=0;
fclose(fp);
system( "echo 'hi'");
puts(contents);
}
Now I need to use a bash script to read the file name that has the "aaa" in its name.
system("cat /home/user/$contents.txt");
I have tried finding some other solutions but I have only encountered popen so far that I failed to implement. If I used bash, its a very simple one liner, thus why I am trying to implement it. Are there any other options?

If I understand your question correctly, maybe you can pass contents to bash via environment variable.
http://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access
here's an example code:
#include <stdlib.h>
int main(){
char * message = "hello";
setenv("contents", message, 1);
system("echo $contents");
}
the output of this script is
hello

Related

Beginner Q -ARGV and multiple files

Good afternoon, Old man trying to learn new tricks here,
I have been given an assignment that I am trying to work my way through but I am stuck as I don't fully understand the argv[]
I have 4 files I want to read from and eventually use malloc and realloc but thats further down.
My initial plan was to try read one file and get it onto the command line. I had it opening but made that many changes that now I'm lost.
Think my problem lies with argv[4] as i dont understand it, when I put 4 it goes into theloop and errors but with 1 it just bombs out.
If someone can point me in the direction I am going wrong here it would be great
Thanks
struct Person { char lname[20]; char fname[20]; int id; };
int i, N;
struct Person *student;
int main(int argc, char *argv[])
{
FILE *outputfile;
printf("Please enter the name of the file to open: ");
scanf("%s", argv[4]);
outputfile = fopen(argv[4], "r") ;
if (outputfile==NULL){
perror(argv[1]);
fprintf(stderr,"Error while opeining file\n");
exit(-1);
}
You don't have to use argv[]. Argv is an array of strings that store the arguments passed in when running the executable. If you run the executable like this: ./a.out, then argv only contains one element, which is the path of the executable itself. If you run the program like this, and you try to access argv[4], it does not give you an error, but if you debug it using GDB, it will output the following: warning: Invalid parameter passed to C runtime function.
You could pass in a file on the command line like this: ./a.out yourfile.txt. In this case, argv[0] will be the path of the executable a.out, and argv[1] will be the string "yourfile.txt".
It might be easier to completely drop the use of argv and store the user input for the filename in a string. You can then pass that string as an argument to fopen. This would look something like this:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char fileName[30];
char ch;
printf("Please enter a file name\n");
scanf("%s", fileName);
FILE *outputFile = fopen(fileName, "r");
if(outputFile == NULL) {
printf("Could not open %s\n", fileName);
exit(-1);
}
}
Use constants (NAME_LEN) instead of hard-coding magic values.
Prefer multiple lines for your struct. It's easier to read and version control systems prefer lines for diffs.
Avoid global variables.
Do a boundary check using argc (count of elements in argv) before you read argv. argv[0] is the name of your program, argv[1] is the first argument.
Treat argv as read-only, i.e. don't do scanf("%s", argv[4]).
Prefer to initialize variables instead of declaring and assigning a value separately. It's easy to forget setting a variable before use which leads ot undefined behavior. Initialization might be faster, too.
Your file handle is called outputfile but with fopen() you use the mode of r for reading. Either mode should be w or you want to change the variable name to inputfile.
#include <stdio.h>
#include <string.h>
#define NAME_LEN 20
struct Person {
char lname[NAME_LEN];
char fname[NAME_LEN];
int id;
};
int main(int argc, char *argv[]) {
char filename[FILENAME_MAX];
if(argc > 4) {
strcpy(filename, argv[4]);
} else {
printf("filename? ");
fgets(filename, FILENAME_MAX, stdin);
filename[strcspn(filename, "\n")] = '\0';
}
FILE *outputfile = fopen(filename, "w");
if(!outputfile) {
// ...
}
fclose(outputfile);
}
and you would run your program with either:
$ ./a.out dummy dummy dummy output.txt
or
$ ./a.out
filename? output.txt
It sounds as if you are expected to provide 4 file names as command line parameters. In which case you should be doing this:
#include <stdio.h>
int main (int argc, char *argv[])
{
const int files = 4;
if(argc != files+1)
{
printf("Usage: myprog file1 file2 file3 file4");
return 0;
}
FILE* fp [files];
for(int i=0; i<files; i++)
{
fp[i] = fopen(argv[i+1], "r");
...
}
...
}

Open two arguments from command line in C

How would I go about opening only two files from the command line in C? I am working on a Machine Learning Project where the first file has the training data (train.txt) and the second file has the actual data (data.txt). For example, when I compile I am looking for something like this:
./machineLearning train.txt data.txt
Initially, I was thinking it would be something along these lines but was not quite sure if this made sense:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char fileName[100];
while(argc < 2)
{
FILE* fp;
fp = fopen(fileName, "r");
}
}
You find the command line arguments in argv. The first argument is a string at argv[1] and the second at argv[2]. So (after checking argc that you have indeed gotten two arguments), just pass these strings to fopen to open the files:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *file1;
FILE *file2;
if (argc < 3) {
/* report that not enough arguments have been given and exit */
}
file1 = fopen(argv[1], "r");
file2 = fopen(argv[2], "r");
/* Check whether file1 or file2 are 0, in case either file could not be opened,
then use the file streams as you require. */
}

C can't open file in Unix but works fine on macOSx

I've written a program to reverse a .txt file, line-by-line, and return the output to a new file. It is part of the requirements for the command line arguments to NOT include the .txt extension, so I add in at the top of the program before fopen is called on the file. This works perfectly fine in macOSx terminal, as you can see here: https://imgur.com/a/HqUFd
However, when I upload this to my school's server, I get the following output: https://imgur.com/a/rCdaI
Relevant code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define NUMARG 3
#define INFILEARG 1
#define OUTFILEARG 2
int countWords(const char *sentence);
int main(int argc, char *argv[]){
/* File pointers */
FILE *finp;
FILE *foutp;
/* Three levels of strings: word < line < text.
Both token variables to use with strtok splitting the text. */
char **holdWords = NULL, *holdLine = NULL, *holdText = NULL,
*lineToken = NULL, *wordToken = NULL;
int stringSize = 0, totalStrings, i;
size_t size = 0;
/* Add .txt extension */
int inFileNameSize = sizeof(argv[INFILEARG]);
int outFileNameSize = sizeof(argv[OUTFILEARG]);
char inFileName[inFileNameSize+4]; //add 4 to have room for ".txt"
char outFileName[outFileNameSize+4];
strcat(inFileName, argv[INFILEARG]);
strcat(inFileName, ".txt");
strcat(outFileName, argv[OUTFILEARG]);
strcat(outFileName, ".txt");
/* Check for errors in argument number and opening files. */
if(argc != NUMARG){
printf("You have to put the input and output files after the program name.\n"); fflush(stdout);
return(1);
}
if( (finp = fopen(inFileName, "r")) == NULL ){
printf("Couldn't open %s for reading.\n", inFileName); fflush(stdout);
return(1);
}
if( (foutp = fopen(outFileName, "w")) == NULL){
printf("Couldn't open %s for writing.\n", outFileName); fflush(stdout);
return(1);
}
Can anyone help me figure out what's going on here? Thank you.
EDIT TO EXPLAIN WHY DIFFERENT THAN LINKED QUESTION: While it's helpful to know why a pointer to an array can't be sizeof'd, my question is about getting the size of a string (one pointer, not a pointer to a pointer). I get an error when using strlen on my mac, yet it works on unix. I get an error when using sizeof of the unix, yet sizeof works on my mac.
It appears your have a buffer overflow, you can see this by the fact the file names printed appear corrupted.
If you look at the lines:
/* Add .txt extension */
int inFileNameSize = sizeof(argv[INFILEARG]);
int outFileNameSize = sizeof(argv[OUTFILEARG]);
Your error lies in the use of the sizeof operator. This returns the sizeof the type not the length of the string. Hence your in/outFileNameSize variable is too short for the actual string you are copying into it.

Command line error

The following code is supposed to read a text file character by character and count the frequency of their occurrence. However, on the Linux command line, it compiles and when I try to run it by the command ./program<file.txt it shows
useage: huffman <filename>
I don't know what's the error.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int count[26];
int main(int argc, char ** argv)
{
unsigned char c;
FILE * file;
int i;
if ( argc != 2 ) {
fprintf(stderr, "Useage: huffman <filename>\n");
exit(1); // exit with error code
}
file = fopen(argv[1], "r");
assert( file != NULL );
c = fgetc(file);
while( !feof(file) ) {
c = fgetc(file);
count[c-'a']++;
}
for(i=0; i<26; i++)
printf("count[%c]=%d\n",65+i,count[i]);
fclose(file);
return 0;
As you execute it as
$ ./program < file.txt
you are calling the program with zero arguments and set its standard input stream to read from file.txt. Therefore, argc in your main is 1 and you get the error message you have placed for this case.
To solve this, you can either
run the program as it's supposed to (without shell redirection)
$ ./program file.txt
or modify your program such that it reads from standard input if called with no arguments. It may then be called either way.
Many POSIX commands use the convention that if called with no file names, they read from standard input instead. For example,
$ cat file.txt
outputs the contents of file.txt while
$ cat
parrots back at you everything you type.
To implement this, you'd need something like this.
FILE * file = NULL;
if (argc == 1)
{
file = stdin;
}
else if (argc == 2)
{
file = fopen(argv[1], "r");
if (file == NULL)
{
fprintf(stderr, "error: %s: %s: %s\n",
"cannot read file", argv[1], strerror(errno));
return EXIT_FAILURE;
}
}
else
{
fprintf(stderr, "error: %s\n", "too many arguments");
return EXIT_FAILURE;
}
assert(file != NULL); /* we have made this sure */
c must be an int.
Make sure c is in proper range before indexing the array.
c = fgetc(file);
if (islower((unsigned char)c)) count[c-'a']++; // assumes 'a' thru 'z' are sequential
You need to #include <ctype.h> for the correct prototype for islower()

How do I define and pass in a file name to fopen() from command line?

I have the following program that writes a user's input to a file. Currently the file to be written to is predefined; however, I was wanting allow the user to define the file name from command prompt. What would be the best way to add this functionality? I am having trouble getting my head around how I would make the string entered by the user an argument in the fopen() function. Should I use scanf() or create another getchar() while loop store the chars in an array and then create a variable as the argument of fopen() or something?
#include <stdio.h>
int main()
{
char c;
FILE *fp;
fp = fopen("file.txt", "w");
while ((c = getchar()) != EOF)
{
putc(c, fp);
}
return 0;
}
That's what the arguments to main are for:
#include <stdio.h>
int main(int argc, char **argv)
{
char c;
FILE *fp;
if (argc >= 2)
fp = fopen(argv[1], "w");
else fp = fopen("file.txt", "w");
while ((c = getchar()) != EOF)
{
putc(c, fp);
}
return 0;
}
If you followed this, you might wonder what is in argv[0]. That's where the program name is. Some operating system environments put the full path to the executable file there. Others put only the program name. Others still put what was typed.
For the command ../../bin/someprogram
on Windows, argv[0] is "C:\\Documents and Settings\\User\bin\\someprogram.exe"
on Linux/bash, argv[0] is ../../bin/someprogram
on Ultrix/csh, (I think) argv[0] is /home/username/bin/someprogram
Use argc and argv
#include <stdio.h>
int main(int argc, char **argv)
{
char c;
FILE *fp;
if(argc < 2){
printf("Usage : ./a.out <filename>");
exit(0);
}
fp = fopen(argv[1], "w");
while ((c = getchar()) != EOF)
{
putc(c, fp);
}
return 0;
}
Define main like this:
int main(int argc, char *argv[]) {
And then use argv: an array of the command-line arguments. argv[0] is the name of the command as entered at the command line, argv[1] is the first argument.
fp = fopen(argv[1], "w');
You probably want to check that argc > 1 to avoid an out-of-bounds array access.
There are many functions to read in strings; fgets and scanf, for example. The problem is that you need to know the max number of characters that you want to read in before-hand. If this is ok for you, then use one of those. If not, then you'll have to write your own function to read in a dynamic string, like here.

Resources