first documentation of shell modding
This commit is contained in:
parent
10605055d6
commit
fe76dac62a
|
@ -1,14 +1,498 @@
|
||||||
# `bash` login
|
# `bash` login
|
||||||
|
|
||||||
TODO
|
What happens when we log into a server or when we open up a terminal with `bash` running in it?
|
||||||
|
As always the manual can tell us quite a bit.
|
||||||
|
Quite often you'll find a list of configuration files used by a program near the end of the manual.
|
||||||
|
Sometimes not, your millage may vary but here is the files section of the `bash` manual.
|
||||||
|
|
||||||
|
```
|
||||||
|
FILES
|
||||||
|
/bin/bash
|
||||||
|
The bash executable
|
||||||
|
/etc/profile
|
||||||
|
The systemwide initialization file, executed for login shells
|
||||||
|
/etc/bash.bashrc
|
||||||
|
The systemwide per-interactive-shell startup file
|
||||||
|
/etc/bash.bash.logout
|
||||||
|
The systemwide login shell cleanup file, executed when a login shell exits
|
||||||
|
~/.bash_profile
|
||||||
|
The personal initialization file, executed for login shells
|
||||||
|
~/.bashrc
|
||||||
|
The individual per-interactive-shell startup file
|
||||||
|
~/.bash_logout
|
||||||
|
The individual login shell cleanup file, executed when a login shell exits
|
||||||
|
~/.inputrc
|
||||||
|
Individual readline initialization file
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
I created a minimal container to play around a bit.
|
||||||
|
This is what I have in my home directory.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ ls -la
|
||||||
|
total 24
|
||||||
|
drwxr-xr-x 2 waldek waldek 4096 Jun 15 15:49 .
|
||||||
|
drwxr-xr-x 3 root root 4096 Jun 15 15:47 ..
|
||||||
|
-rw------- 1 waldek waldek 39 Jun 15 15:50 .bash_history
|
||||||
|
-rw-r--r-- 1 waldek waldek 220 Jun 15 15:47 .bash_logout
|
||||||
|
-rw-r--r-- 1 waldek waldek 3526 Jun 15 15:47 .bashrc
|
||||||
|
-rw-r--r-- 1 waldek waldek 807 Jun 15 15:47 .profile
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's have a look at them one by one.
|
||||||
|
First the `.bash_history`.
|
||||||
|
This contains a history of all the commands I ran on this computer!
|
||||||
|
Quite handy for when we forget how to do something but we know we've done it before.
|
||||||
|
You can use `grep` to search the file but there is also a shortcut you can use, `ctrl-r`.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ cat .bash_history
|
||||||
|
vim .profile
|
||||||
|
su
|
||||||
|
ls -la
|
||||||
|
exit
|
||||||
|
su
|
||||||
|
logout
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
Next up is `.bash_logout`.
|
||||||
|
It's purpose is written in the comment on the first line!
|
||||||
|
This file gets executed when a login shell exits.
|
||||||
|
Is there a difference between a *shell* and a *login shell*?
|
||||||
|
I'll let you ponder this a bit and we'll come back to this later.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ cat .bash_logout
|
||||||
|
# ~/.bash_logout: executed by bash(1) when login shell exits.
|
||||||
|
|
||||||
|
# when leaving the console clear the screen to increase privacy
|
||||||
|
|
||||||
|
if [ "$SHLVL" = 1 ]; then
|
||||||
|
[ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q
|
||||||
|
fi
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
Now the `.bashrc` file.
|
||||||
|
I know it's a pretty long file so I'll just show the `head`.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ head .bashrc
|
||||||
|
# ~/.bashrc: executed by bash(1) for non-login shells.
|
||||||
|
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
|
||||||
|
# for examples
|
||||||
|
|
||||||
|
# If not running interactively, don't do anything
|
||||||
|
case $- in
|
||||||
|
*i*) ;;
|
||||||
|
*) return;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
Aha!
|
||||||
|
The comment on the first line mentions *non-login shells* so there must be a difference!
|
||||||
|
This is a very important configuration file and I urge you to read it, especially the comments.
|
||||||
|
What kind of content is in this file?
|
||||||
|
|
||||||
|
Last but not least `.profile`.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ cat .profile
|
||||||
|
# ~/.profile: executed by the command interpreter for login shells.
|
||||||
|
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
|
||||||
|
# exists.
|
||||||
|
# see /usr/share/doc/bash/examples/startup-files for examples.
|
||||||
|
# the files are located in the bash-doc package.
|
||||||
|
|
||||||
|
# the default umask is set in /etc/profile; for setting the umask
|
||||||
|
# for ssh logins, install and configure the libpam-umask package.
|
||||||
|
#umask 022
|
||||||
|
|
||||||
|
# if running bash
|
||||||
|
if [ -n "$BASH_VERSION" ]; then
|
||||||
|
# include .bashrc if it exists
|
||||||
|
if [ -f "$HOME/.bashrc" ]; then
|
||||||
|
. "$HOME/.bashrc"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set PATH so it includes user's private bin if it exists
|
||||||
|
if [ -d "$HOME/bin" ] ; then
|
||||||
|
PATH="$HOME/bin:$PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set PATH so it includes user's private bin if it exists
|
||||||
|
if [ -d "$HOME/.local/bin" ] ; then
|
||||||
|
PATH="$HOME/.local/bin:$PATH"
|
||||||
|
fi
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
## which files are sources when
|
## which files are sources when
|
||||||
|
|
||||||
TODO
|
So, we have different files that are sourced at different times.
|
||||||
|
Let's try to play around a bit.
|
||||||
|
I added some comments to them so we get a clear idea which are sourced when.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ tail -n 1 .bashrc .profile .bash_logout
|
||||||
|
==> .bashrc <==
|
||||||
|
echo I am .bachrc
|
||||||
|
|
||||||
|
==> .profile <==
|
||||||
|
echo I am .profile
|
||||||
|
|
||||||
|
==> .bash_logout <==
|
||||||
|
echo I am .bash_logout
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
When I log in on a tty I get the following output.
|
||||||
|
This is an actual interactive login so we source both `.bashrc` and `.profile`.
|
||||||
|
You might ask yourself where the *other* output comes from.
|
||||||
|
That's up to you to find out!
|
||||||
|
|
||||||
|
```
|
||||||
|
Debian GNU/Linux 11 tester pts/1
|
||||||
|
|
||||||
|
tester login: waldek
|
||||||
|
Password:
|
||||||
|
Linux tester 5.10.0-15-amd64 #1 SMP Debian 5.10.120-1 (2022-06-09) x86_64
|
||||||
|
|
||||||
|
The programs included with the Debian GNU/Linux system are free software;
|
||||||
|
the exact distribution terms for each program are described in the
|
||||||
|
individual files in /usr/share/doc/*/copyright.
|
||||||
|
|
||||||
|
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||||
|
permitted by applicable law.
|
||||||
|
Last login: Wed Jun 15 16:03:17 CEST 2022 on pts/1
|
||||||
|
I am .bachrc
|
||||||
|
I am .profile
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
What if we `su` to ourselves?
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ su waldek
|
||||||
|
Password:
|
||||||
|
I am .bachrc
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
The `.profile` is not sourced!
|
||||||
|
We can however change the behaviour of `su` with arguments.
|
||||||
|
A quick look at the `man su` tells us that.
|
||||||
|
|
||||||
|
```
|
||||||
|
-, -l, --login
|
||||||
|
Start the shell as a login shell with an environment similar to a real login:
|
||||||
|
|
||||||
|
o clears all the environment variables except TERM and variables specified by --whitelist-environment
|
||||||
|
|
||||||
|
o initializes the environment variables HOME, SHELL, USER, LOGNAME, and PATH
|
||||||
|
|
||||||
|
o changes to the target user's home directory
|
||||||
|
|
||||||
|
o sets argv[0] of the shell to '-' in order to make the shell a login shell
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
So we can do the following.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ su - waldek
|
||||||
|
Password:
|
||||||
|
I am .bachrc
|
||||||
|
I am .profile
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
If we `exit` this session we get the following.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ exit
|
||||||
|
logout
|
||||||
|
I am .bash_logout
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
Ah, there is out `.bash_logout` message!
|
||||||
|
And if we exit the tty session we get this.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ exit
|
||||||
|
logout
|
||||||
|
I am .bash_logout
|
||||||
|
|
||||||
|
Debian GNU/Linux 11 tester pts/1
|
||||||
|
|
||||||
|
tester login:
|
||||||
|
```
|
||||||
|
|
||||||
|
When we launch a bash in a bash we get the following.
|
||||||
|
But when we launch a script, none of our files get sourced!
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ bash
|
||||||
|
I am .bachrc
|
||||||
|
waldek@tester:~$ exit
|
||||||
|
exit
|
||||||
|
waldek@tester:~$ bash script.sh
|
||||||
|
I'm a script
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
What about `ssh` connections?
|
||||||
|
I'm running the server on port 2222 because it's a contained with host networking.
|
||||||
|
It's a bit too early to go into too much detail but by then end of the course you'll fully understand what's happening!
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ ssh localhost -p 2222
|
||||||
|
waldek@localhost's password:
|
||||||
|
Linux tester 5.10.0-15-amd64 #1 SMP Debian 5.10.120-1 (2022-06-09) x86_64
|
||||||
|
|
||||||
|
The programs included with the Debian GNU/Linux system are free software;
|
||||||
|
the exact distribution terms for each program are described in the
|
||||||
|
individual files in /usr/share/doc/*/copyright.
|
||||||
|
|
||||||
|
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||||
|
permitted by applicable law.
|
||||||
|
Last login: Wed Jun 15 16:29:26 2022 from ::1
|
||||||
|
I am .bachrc
|
||||||
|
I am .profile
|
||||||
|
waldek@tester:~$ exit
|
||||||
|
logout
|
||||||
|
I am .bash_logout
|
||||||
|
Connection to localhost closed.
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
What if we run a command over `ssh`?
|
||||||
|
Then none of these files are sourced!
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ ssh localhost -p 2222 ls -la
|
||||||
|
waldek@localhost's password:
|
||||||
|
total 36
|
||||||
|
drwxr-xr-x 3 waldek waldek 4096 Jun 15 16:29 .
|
||||||
|
drwxr-xr-x 3 root root 4096 Jun 15 15:47 ..
|
||||||
|
-rw------- 1 waldek waldek 649 Jun 15 16:27 .bash_history
|
||||||
|
-rw-r--r-- 1 waldek waldek 243 Jun 15 16:19 .bash_logout
|
||||||
|
-rw-r--r-- 1 waldek waldek 3545 Jun 15 16:20 .bashrc
|
||||||
|
-rw-r--r-- 1 waldek waldek 826 Jun 15 16:17 .profile
|
||||||
|
drwx------ 2 waldek waldek 4096 Jun 15 16:29 .ssh
|
||||||
|
-rw------- 1 waldek waldek 3141 Jun 15 16:20 .viminfo
|
||||||
|
-rw-r--r-- 1 waldek waldek 34 Jun 15 16:18 script.sh
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
# A clean slate
|
||||||
|
|
||||||
|
I deleted all the content of our three files.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:~$ cat .bashrc .bash_logout .profile
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
waldek@tester:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
We don't see any differences but our shell is *less* powerful.
|
||||||
|
For example, autocomplete does not work anymore on things like `systemctl`.
|
||||||
|
We now have a `bash` shell that has only sourced actual content from the following files.
|
||||||
|
|
||||||
|
* `/etc/profile`
|
||||||
|
* `/etc/bash.bashrc`
|
||||||
|
* `/etc/bash.bash.logout` if it exists
|
||||||
|
|
||||||
|
As these are system files we can only edit them as `root`.
|
||||||
|
I went a head and added a comment `#` in front of every line.
|
||||||
|
When I now log in on a tty I get the following.
|
||||||
|
|
||||||
|
```
|
||||||
|
Debian GNU/Linux 11 tester pts/1
|
||||||
|
|
||||||
|
tester login: waldek
|
||||||
|
Password:
|
||||||
|
Linux tester 5.10.0-15-amd64 #1 SMP Debian 5.10.120-1 (2022-06-09) x86_64
|
||||||
|
|
||||||
|
The programs included with the Debian GNU/Linux system are free software;
|
||||||
|
the exact distribution terms for each program are described in the
|
||||||
|
individual files in /usr/share/doc/*/copyright.
|
||||||
|
|
||||||
|
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||||
|
permitted by applicable law.
|
||||||
|
Last login: Wed Jun 15 16:44:05 CEST 2022 on pts/1
|
||||||
|
-bash-5.1$
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a fully barebones `bash` shell, no bells and whistles at all.
|
||||||
|
You can see our prompt has changed to a super simple one, no more username nor hostname nor path.
|
||||||
|
Tab complete works, but only for programs and paths, not for arguments.
|
||||||
|
|
||||||
# Prompt customization
|
# Prompt customization
|
||||||
|
|
||||||
TODO
|
Form this basic session we can learn quite a bit.
|
||||||
|
The most obvious change is our prompt.
|
||||||
|
The fact that it changed means we can modify it too!
|
||||||
|
Let's discover how.
|
||||||
|
|
||||||
|
From the manual we can conclude that `$PSX` are the variables that hold the prompt.
|
||||||
|
|
||||||
|
```
|
||||||
|
PS0 The value of this parameter is expanded (see PROMPTING below) and displayed by interactive shells after reading a command and before
|
||||||
|
the command is executed.
|
||||||
|
PS1 The value of this parameter is expanded (see PROMPTING below) and used as the primary prompt string. The default value is ``\s-\v\$
|
||||||
|
''.
|
||||||
|
PS2 The value of this parameter is expanded as with PS1 and used as the secondary prompt string. The default is ``> ''.
|
||||||
|
PS3 The value of this parameter is used as the prompt for the select command (see SHELL GRAMMAR above).
|
||||||
|
PS4 The value of this parameter is expanded as with PS1 and the value is printed before each command bash displays during an execution
|
||||||
|
trace. The first character of the expanded value of PS4 is replicated multiple times, as necessary, to indicate multiple levels of
|
||||||
|
indirection. The default is ``+ ''.
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
-bash-5.1$ echo $PS
|
||||||
|
$PS1 $PS2 $PS4
|
||||||
|
-bash-5.1$ echo $PS1
|
||||||
|
\s-\v\$
|
||||||
|
-bash-5.1$
|
||||||
|
```
|
||||||
|
|
||||||
|
Your prompt is defined by the `$PS1` variable.
|
||||||
|
By changing this we can change it's behaviour.
|
||||||
|
|
||||||
|
```
|
||||||
|
-bash-5.1$ PS1="helloworld"
|
||||||
|
helloworldls
|
||||||
|
script.sh
|
||||||
|
helloworldcd /
|
||||||
|
helloworldls
|
||||||
|
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
|
||||||
|
helloworld
|
||||||
|
```
|
||||||
|
|
||||||
|
This is *far* from useful but it's just to prove a point.
|
||||||
|
Let's try to get our username back.
|
||||||
|
Again, by reading the manual we can see all variables we can use in a prompt.
|
||||||
|
I include the **PROMPTING** section for completeness.
|
||||||
|
|
||||||
|
```
|
||||||
|
PROMPTING
|
||||||
|
When executing interactively, bash displays the primary prompt PS1 when it is ready to read a command, and the secondary prompt PS2 when it
|
||||||
|
needs more input to complete a command. Bash displays PS0 after it reads a command but before executing it. Bash displays PS4 as described
|
||||||
|
above before tracing each command when the -x option is enabled. Bash allows these prompt strings to be customized by inserting a number of
|
||||||
|
backslash-escaped special characters that are decoded as follows:
|
||||||
|
\a an ASCII bell character (07)
|
||||||
|
\d the date in "Weekday Month Date" format (e.g., "Tue May 26")
|
||||||
|
\D{format}
|
||||||
|
the format is passed to strftime(3) and the result is inserted into the prompt string; an empty format results in a locale-
|
||||||
|
specific time representation. The braces are required
|
||||||
|
\e an ASCII escape character (033)
|
||||||
|
\h the hostname up to the first `.'
|
||||||
|
\H the hostname
|
||||||
|
\j the number of jobs currently managed by the shell
|
||||||
|
\l the basename of the shell's terminal device name
|
||||||
|
\n newline
|
||||||
|
\r carriage return
|
||||||
|
\s the name of the shell, the basename of $0 (the portion following the final slash)
|
||||||
|
\t the current time in 24-hour HH:MM:SS format
|
||||||
|
\T the current time in 12-hour HH:MM:SS format
|
||||||
|
\@ the current time in 12-hour am/pm format
|
||||||
|
\A the current time in 24-hour HH:MM format
|
||||||
|
\u the username of the current user
|
||||||
|
\v the version of bash (e.g., 2.00)
|
||||||
|
\V the release of bash, version + patch level (e.g., 2.00.0)
|
||||||
|
\w the current working directory, with $HOME abbreviated with a tilde (uses the value of the PROMPT_DIRTRIM variable)
|
||||||
|
\W the basename of the current working directory, with $HOME abbreviated with a tilde
|
||||||
|
\! the history number of this command
|
||||||
|
\# the command number of this command
|
||||||
|
\$ if the effective UID is 0, a #, otherwise a $
|
||||||
|
\nnn the character corresponding to the octal number nnn
|
||||||
|
\\ a backslash
|
||||||
|
\[ begin a sequence of non-printing characters, which could be used to embed a terminal control sequence into the prompt
|
||||||
|
\] end a sequence of non-printing characters
|
||||||
|
|
||||||
|
The command number and the history number are usually different: the history number of a command is its position in the history list, which
|
||||||
|
may include commands restored from the history file (see HISTORY below), while the command number is the position in the sequence of com‐
|
||||||
|
mands executed during the current shell session. After the string is decoded, it is expanded via parameter expansion, command substitution
|
||||||
|
or contain characters special to word expansion.
|
||||||
|
```
|
||||||
|
|
||||||
|
So, to get our username back we need the `\u` variable.
|
||||||
|
|
||||||
|
```
|
||||||
|
helloworldPS1="\u"
|
||||||
|
waldekls
|
||||||
|
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
|
||||||
|
waldek
|
||||||
|
```
|
||||||
|
|
||||||
|
That *glue* between our username and command is rather annoying, let's modify that a bit.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldekPS1="\u -> "
|
||||||
|
waldek -> ls
|
||||||
|
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
|
||||||
|
waldek ->
|
||||||
|
```
|
||||||
|
|
||||||
|
Ah, much better!
|
||||||
|
Now, what time is it?
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek -> PS1="\u \t -> "
|
||||||
|
waldek 17:02:53 -> ls
|
||||||
|
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
|
||||||
|
waldek 17:02:56 ->
|
||||||
|
```
|
||||||
|
|
||||||
|
And where am I?
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester 17:04:10 -> PS1="\u@\H \t -> "
|
||||||
|
waldek@tester 17:04:19 -> ls
|
||||||
|
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
|
||||||
|
waldek@tester 17:04:20 ->
|
||||||
|
```
|
||||||
|
|
||||||
|
And in which directory?
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester 17:04:20 -> PS1="\u@\H:\w \t -> "
|
||||||
|
waldek@tester:/ 17:05:06 -> cd /var/log/
|
||||||
|
waldek@tester:/var/log 17:05:13 ->
|
||||||
|
```
|
||||||
|
|
||||||
|
What about the *other* `$PS` variables?
|
||||||
|
Well, if we want to know the exact time when we launch a command we can modify the `$PS0` variable.
|
||||||
|
|
||||||
|
```
|
||||||
|
waldek@tester:/var/log -> PS0="it is \t \n"
|
||||||
|
waldek@tester:/var/log -> ls
|
||||||
|
it is 17:06:48
|
||||||
|
alternatives.log auth.log btmp dpkg.log journal messages runit user.log
|
||||||
|
apt bootstrap.log daemon.log faillog lastlog private syslog wtmp
|
||||||
|
waldek@tester:/var/log -> cd
|
||||||
|
it is 17:06:58
|
||||||
|
waldek@tester:~ ->
|
||||||
|
```
|
||||||
|
|
||||||
|
## Decoding the *base* prompt
|
||||||
|
|
||||||
|
On a modern install your `$PS1` will probably be as one of the two below.
|
||||||
|
They are actually the *same*, just one has **colors** in it, the other one not!
|
||||||
|
Customizing colors of a prompt is a bit of a nightmare but well worth the exercise!
|
||||||
|
|
||||||
|
* `PS1='\u@\h:\w\$ '`
|
||||||
|
* `PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '']]]]'`
|
||||||
|
|
||||||
# Alternative shells
|
# Alternative shells
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue