Is there a way in c to get input from the user rather than stdin that may come from a pipe from another program?
I have a program that first prompts for a password using fgets(pas, 256, stdin) but the problem is would then read from stdin again which is commonly a pipe from another program so when I do cat test | ./a.out it would then read the password from the output of the previous program rather than prompting the user to enter it.
Related
I have this program:
#include <stdio.h>
int main() {
char buf[10];
puts("gimme input:");
fread(buf, 1, 10, stdin);
printf("got %s", buf);
}
When I run this and open another terminal I try to write to stdin:
echo "ASDFASDFASDF" > /proc/{pid}/0
ASDFSADFSADF gets printed on the terminal that is running my C program, but fread still doesn't return until I type in the actual terminal. It also does not print any of the text that I wrote to /proc/{pid}/0
Is there something else I have to do to programatically input text to stdin?
If stdin is a terminal, then writing something to stdin will write to the terminal. Reading from the terminal will read whatever is typed into the terminal, not what's written to the terminal. This is just how terminals work.
If you want a program to read from something other than a terminal, you have to direct that to happen. Or, if you want to use a virtual terminal that you can put information into it and have it be read out, you have to direct that to happen.
Probably the simplest solution is to create a pipe with mkpipe and have the program read from the pipe rather than a terminal.
When you execute the echo command output-ing to the File Descriptor 0 you're just sending text. If you check the file descriptor using ls -l probably it is pointing to an device TTY or PTY/PTS. If you check the FD type using lsof it will be tty. It means you need to interact with this FD such as TTY.
Basically you need to simulate the input to get the expected behavior.
You can do this by calling the kernel tool ioctl.tiocsti(). I added a python code into the following similar question: Writing to File descriptor 0 (STDIN) only affects terminal. Program doesn't read
This question already has answers here:
How to use redirection in C for file input
(4 answers)
Closed 1 year ago.
I'm very beginner-level in coding, C is the only language I have been learning. I've done thorough research on input redirection to a file to try to figure out how it works, but I do not understand where to use the command or exactly how it is used. My question is, where do I put the redirection command line in the program exactly? I know that it looks something like this: ./a < filename.txt , but I have no idea where to put it in the program, or if it even goes in the program? I want to read data from the files into a scanf using a simple loop. Also, the 'a', is that the exact name of the C program you are writing?
If you want to read from a redirection, then the program needs to read from
stdin:
int main(void)
{
char line[1024];
fgets(line, sizeof line, stdin);
puts(line);
return 0;
}
If you execute the program like this:
$ ./readline
then the user must enter the text and press ENTER.
If you execute the program like this:
$ echo "Hello World" | ./readline
Hello World
$ ./readline < filename
First line of filename
then stdin will be connected to the pipe / redirection. You don't have to
worry about this, the shell executing the command does the work (connecting stdin to the pipes, etc) so that
your program only need to read from stdin.
Same thing applies for stdout, if you want that the user calls your program
and uses the output in a pipe or redirection, then just write normally to
stdout. The shell takes care of connecting stdout to the pipe / redirection.
If I receive invalid input from pipe i.e.
echo -1 | my_command
my_command is my C program and I can modify it. Is there any way to prompt the user to enter valid input, i.e. changing the input stream from pipe to stdin?
Thanks in advance.
stdin is the pipe, what you mean is probably open the console instead. That's certainly possible:
freopen("/dev/tty", "r", stdin);
(This should work on any Unix-style platform. Be sure to check for errors, as always.)
This problem maybe a little bit hard to state. For example, a program receive a string from stdin, but it need a interactive input from user, like this:
echo "Some text to handle later after command is specified" | a.out
And in the beginning of the program:
printf("Please input command first");
scanf("%s", &cmd);
/* Some Code Here */
/* process "Some text to handle later after command is specified" */
Is there a way to "suspend" previous input stream and wait for the scanf's ones?
The standard does not specify any way to get interactive user input besides reading from stdin. Since your stdin is occupied with a pipe, you need to tread an implementation-specific path.
For Unix-like systems that would be a special file named /dev/tty. fopen it and use normal stdio functions.
On Windows you probably need to call Console API.
Threre's no guarantee a program is attached to any interactive device, so prepare to fail.
Note that it's considered bad style to write programs this way. If there's any user input expected, a well-witten program should just use stdin. All other input streams should then be passed as filenames via command-line arguments.
When using pipes, the shell sets up the programs stdin to be from the output of the previous command. So reading should not be a problem.
The problem here is that you should not print any output if the input is from a pipe (or redirection). This can be done by checking the result of the isatty function:
if (isatty(fileno(stdin)))
{
/* Only print prompt if input is an interactive terminal */
printf(...);
}
scanf(...);
Or am I misreading you, in that you want to read both from the user, and from the pipe? Then you probably have to open a direct connection to the terminal.
For this you could use ttyname to get the name of the TTY device of stdout and open that device for input to read the user input. That won't work if the stdout is leading to a pipe (or is being redirected) as well.
If you're redirecting input for a compiled c program, what's the typical method of reading this input within the program. Is it simply scanf? Say you have a text file like the following:
1
2
3
4
With 4 numbers, one on each line. How do you redirect standard input in your program to read this file, and duplicate it to another text file? Is each new line sent through scanf?
Redirection of streams is an OS concept, it has nothing to do with the C language. If you read from stdin, which is the standard input stream, you will deal with it correctly. Functions like scanf use stdin implicitly, so your program will work fine regardless of whether it gets its input from the console or from a redirected file.
If you are on Linux, redirection is very easy. If you executable name is a.out
$ echo `a.out` > file.txt
will redirect all output from a.out to file.txt