Red eyes





Hi, I present to your attention a small tutorial on how to design a command line prompt with a red eye.



Everyone who worked in the console of some Linux probably noted the convenient feature of displaying the current folder, username, server name and something else depending on the distra in the prompt line. I always liked it too. But sometimes it turned out like this:







It is difficult to "create" in a line of three characters, of course the cursor moves to the next line, but it rather infuriates more than helps. And at some point, I said to myself:







I decided to take back all the command line space and never give it to anyone again. The question was how to change the command prompt text? It turned out to be very simple, just change the special system variable `PS1`.







Yes, you can set a new invitation text directly in the terminal. But how do you save the changes? And even without information about the current catalog, you somehow feel uncomfortable, constantly asking yourself the question: "Where am I?" The ~ / .bashrc file will help , in it you can save the PS1 change, and so that information about the current directory does not take up the working space, I decided to place it not IN, but OVER the command line. Add the following line to the ~ / .bashrc file:



PS1='$PWD\n# '


Pay attention to single quotes, if we use double quotes, then instead of a pointer to the $ PWD variable (a system variable that stores the full path of the current folder, analogous to the pwd command) , its value (current directory) will be written to the prompt string and changed when moving from the folder the folder will not be. It looks like this: The







command line is completely free, but the folder name merges with the contents if you run the ls command . We'll have to separate the flies from the cutlets, the folder name from the contents. I decided to add "frames" for $ PWD by adding "-" lines at the top and bottom. How to find out the number of characters in a string? There is also the system variable $ COLUMNS for this.... And to quickly form a string with the required number of "-" characters, use the printf command :



printf -v line "%${COLUMNS}s"


This command will create a variable $ line and fill it with spaces in the amount of $ COLUMNS but we do not need spaces but "-", for this we use the following trick:



