2

Basically what I want to do is have a program with int main(argc, *argv[]) and instead of writing chars into command line, I want to have my program read those words from a file. How could I accomplish this? Is there a special command in Linux for that?

tshepang
  • 12,111
  • 21
  • 91
  • 136
deviance
  • 97
  • 2
  • 5
  • 13
  • "read those words from a file"? Which words? Command line arguments? – Lee Duhem Jan 21 '14 at 02:01
  • https://gist.github.com/anonymous/928ada24aa8e6e1adda9 file number 3, upper cased words as command line arguments – deviance Jan 21 '14 at 09:33
  • You want to read a list of words from a file, then use these words as command line arguments to your/another program? – Lee Duhem Jan 21 '14 at 09:48
  • I want to treat words in this file as command line arguments for program #1 – deviance Jan 21 '14 at 09:50
  • I think it is simpler and better to read your data file directly in your 'gistfile1.c'. Construct a very long command line arguments is possible, but it is unnecessary, and your constructed command line could exceed the system limit about command line length. – Lee Duhem Jan 21 '14 at 09:56
  • :( How could I read it, and put it every word in some 2d char array then? – deviance Jan 21 '14 at 10:01
  • Please try my answer to your question. – Lee Duhem Jan 21 '14 at 10:19
  • Command line parameters are most definitely not the solution here, as the command line length is severely limited ([8191 bytes on windows](http://stackoverflow.com/questions/3205027/maximum-length-of-command-line-string) and [more but not infinite on Linux](http://stackoverflow.com/questions/6846263/maximum-length-of-command-line-argument-that-can-be-passed-to-sqlplus-from-lin), so just read in that file if you want a solution that will also survive larger word sets. – fvu Jan 21 '14 at 11:09

5 Answers5

6

You can use standard redirect operations in a *nix shell to pass files as input:

./myprogram < inputfile.txt

This statement executes your program (myprogram) and pumps the data inside of inputfile.txt to your program

You can also redirect the output of program to a file in a similar fashion:

./myprogram > outputfile.txt
Hunter McMillen
  • 59,865
  • 24
  • 119
  • 170
2

Instead of doing

for(int i = 1; i < argc; i++)
{
    insert(&trie, argv[i]);
}

you could doing something like

FILE *input;
char *line;

....

while (fscanf(input, "%ms", &line) != EOF) {
    insert(&trie, line);
        /* If you make a copy of line in `insert()`, you should
         * free `line` at here; if you do not, free it later. */
        free(line);
}
Lee Duhem
  • 14,695
  • 3
  • 29
  • 47
  • But I won't have argc tell me how many words are there, right? – deviance Jan 21 '14 at 10:35
  • Also, 2 errors when I added this to code: finale.c:163:5: warning: ISO C does not support the 'm' scanf flag [-Wformat] finale.c:163:18: warning: ‘input’ is used uninitialized in this function [-Wuninitialized – deviance Jan 21 '14 at 10:51
  • Well when I forced it to compile it core dump'd – deviance Jan 21 '14 at 11:21
  • `%ms` is not available in all language dialects - cfr [the man page](http://linux.die.net/man/3/scanf). [Here](http://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html) you can see how to switch dialects with gcc. Alternatively (but that's only a quick, temp fix as it's unsafe), redeclare `char line[128];` and `fscanf(input, "%s", line)` and drop the free. It's unsafe because it's vulnerable to buffer overruns, but at least it should allow you to test the rest of the logic of your program. – fvu Jan 21 '14 at 12:31
1

Use redirection

yourprogram < youtextfile

will offer the content of yourtextfile as standard input (stdin) to yourprogram. Likewise

yourprogram > yourothertextfile

will send everything the program writes to standard output (stdout) to yourothertextfile

You'll notice when reading man pages that most system calls have a version that works directly with stdin or stdout

For example consider the printf family:

printf ("hello world\n");

is a shorter version of

fprintf (stdout,"hello world\n");

and the same goes for scanf and stdin.

This is only the most basic usage of redirection, which in my opinion is one of the key aspects of "the unix way of doing things". As such, you'll find lots of articles and tutorials that show examples that are a lot more advanced than what I wrote here. Have a look at this Linux Documentation Project page on redirection to get started.

EDIT: getting fed input via redirection ior interactively "looks" the same to the program, so it will react the same to redirected input as it does to console input. This means that if your program expects data line-wise (eg because it uses gets() to read lines), the input text file should be organized in lines.

fvu
  • 32,488
  • 6
  • 61
  • 79
  • Well it's weird, any idea on why it doesn't work? Text file has words in it, but when I do ./a.out < mytextfile.txt it just doesn't give anything, argc is 1 – deviance Jan 21 '14 at 00:59
  • 1
    hard to say without seeing both the code and the text file... I have to go now, I'll make a quick edit that may help you understand why it could fail. – fvu Jan 21 '14 at 01:02
  • Here it is: https://gist.github.com/anonymous/928ada24aa8e6e1adda9 program number 1 uses this txt file to read upper case words and put them into tree, while program 2 converts any text into upper case words without numbers or any other non alpha characters. File 3 is the text, but much shortened - it has few thousand of words and each one of them has to go to command line – deviance Jan 21 '14 at 09:28
0

By default, every program you execute on POSIX-compliant systems has three file descriptors open (see <unistd.h> for the macros' definition): the standard input (STDOUT_FILENO), the standard output (STDOUT_FILENO), and the error output (STDERR_FILENO), which is tied to the console.

Since you said you want read lines, I believe the ssize_t getline(char **lineptr, size_t *n, FILE *stream) function can do the job. It takes a stream (FILE pointer) as a third argument, so you must either use fopen(3) to open a file, or a combination of open(2) and fdopen(3).

Getting inspiration from man 3 getline, here is a program demonstrating what you want:

#define _GNU_SOURCE
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE    *fp;
    size_t  len;
    char    *line;
    ssize_t bytes_read;

    len = 0;
    line = NULL;
    if (argc > 1)
    {
        fp = fopen(argv[1], "r");
        if (fp == NULL)
        {
            perror(*argv);
            exit(EXIT_FAILURE);
        }
    }
    else
        fp = stdin;

    while ((bytes_read = getline(&line, &len, fp)) != -1)
        printf("[%2zi] %s", bytes_read, line);
    free(line);
    exit(EXIT_SUCCESS);
}

Without arguments, this program reads lines from the standard input: you can either feed it lines like echo "This is a line of 31 characters" | ./a.out or execute it directly and write your input from there (finish with ^D).

With a file as an argument, it will output every line from the file, and then exit.

Diti
  • 1,454
  • 3
  • 23
  • 38
  • How would I put these words in a 2d char array though? I posted a link somewhere up in the comments – deviance Jan 21 '14 at 10:07
  • An array of arrays of `char`, or an array of pointers to `char`? You could either do something like `memcmp(double_array + index, line, bytes_read)` (with `index` a counter you increment each time you insert an element), or, for an array of pointers, `double_array[index] = strdup(line)`. You can do whatever you want with `line` in my code snippet; including duplicate it in whatever control structure (array, list node, etc.) you want. I am not going to give you a more specific code, since I believe I should just answer your original question: how to read lines from a file and process it. – Diti Jan 21 '14 at 12:39
0

You can have your executable read its arguments on the command line and use xargs, the special Linux command for passing the contents of a file to a command as arguments.

An alternative to xargs is parallel.

reinierpost
  • 8,425
  • 1
  • 38
  • 70