Here's a use-case to clarify my question. Say I have a calendar program that is set to run in ~/.bashrc
, and it ensures the streaming output overwrites the same block of lines.
Is it possible to have the streaming output display in the terminal from the background process without clobbering new input? I already looked at Displaying stdout of a background process in specific location of the terminal, but the asker requires outputting new lines at termination, which I don't need to do.
Here's a screenshot of the program output, which currently runs in the foreground and terminates after outputting the formatted text once:
I just want that formatted text to continually replace itself while allowing foreground processes to function as normal. A solution in Bash, C, and / or C++ using something like zsh
or ANSI escape sequences would be perfect for me.
For reference, here's the current C code I'm using, but if it's easier for you, you could just formulate a solution that uses cal
instead:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
const char months[12][10] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
const char weekDays[7][10] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
void printCalendar(void);
int getWeekDay(int, int, int, int, int);
int getMaxDay(int, int);
void getDate(int *, int *, int *, int *, int *, int *, int *);
void formatTime(char *, int, int, int);
int main(void) {
printCalendar();
return 0;
}
void printCalendar(void) {
int second, minute, hour, day, month, year, weekDay, maxDay, col, x = 0, i;
char str[12];
getDate(&second, &minute, &hour, &day, &month, &year, &weekDay);
formatTime(str, hour, minute, second);
maxDay = getMaxDay(month, year);
printf("\e[3J");
printf("%s %s\n", weekDays[weekDay], str);
printf("%s %d, %d\n\n ", months[month], day, year);
printf("Sun Mon Tue Wed Thu Fri Sat\n ");
for (i = 1; i <= maxDay; i++) {
col = getWeekDay(i, month, year, day, weekDay);
if (x > col) {
x = 0;
printf("\n ");
}
while (x < col) {
x++;
printf(" ");
}
x++;
if (i == day) {
if (i < 10) {
printf(" ");
}
printf(" \e[7m%d\e[0m ", i);
} else {
printf("%3d ", i);
}
}
printf("\n\n");
}
int getWeekDay(int day, int month, int year, int rmday, int rwday) {
return (day - rmday + rwday + 35) % 7;
}
int getMaxDay(int month, int year) {
switch (month) {
case 3: // April
case 5: // June
case 8: // September
case 10:// November
return 30;
case 1: // February
if ((year % 100 == 0 && year % 400 != 0) || year % 4 != 0) {
return 28; // Not leap year
}
return 29; // Leap year
default:
return 31; // Remaining months
}
}
void getDate(int *second, int *minute, int *hour, int *day, int *month, int *year, int *weekDay) {
time_t now;
struct tm *date;
time(&now);
date = localtime(&now);
*second = (date -> tm_sec);
*minute = (date -> tm_min);
*hour = (date -> tm_hour);
*day = (date -> tm_mday);
*month = (date -> tm_mon);
*year = (date -> tm_year) + 1900;
*weekDay = (date -> tm_wday);
}
void formatTime(char *str, int hour, int minute, int second) {
sprintf(str, "%02d:%02d:%02d %s", (hour % 12) ? (hour % 12) : 12, minute, second, hour / 12 ? "PM" : "AM");
str[11] = '\0';
}
And the code in ~/.bashrc
is just:
clear && ~/Documents/C/Calendar/calendar
Thanks for any help
Best Answer
I recommend GNU
screen
for this. First, start up a newscreen
instance:Then make a split with Ctrl+A Shift+S. You can resize the top portion with the
resize
command. I found a height of 9 to be reasonable forcal
:Ctrl+A
:resize 9
Then use any command that constantly produces output. I don't use
watch
or even have it on many systems, butworks just as well.
Then Ctrl+A Tab moves you to the other (bottom) part of the split. Finally, Ctrl+A C opens a new shell in which you can run commands without interference from the other portion of the split.
If you want this to occur automatically, you can use
.screenrc
:See
screen(1)
for a full description of commands, and possible inspiration for alternative configurations.