I'm working on a programming assignment for my Operating Systems class and I'm running into some issues with the way my output is showing up in the terminal.
The purpose of the program is to take input from a file or the STDIN and essentially pass it through 4 pipes to get the frequency of the words. I'm using calls to fork(),execlp(), and pipe() to complete this and am not having any issues with my program, however as the last child executes and prints to the terminal it looks like this:
os-class ~/cs344/Homework3 190% myword text.txt
os-class ~/cs344/Homework3 191% 1 aaaaa
1 aaaaaa
1 aaaaaaa
8 it
5 s
5 sa
(Here I could enter command for 191%, something like 'ls'..)
myword is my executable and text.txt is the file I'm using for testing. I'm mainly confused because it seems like my pipes are lined up correctly with STDIN and STDOUT. Do I need to insert a wait() somewhere?
Thanks for any suggestions and sorry if there's already an answer to this somewhere! I wasn't exactly sure what to search for.
Each parent that does fork() will need to wait() on its children or the children will continue to run after the parent has exited.
The shell (if you wrote it) also needs to wait on the programs it starts.
Related
I am trying to make a program that can process sentences in C in the POSIX environment. Assume that my program's name is "test". If the user entered just "./test", then my program will ask the user to enter some sentences. This one so far is easy.
However, if the user entered "./test < file.txt", the program should get the characters from that txt file. I do not know how I can get the characters of the file in C. I tried something like file = open(argv[2]);, but it did not work.
I will really appreciate it if you give me the answer to this question.
TL;DR: If you start your program like
./test
and you have to type in the input, then exactly the same program will read from file.txt if you start it as
./test < file.txt
Longer explanation starts here. (The following explanation is not 100% precise, but shall help to get an understanding what is going on in principle.)
In a C program you can open files with fopen. As a return value, fopen gives you a FILE pointer. However, when you start a program under Unix, three FILE pointers are already available. These default FILE pointers are stored in variables named stdin, stdout and stderr.
Of these, stdin can be used to read from, stdout and stderr can be written to. And, stdin is used as default in several C library calls, like, gets or scanf. Similarly, stdout is used by default for calls like printf.
Now, although they are called FILE pointers, they can in fact represent other things than just files. stdin could be a file, but it can also be a console where you can type in stuff.
This latter scenario is what you observe when you start your test program from the shell with the command
./test
In this case, the test process will be started with stdin just using the console from the shell from which you started the test program. Therefore, if in your test program you call, say, gets(), then your program will implicitly read from stdin, which represents the console input that was inherited from the shell. Consequently, in this case the user has to provide input by typing it in.
Now let's look at what happens if you start your process from the shell in the following way:
./test < file.txt
Here, the shell does a bit of extra work before it actually creates your test process. This is because the < file.txt part of your command line is interpreted by the shell - this is not passed as arguments to your program. Instead, what the shell does is, to open the file.txt and, when the test process is started, hand the opened file.txt over to the process such that in your test process stdin is connected to file.txt.
Then, the call to gets() in your program will again read from stdin, but this time stdin is not the console. This time stdin really corresponds to a file, that is, file.txt.
I understand how IPC works and how when you make a pipe before fork() the child/children can inherit the pipe for communication. However, I cant wrap my head around how I would do this for two unrelated processes? (i.e processes that are not the parent or children of each other?).
Im asking because Im trying to get one of my .c files to communicate with another .c file via pipes, but I dont know how that works explicitly in xv6. Any help/ideas would be greatly appreciated!!
There are several ways to accomplish this, for something simple, try checking out popen(). One program can spawn an unrelated one and then can then read and write to each other.
https://man7.org/linux/man-pages/man3/popen.3.html
For other solutions you should look into FIFO files or even sockets as a means of IPC.
Pipes are not able to communicate between 2 processes unless those two processes share a common ancestor, regardless of the Linux distro you use. If you are trying to allow 2 unrelated files to communicate, one of the exec() commands must be used in the child or parent process; this page may have what you're looking for.
What pipe does is to connect the standard output of one program to the standard input of another program.
Consider the cat and wc program in xv6. cat displays the content of a file or files. Let's say we have a text file test.txt with Hello World in it. cat can display its content like this:
$ cat test.txt
Hello World
wc calculates the number of lines, words, and characters in a file, files, OR stdin. So it can be used either like this(read from a file):
$ wc test.txt
1 2 12 test.txt
or this(read from stdin):
$ wc
Hello World
<Press Ctrl-D>
1 2 12
We can use pipe to connect these two commands:
$ cat test.txt | wc
1 2 12
So here cat reads the file and prints its content into stdout, but it doesn't get displayed onto the screen. Instead it gets feeded into the stdin of wc and wc counts the lines, words, and characters in it. Notice that this communication is unidirectional. It only goes from left to right, no backwards.
You can refer to the source code of these two commands to write your program. Basically all you have to do is to make sure the previous command outputs into stdout and the subsequent command reads from stdin.
I'm now working on a small C program in Linux. Let me explain you what I want to do with a sample Linux command below
ls | grep hello
The above command is executed in the below passion (Let me know if I've got this wrong)
ls command will be executed first
Output will be given to grep command which will again generate output by matching "hello"
Now I would like to write a C program which takes the piped output of one command as input. Means, In the similar passion of how "grep" program was able to get the input from ls command (in my example above).
Similar question has been asked by another user here, but for some reason this thread has been marked as "Not a valid question"
I initially thought we can get this as a command line argument to C program. But this is not the case.
If you pipe the output from one command into another, that output will be available on the receiving process's standard input (stdin).
You can access it using the usual scanf or fread functions. scanf and the like operate on stdin by default (in the same way that printf operates on stdout by default; in the absence of a pipe, stdin is attached to the terminal), and the C standard library provides a FILE *stdin for functions like fread that read from a FILE stream.
POSIX also provides a STDIN_FILENO macro in unistd.h, for functions that operate one file descriptors instead. This will essentially always be 0, but it's bad form to rely on that being the case.
If fact, ls and grep starts at the same time.
ls | grep hello means, use ls's standard output as grep's standard input. ls write results to standard output, grep waits and reads any output from standard input at once.
Still have doubts? Do an experiment. run
find / | grep usr
find / will list all files on the computer, it should take a lot of time.
If ls runs first, then OS gives the output to grep, we should wait a long time with blank screen until find finished and grep started. But, we can see the results at once, that's a proof for that.
The topic might sound weird, but here's what I want to achieve:
In Terminal A, type command line as following:
./create proA
The first process proA is created. It outputs something like
This is process A.
Open another terminal window (called Terminal B). In Terminal B, type the following line:
./create proB
The second process proB is created. It outputs:
This is process B.
UPDATED:
I'm trying to create two processes that communicate with each other. Before going into more details, I just want to try if I can create another process that has some relationship with first process when another terminal window is opened.
Is it possible to achieve something like this? If so, can someone give any tip for how to start in c? Thanks!
The terminals don't matter for inter process communication. There are so many ways to communicate between processes that it doesn't make sense to highlight any of them here.
About having a own terminal for each process. Well:
(xterm -e "${COMMANDLINE1}" &) ; (xterm -e "${COMMANDLINE2}" &)
if you want to see only errors, you should use:
./process > /dev/null 2>&1
if you did't understood 2>&1, read below)
possible numbers:
0 — STDIN, 1 — STDOUT and 2 — STDERR
that means, all std errors will be printed in std out.
I'm working on a fairly simple application in C. The end goal is to pipe the output from one process to in input of another in a *nix environment (yes, I am aware of the pipe() command and dup/dup2 but I'm trying to find away around using those commands). I was wondering if there is any way to connect the streams rather than using file descriptors (The systems aren't guaranteed to be POSIX compliant).
So basically I want to do something like this (pseudo-code)
pid = fork()
if pid == 0
// assign this process's stdin to the parents stdout.
stdin = parent.stdout;
exec() // launch new process that receives the parents stdout as stdin
// child stuff....
else
// parent stuff....
I know that it probably won't be as simple as just doing an assignment as above, but is there any way to do this using only streams? I tried looking around, but couldn't find anything..
Thanks!
sorry if I'm missing the point here but the whole philosophy of *nix is one program, one job. If you need a program to dump the contents of a program to the screen then you have the cat command. If the files too big and you need page breaks you pipe the output of cat to the more command:
cat myfile.txt | more
If you need to pipe between two terminal applications then you're meant to use the command line to do so:
myprog1 | myprog2
Obviously that's the philosophical approach, so if that doesn't help then can you clarify what you're trying to pipe and why you're trying to do it in process ?