[Linux] progress bar applet

This blog will mainly deduce a progress bar applet running on Linux step by step, and will use vim editor and gcc compiler . If you are not familiar with these two software, you can click on the link and learn from this blog. The progress bar applet is displayed as follows:
insert image description here

a.\r && \n

There are many characters in C language, but they can be divided into two types macroscopically: visible characters and control characters

Displayable characters: A, a, B, c... and other characters

Control characters: \n (carriage return), \t (horizontal tab), \r (line feed), etc.

\rHere we need to use and \ntwo characters under Linux system

Generally, when we use the C language \nto change the line, or use the computer's Enter key to change the line, we directly change it to the leftmost position of the next line

int main()
{
    
    
	printf("Hello\nWorld!");

	return 0;
}

insert image description here

But in fact, these are two actions, only in the language category. C language uses \nthe two actions of changing to the next line and returning to the current leftmost .

Like our previous old-fashioned keyboard, the Enter key is different from the current Enter key, indicating that the key is the sum of two actions.

insert image description here
So the newline we usually refer to is composed of these two actions.

After understanding the above knowledge, let's take a look at \rthe \nmeaning of and

\r: carriage return (return to the leftmost side of the current line)

\n: Newline (change to the next line)

insert image description here
When we use C language \nfor line break, at the language level, two actions of line break + carriage return are performed by default.

2. The concept of line buffer

question:

Let's first observe the difference between the following two pieces of code after running under Linux

  • The executable file of the two pieces of code will be named MyTest, and run to display

  • Functions will be used in the code sleep, you can use the man command to find it in the No. 3 manual ( Linux common commands )

    man 3 sleep
    

    insert image description here

    • Function: Pause at the current code, in seconds.

code 1

#include<stdio.h>
#include<unistd.h>

int main()
{
    
    
   printf("hello world\n");//使用换行符'\n'
   sleep(3);//暂停3秒后继续运行
   return 0;
}

insert image description here
code 2

#include<stdio.h>
#include<unistd.h>

int main()
{
    
    
   printf("hello world\r");//使用回车符'\r'
   sleep(3);//暂停3秒后继续运行
   return 0;
}

insert image description here

According to our normal logic, both pieces of code should print something, but code 2 only executes sleep and nothing is printed out, why? \rDoes it have something \nto do with?

