I have to solve the following problem as homework: create two processes with popen. The parent process will read from stdin lines of at most 30 chars and give the first child the digits from the line and give the second child the letters from the line, which will transform them to uppercase. Both processes will then print these things to the parent's stdout.
So basically i want something similar to running the "tee" command. Read a line, write some output and repeat until ctrl-d
Here is my attempt:
#include <stdio.h>
#include <ctype.h>
int main() {
FILE *digits, *letters;
char string[31];
if ((digits = popen("tee", "w")) == NULL) {
perror("can't create pipe for digits");
return 1;
}
if ((letters = popen("tr a-z A-Z", "w")) == NULL) {
perror("can't create pipe for letters");
return 1;
}
while(!feof(stdin)) {
fgets(string, 31, stdin);
for (char* c = string; *c != '\0'; c++)
if (isdigit(*c))
fputc(*c, digits);
else if (isalpha(*c))
fputc(*c, letters);
fputc('\n', digits);
fputc('\n', letters);
}
pclose(digits);
pclose(letters);
return 0;
}
But after I write a line and press enter, the program expects input again, without printing anything. It prints all of the output at the end, after pressing ctrl-d. And I don't understand why. It reads the line correctly, then it feeds the correct characters to each child, followed by a new line. Why don't these processes immediately print their output? Is the actual command ran when pclose is called? Because I couldn't find any information about that. Also, is writing '\n' to a child's stdin the same as pressing enter? And what's even weirder is that the last line from the output of each child is printed twice.
For example, here is how I would like it to work:
(input)
1a2b3c
(output)
123
ABC
(input)
4d5e6f
(output)
456
DEF
(ctrl-d)
But I get this:
(input)
1a2b3c
(input)
4d5e6f
(ctrl-d)
(output)
123
456
456
ABC
DEF
DEF
This is the code:
#include <stdio.h>
int main()
{
int i = 0;
while(getchar() != '\n') {
printf("\n%d\n", i);
i++;
}
printf("second printf: %d\n", i);
return 0;
}
The expected ouput after I press enter only is:
second printf: 0
instead of:
0
second printf: 1
Why is this happening ?
I am on linux Ubuntu MATE.
So I got some information about anas firari's environment by reading his other questions. This involves some measure of physic debugging.
You are getting input of \r\n when you type a newline because your terminal is in raw mode. Older shells used to choke on this by treating \r as something that isn't whitespace, but newer ones actually work ok.
I discovered the function read(), but I don't understand everything.
Here is my code:
#include <unistd.h>
#include <stdio.h>
int main(void)
{
char array[10];
int ret;
printf("read : ");
fflush(stdout);
array[sizeof(array) - 1] = '\0';
ret = read(STDIN_FILENO, array, sizeof(array) - 1);
printf("array = %s\n", array);
printf("characters read = %d\n", ret);
//getchar();
return (0);
}
Here is an example of the running program :
$> ./a.out
read : hi guys how are you
array = hi guys h
characters read = 9
$> ow are you
zsh: command not found: ow
$>
Why is it launching a shell command after the end of the program?
I noticed that if I uncomment the getchar() line, this strange behavior disappears. I'd like to understand what is going on, if someone has an idea :)
Your call to read is reading in the first 9 characters of what you've type. Anything else will be left in the input buffer so that when you program exits, your shell will read it instead.
You should check the return value of read so you know how much has been read as it's not guaranteed that it'll be the amount you ask for and also the value returned is used to indicate an error.
The string read in won't be null-terminated either, so you also should use the return value (if positive) to put the NUL character in so that your string is valid.
If you want to read in the whole line, you'll need to put in a loop and identify when there is an end of line character (most likely '\n').
You typed about 20 characters, but you only read 9 characters with read(). Everything after that was left in the terminal driver's input buffer. So when the shell called read() after the program exited, it got the rest of the line, and tried to execute it as a command.
To prevent this, you should keep reading until you get to the end of the line.
int main()
{
int i;
FILE *list,*file;
char temp[30];
list=fopen("filelist","rb");
while(fgets(temp,30,list)!=NULL)
{
file=fopen(temp,"r");
{
fclose(list);
return 0;
}
This is my code I basically want to open all files in filelist but my fopen call (exept the first one always returns a NULL am i missing something also this is my filelist
file1
file2
file3
file4
also i dont use file extensions and files exist in the same directory wtih executable.
fgets() stores the new-line character into the buffer it is populating so you need to remove it before calling fopen() within the while.
From the linked reference page for fgets():
Reads at most count - 1 characters from the given file stream and stores them in str. The produced character string is always NULL-terminated. Parsing stops if end-of-file occurs or a newline character is found, in which case str will contain that newline character.
Example code to remove the new-line:
char* nl = strrchr(temp, '\n');
if (nl) *nl = 0;
fgets leaves the newline on the end of the string, which you can plainly see if you add the following line afterwards:
printf ("[%s]\n", temp);
You'll see something like:
[file1
]
You need to remove it before use, which you can do this with something like:
size_t sz = strlen (temp);
if (sz > 0)
if (temp[sz-1] == '\n')
temp[sz-1] = '\0';
You can see this effect in action in the following complete program:
#include <stdio.h>
#include <string.h>
int main (void) {
size_t sz;
char temp[30];
printf ("\n> ");
while (fgets (temp, sizeof(temp), stdin) != NULL) {
printf ("before: [%s]\n", temp);
sz = strlen (temp);
if (sz > 0) {
if (temp[sz-1] == '\n') {
temp[sz-1] = '\0';
}
}
printf ("after : [%s]\n", temp);
printf ("\n> ");
}
return 0;
}
It basically uses your exact method to get a line using fgets (but from standard input) and then outputs the result both before and after removal of the trailing newline. A sample run follows:
pax> ./testprog
> hello
before: [hello
]
after : [hello]
> goodbye
before: [goodbye
]
after : [goodbye]
> [CTRL-D]
pax> _
You may also want to look at a few other things in that code segment:
the use of an open brace { at the end of the while loop.
the fact that you're opening the files within the loop and not doing anything with them (including closing them).
the use of "rb" open mode. Usually this is unnecessary, it's certainly unnecessary if you know it's a text file.
you should always check the return codes of functions that can fail (like fopen) before using them.
the canonical form of main in C where no arguments are needed is int main (void).
I'll state my case of which I am still uncertain: I thought my problem was with "fopen", but after trying every single solution, I ran into the extension problem, which I'm facing in Windows 10. It appears that Windows puts ".txt" automatically but, if you put ".txt" as extension, the name becomes ".txt.txt" at the end. So I left the file name with no extension, and put "file.txt" as argument of "fopen", and that was the only way it has worked for me.
How can I erase the current printed console line in C? I am working on a Linux system. For example -
printf("hello");
printf("bye");
I want to print bye on the same line in place of hello.
You can use VT100 escape codes. Most terminals, including xterm, are VT100 aware. For erasing a line, this is ^[[2K. In C this gives:
printf("\33[2K\r");
Some worthwhile subtleties...
\33[2K erases the entire line your cursor is currently on
\033[A moves your cursor up one line, but in the same column i.e. not to the start of the line
\r brings your cursor to the beginning of the line (r is for carriage return N.B. carriage returns do not include a newline so cursor remains on the same line) but does not erase anything
In xterm specifically, I tried the replies mentioned above and the only way I found to erase the line and start again at the beginning is the sequence (from the comment above posted by #Stephan202 as well as #vlp and #mantal) \33[2K\r
On an implementation note, to get it to work properly for example in a countdown scenario since I wasn't using a new line character '\n'
at the end of each fprintf(), so I had to fflush() the stream each time (to give you some context, I started xterm using a fork on a linux machine without redirecting stdout, I was just writing to the buffered FILE pointer fdfile with a non-blocking file descriptor I had sitting on the pseudo terminal address which in my case was /dev/pts/21):
fprintf(fdfile, "\33[2K\rT minus %d seconds...", i);
fflush(fdfile);
Note that I used both the \33[2K sequence to erase the line followed by the \r carriage return sequence to reposition the cursor at the beginning of the line. I had to fflush() after each fprintf() because I don't have a new line character at the end '\n'. The same result without needing fflush() would require the additional sequence to go up a line:
fprintf(fdfile, "\033[A\33[2K\rT minus %d seconds...\n", i);
Note that if you have something on the line immediately above the line you want to write on, it will get over-written with the first fprintf(). You would have to leave an extra line above to allow for the first movement up one line:
i = 3;
fprintf(fdfile, "\nText to keep\n");
fprintf(fdfile, "Text to erase****************************\n");
while(i > 0) { // 3 second countdown
fprintf(fdfile, "\033[A\33[2KT\rT minus %d seconds...\n", i);
i--;
sleep(1);
}
You can use a \r (carriage return) to return the cursor to the beginning of the line:
printf("hello");
printf("\rbye");
This will print bye on the same line. It won't erase the existing characters though, and because bye is shorter than hello, you will end up with byelo. To erase it you can make your new print longer to overwrite the extra characters:
printf("hello");
printf("\rbye ");
Or, first erase it with a few spaces, then print your new string:
printf("hello");
printf("\r ");
printf("\rbye");
That will print hello, then go to the beginning of the line and overwrite it with spaces, then go back to the beginning again and print bye.
You could delete the line using \b
printf("hello");
int i;
for (i=0; i<80; i++)
{
printf("\b");
}
printf("bye");
Usually when you have a '\r' at the end of the string, only carriage return is printed without any newline. If you have the following:
printf("fooooo\r");
printf("bar");
the output will be:
barooo
One thing I can suggest (maybe a workaround) is to have a NULL terminated fixed size string that is initialized to all space characters, ending in a '\r' (every time before printing), and then use strcpy to copy your string into it (without the newline), so every subsequent print will overwrite the previous string. Something like this:
char str[MAX_LENGTH];
// init str to all spaces, NULL terminated with character as '\r'
strcpy(str, my_string); // copy my_string into str
str[strlen(my_string)] = ' '; // erase null termination char
str[MAX_LENGTH - 1] = '\r';
printf(str);
You can do error checking so that my_string is always atleast one less in length than str, but you get the basic idea.
i iterates through char array words. j keeps track of word length. "\b \b" erases word while backing over line.
#include<stdio.h>
int main()
{
int i = 0, j = 0;
char words[] = "Hello Bye";
while(words[i]!='\0')
{
if(words[i] != ' ') {
printf("%c", words[i]);
fflush(stdout);
}
else {
//system("ping -n 1 127.0.0.1>NUL"); //For Microsoft OS
system("sleep 0.25");
while(j-->0) {
printf("\b \b");
}
}
i++;
j++;
}
printf("\n");
return 0;
}
This script is hardcoded for your example.
#include <stdio.h>
int main ()
{
//write some input
fputs("hello\n",stdout);
//wait one second to change line above
sleep(1);
//remove line
fputs("\033[A\033[2K",stdout);
rewind(stdout);
//write new line
fputs("bye\n",stdout);
return 0;
}
Click here for source.
under windows 10 one can use VT100 style by activating the VT100 mode in the current console to use escape sequences as follow :
#include <windows.h>
#include <iostream>
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#define DISABLE_NEWLINE_AUTO_RETURN 0x0008
int main(){
// enabling VT100 style in current console
DWORD l_mode;
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleMode(hStdout,&l_mode)
SetConsoleMode( hStdout, l_mode |
ENABLE_VIRTUAL_TERMINAL_PROCESSING |
DISABLE_NEWLINE_AUTO_RETURN );
// create a waiting loop with changing text every seconds
while(true) {
// erase current line and go to line begining
std::cout << "\x1B[2K\r";
std::cout << "wait a second .";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ..";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ...";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ....";
}
}
see following link : windows VT100
there is a simple trick you can work here but it need preparation before you print, you have to put what ever you wants to print in a variable and then print so you will know the length to remove the string.here is an example.
#include <iostream>
#include <string> //actually this thing is not nessasory in tdm-gcc
using namespace std;
int main(){
//create string variable
string str="Starting count";
//loop for printing numbers
for(int i =0;i<=50000;i++){
//get previous string length and clear it from screen with backspace charactor
cout << string(str.length(),'\b');
//create string line
str="Starting count " +to_string(i);
//print the new line in same spot
cout <<str ;
}
}
Just found this old thread, looking for some kind of escape sequence to blank the actual line.
It's quite funny no one came to the idea (or I have missed it) that printf returns the number of characters written. So just print '\r' + as many blank characters as printf returned and you will exactly blank the previuosly written text.
int BlankBytes(int Bytes)
{
char strBlankStr[16];
sprintf(strBlankStr, "\r%%%is\r", Bytes);
printf(strBlankStr,"");
return 0;
}
int main(void)
{
int iBytesWritten;
double lfSomeDouble = 150.0;
iBytesWritten = printf("test text %lf", lfSomeDouble);
BlankBytes(iBytesWritten);
return 0;
}
As I cant use VT100, it seems I have to stick with that solution
echo -e "hello\c" ;sleep 1 ; echo -e "\rbye "
What the above command will do :
It will print hello and the cursor will remain at "o" (using \c)
Then it will wait for 1 sec (sleep 1)
Then it will replace hello with bye.(using \r)
NOTE : Using ";", We can run multiple command in a single go.
For me, this code, work well for serial console window with arduino
on Tera Term VT console:
SEROUT.print("\e[A\r\n\e[2K");
SEROUT.print('>');
I use '>' because on my console command i type command after '>'
use this function to clear n lines in C++
void clear_line(int n) {
std::string line_up = "\x1b[A";
std::string line_clear = "\33[2K\r";
for (int i = 0; i < n; ++i)
std::cout << line_up << line_clear << std::flush;
}
Others have already answered OP's question. Here is an answer for those wondering why carriage return behaves the way it does on their Linux machine -
The behavior of the carriage return character seems to be platform-dependent.
From section '5.2.2 Character display semantics' of the C11 standard:
\r (carriage return) Moves the active position to the initial position
of the current line.
From section '3.86 Carriage-Return Character (< carriage-return>)' of the POSIX standard (https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html):
A character that in the output stream indicates that printing should
start at the beginning of the same physical line in which the
carriage-return occurred. It is the character designated by '\r' in
the C language. It is unspecified whether this character is the exact
sequence transmitted to an output device by the system to accomplish
the movement to the beginning of the line.
It does not state whether carriage return is supposed to erase (=> populate with NUL characters) the entire line or not. My guess is that it is NOT supposed to erase.
However, on my Linux machine (tried on both x86_64 and ARM32), what I observed is that the carriage return character moved the cursor to the beginning of the current line and also populated the line with '\0' characters (NUL characters). In order to notice those NUL characters, you might have to call the write system call directly from your code instead of calling via glibc printf.
Let's take the following code snippet as an example:
printf("hello");
printf("\rbye");
Building and running this on beaglebone black (32-bit ARM) bash terminal:
ubuntu#arm:~$ ./a.out
byeubuntu#arm:~$
strace output on write syscall:
bye) = 9 9hello
+++ exited with 4 +++