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
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?
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
[[ $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
"#" "$"?)
(*) (*)