This problem involves the concept of the cache area (let's briefly understand here, the remaining content of the buffer will be in a later blog)

answer:

Let's take a look at the following code and its running results:

code 3

#include<stdio.h>
#include<unistd.h>

int main()
{
    
    
   printf("hello world");
   sleep(3);//暂停3秒后继续运行
   return 0;
}

insert image description here

We can see the above results, it seems that this time the sleep function is executed first, after the printf is executed, and after the output string, the command line is output.

  • The code in C language executes a sequential structure , which must be executed in sequence and code logic, so printf must be executed first, and then sleep.

  • Printf is executed, and there needs to be a place to temporarily store strings, and this place is the buffer area .

  • When the code is executed, the buffer area is refreshed , and the string is printed to the screen. At this time , the position of the cursor (green cursor) is behind the string.

  • In Linux, every time the data is printed to the monitor, it starts from the position of the cursor, that is, the cursor matches the monitor, where the cursor is, the printing starts there.

  • So the command line will be printed directly after the string. ( Code 1 has a line break, and the cursor is on a new line)

  • Different platform buffers have different expressions. In Linux, the buffer has its own refresh strategy (many)

    What we are looking at now is the line cache , which will refresh the cache area in six situations (only three are introduced, and the rest is irrelevant to this article)

    1. A newline character is encountered, such as: \n. ( Code 1 first sees the string and then sleeps)
    2. when the program ends. ( in the case of code three )
    3. active refresh

From the above content, we can analyze the reasons for the unsuccessful execution of code 2 :

After the printf function is executed, the buffer is not refreshed, and the data is saved in the buffer. After the sleep is executed, the string is printed on the display, but in the previous content we specified \rit as a carriage return, and the cursor returned to the end of the line. left, then the command line is printed at the beginning of the cursor, overwriting the contents of the string. We can't see anything anymore.

So is there a way to fix this? Answer: I can't think of it, as long as we \rput it at the end of the string, the string will eventually be overwritten by the command line. Even if we use other control characters to display the result, the result is different from what we want after all.

Here we can use the third method of refreshing the cache described above to check whether our answer is correct, and see the string appear and disappear on the screen.

Detection:

If we want to actively refresh the buffer, we need to use fflushfunctions. We can also use the man command to find it in the No. 3 manual. Linux common commands

man 3 fflush

insert image description here

The test code is as follows:

#include<stdio.h>
#include<unistd.h>

int main()
{
    
    
   printf("hello world\r");//使用回车符'\r'
   fflush(stdout);//自动刷新缓存区
   sleep(3);//暂停3秒后继续运行
   return 0;
}

insert image description here

We can see from the results that this is the case, its cursor is moved to the far left, and it is overwritten when the command line is printed, and we cannot see the result in Code 2 .

expand

Everything printed to the display is a character

printf("%d",123);
//打印的123,分别为'1'、'2'、'3'

3. Progress bar

Display of results:

insert image description here
We can use the knowledge of the buffer above to implement such a small program on Linux using C language

We can simply divide such a small program into four parts as shown in the figure below:

insert image description here

1. Progress dynamic bar

The graph of the growth of the progress bar I set to =, and start with the >symbol

The setting of the progress bar is from 0% to 100% (0% has no progress), we need 100 pieces of size =, and one more >, and add a terminator at the end \0, a total of 102 bytes are stored, which is the char for storing the progress bar The array size of type is 102.

Note: After creating the array, you need to continue to initialize it to make it 102 bytes, so that it can \0stop accurately every time it reaches the updated position.

We want it to be refreshed every 1% of the load. We need to put the printed array in the loop and \rput it behind the string to be printed. Use fflush(stdout)it to automatically refresh the buffer area. Use usleep(sleep unit seconds, usleep unit Subtle, you can try it yourself to see which one is more suitable) Pause each cycle and continue, so that you can show the shape of the progress bar rising.

insert image description here
insert image description here

2. Progress percentage

We print the progress bar in the loop, as long as the number of loops is printed when printing. Note: the percent sign means that %%it cannot be used \%, and an alarm will be issued. If the compilation on the first platform fails, it will be displayed.

Modify the above code as follows

printf("[%-100s][%d%%]\r",bar,i);

3. Small decorations

At the end of the progress bar, we added a rotating cursor to make it look more vivid,

Here | / - \four symbols are used to represent the cursor and stored in an array. Note: \ represents a shift character, and two \ are used to represent one

Rotate clockwise: "|/-\"

Rotate counterclockwise: "|\-/"

Clockwise is used here, and the complete modified code is as follows:

  #include<stdio.h>    
  #include<unistd.h>    
  #include<string.h>    
      
  #define N 101    
  #define STYLE '='    
      
  int main()    
  {
    
        
    char bar[N];    
    memset(bar,'\0',sizeof(bar));    
    char lable[4] = "|/-\\";    
    int i=0;    
    while(i<=100)    
    {
    
        
      printf("[%-100s][%d%%][%c]\r",bar,i,lable[i%4]);                                                                                      
      fflush(stdout);    
      usleep(100000);    
      bar[i++] = STYLE;    
      if(i!=100) bar[i] = '>';    
    }    
    printf("\n");    
    return 0;    
  }   

insert image description here

4. Color

There are many ways to change the color of the progress bar we output. Here I only show one. Those who are interested can search for it by themselves.

//格式
printf("\e[31m字符串\e[0m");

//31:前景色
//\e[31 :开头
//\e[0m :终止,使改变的颜色只在字符串内

foreground color (font color)

character color
30 black
31 red
32 green
33 yellow
34 blue
35 Purple
36 dark green
37 White

With this knowledge, we can change the color of the progress bar, turning it red, the code is as follows:

#include<stdio.h>
#include<unistd.h>
#include<string.h>

#define N 101
#define STYLE '='

int main()
{
    
    
  char bar[N];
  memset(bar,'\0',sizeof(bar));
  const char* lable = "|/-\\";
  int i=0;
  while(i<=100)
  {
    
    
    printf("[\e[31m%-100s\e[0m][%d%%][%c]\r",bar,i,lable[i%4]);                                                               
    fflush(stdout);                                                   
    usleep(100000);                                                   
    bar[i++] = STYLE;
    if(i!=100) bar[i] = '>';
  }                         
  printf("\n");             
  return 0;    
}  

insert image description here
The color and shape of the progress bar are not the only ones. If you are interested, you can search for more content and create a special progress bar yourself.

Guess you like

Origin blog.csdn.net/m0_52094687/article/details/128720874