line=${line// /-} #     -


Let's add this code to ~ / .bashrc



printf -v line "%${COLUMNS}s"
line=${line// /-}
PS1='\n$line\n$PWD\n$line\n# '






Great, but if we change the size of the terminal window now, the size of the "lines" will not change and the beauty will disappear:







To correct the situation, we will transfer the new code to the info function and add it to PS1:



info () {
    printf -v line "%${COLUMNS}s"
    line=${line// /-}
    printf "\n$line\n$PWD\n$line\n# "
}
PS1='$(info)'


You can combine business with pleasure by adding a "padding" to the top delimiter with the hostname. The insert with the name will be in the middle, for this we need to calculate the center of the line (taking into account the length of the host name and additional characters):



info () {
    name_length="{ $HOSTNAME }"
    name_length=${#name_length}
    top_line_left=$[(COLUMNS-name_length)/2]
    top_line_right=$[COLUMNS-(top_line_left+name_length)]
    printf -v top_line "%${top_line_left}s{_S_${HOSTNAME}_S_}%${top_line_right}s"
    printf -v bot_line "%${COLUMNS}s"
    bot_line=${bot_line// /-}
    top_line=${top_line// /-}
    top_line=${top_line//_S_/ }
    printf "\n$top_line\n$PWD\n$bot_line\n# "
}
PS1='$(info)'






I have enclosed the hostname in curly braces with spaces, but instead of spaces around $ HOSTNAME , the characters "_S_" are used, which are then changed to spaces. This is necessary because in the final line all spaces are replaced by "-", and spaces must remain inside the insert. Let's add colors, for this we will prepare variables with codes for changing the color of the text in the terminal, I used the following colors:



RED='\e[31m' # 
GRN='\e[32m' # 
YLW='\e[33m' # 
BLU='\e[34m' # 
MGN='\e[35m' # 
DEF='\e[0m'  #    
BLD='\e[1m'  # 
DIM='\e[2m'  # 


Let's add these variables to our code:



info () {
    name_length="{ $HOSTNAME }"
    name_length=${#name_length}
    top_line_left=$[(COLUMNS-name_length)/2]
    top_line_right=$[COLUMNS-(top_line_left+name_length)]
    printf -v top_line "%${top_line_left}s{_S_$DEF$BLD$HOSTNAME${DEF}_S_$GRN}%${top_line_right}s"
    printf -v bot_line "%${COLUMNS}s"
    bot_line=$GRN${bot_line// /-}$DEF
    top_line=${top_line// /-}
    top_line=$GRN${top_line//_S_/ }$DEF
    printf "\n$top_line\n$BLD$BLU$PWD$DEF\n$bot_line\n# "
}
PS1='$(info)'






Go ahead, the right side looks empty, you can put the date and time there:



printf -v date "%(%a %d %b %T)T"


To place this on the right, you need to add some amount of spaces after $ PWD , which, let's count:



center_space=$[COLUMNS-${#date}-${#PWD}]
((center_space<0)) && center_space=1
...
printf "\n$top_line\n$BLD$BLU$PWD$DEF%${center_space}s$DIM$date\n$bot_line\n# "






Can you do better? Of course, let's add the output of git status if we are in the folder with the git project:



    git_tst= git_clr=
    [[ -d .git ]] && {
        git_tst=($(git status -c color.ui=never -sb))
        git_tst="GIT ${git_tst[*]} " #   
        git_clr=(GIT $(git -c color.ui=always status -sb))
        git_clr="GIT ${git_clr[*]} " #   
    }
    ...
    center_space=$[COLUMNS-${#date}-${#PWD}-${#git_tst}]
    ...
    printf "\n$top_line\n$BLD$BLU$PWD$DEF%${center_space}s$git_clr$DIM$date\n$bot_line\n\$ "






Note that git_clr and git_tst are first written as an array and then converted to variables. This is necessary in order to remove line breaks from the git status output . But where are the eyes? Now there will be O_o eyes, let's create an array with a basic set of eyes:



eyes=(O o ∘ β—¦ ⍀ β₯)


And let's count their number:



en=${#eyes[@]}


Let's add a mouth symbol:



mouth='_'


And let's make a generator of random faces:



face () {
    printf "$YLW${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}$DEF"
}


The eyes will be located at the edges of the information field, you need to take them into account when calculating the number of spaces in the middle, we will prepare a separate variable for this:



face_tst='O_o  o_O'
...
center_space=$[COLUMNS-${#date}-${#PWD}-${#git_tst}-${#face_tst}]
printf "\n$top_line\n$(face) $BLD$BLU$PWD$DEF%${center_space}s$git_clr$DIM$date $(face)\n$bot_line\n\$ "






How to make your eyes redden? Sitting at the computer for a long time, not sleeping. On stackoverflow.com I came across an interesting question , the author asks: "how to change the color in the command line prompt to red if the last command fails?" This led me to the idea of ​​red eyes. Let's add to the info function remembering the completion status of the last command:



info () {
    error=$?
    ...
}


And let's change the face function so that it checks the $ error variable and, depending on its value, paints the eyes red or yellow:



face () {
    [[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW
    printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"
}






Well , my eyes turned red, but you can add something else. Let's add a check for the $ debian_chroot variable :



[[ $debian_chroot ]] && chrt="($debian_chroot)" || chrt=
...
name_length="{ $HOSTNAME$chrt }"
...
printf -v top_line "%${top_line_left}s{_S_$DEF$BLD$HOSTNAME$chrt${DEF}_S_$GRN}%${top_line_right}s"


And let's change the text in the title of the terminal window:



PS1='$(info)'; case "$TERM" in xterm*|rxvt*) PS1="\[\e]0;$(face 1) \w\a\]$PS1";; esac


The heading will display the face and the current directory, but you will have to slightly modify the face function so that it draws a face without color codes, they will be displayed in the heading as just text, we will pass some parameter to the face function (for example, "1"), add a check inside the function, if the 1st argument is given, output the muzzle without coloring:



face () {
    [[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW
    [[ $1 ]] && printf "${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}" \
             || printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"
}






Final script:



RED='\e[31m' # 
GRN='\e[32m' # 
YLW='\e[33m' # 
BLU='\e[34m' # 
MGN='\e[35m' # 
DEF='\e[0m'  #    
BLD='\e[1m'  # 
DIM='\e[2m'  # 
eyes=(O o ∘ β—¦ ⍀ β₯) en=${#eyes[@]} mouth='_'
face () {
    [[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW
    [[ $1 ]] && printf "${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}" \
             || printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"
}
info () { error=$? git_tst= git_clr=
    [[ -d .git ]] && {
        git_tst=($(git -c color.ui=never status -sb))
        git_tst="GIT ${git_tst[*]} " #   
        git_clr=($(git -c color.ui=always status -sb))
        git_clr="GIT ${git_clr[*]} " #   
    }
    [[ $debian_chroot ]] && chrt="($debian_chroot)" || chrt=
    name_length="{ $HOSTNAME$chrt }"
    name_length=${#name_length}
    face_tst='O_o  o_O'
    top_line_left=$[(COLUMNS-name_length)/2]
    top_line_right=$[COLUMNS-(top_line_left+name_length)]
    printf -v top_line "%${top_line_left}s{_S_$DEF$BLD$HOSTNAME$chrt${DEF}_S_$GRN}%${top_line_right}s"
    printf -v bot_line "%${COLUMNS}s"
    printf -v date  "%(%a %d %b %T)T"
    top_line=${top_line// /-}
    top_line=$GRN${top_line//_S_/ }$DEF
    bot_line=$GRN${bot_line// /-}$DEF
    center_space=$[COLUMNS-${#date}-${#PWD}-${#git_tst}-${#face_tst}]
    ((center_space<0)) && center_space=1
    printf "\n$top_line\n$(face) $BLD$BLU$PWD$DEF%${center_space}s$git_clr$DIM$date $(face)\n$bot_line\n\$ "
}
PS1='$(info)'; case "$TERM" in xterm*|rxvt*) PS1="\[\e]0;$(face 1) \w\a\]$PS1";; esac


That's all, thank you for your attention!) Subscribe, like, that's all, the project is in the info-bar github Create, invent, try!)



care check
"#" "$"?)



(*) (*)



All Articles