Bourne-again Shell
Status: Done except for the "Bash Programming" section.
Pagecode: T->1 A->SAml H->trsa[t,a,si]d[t,a,si] C->SA[ccceji]
Last changed: Friday 2010-09-03 [15:24 UTC]
Abstract:
Bash is a free software Unix shell written for the GNU Project. A Unix shell, also called "the command line", provides the traditional user interface for the Unix operating system and for Unix-like systems. Users direct the operation of the computer by entering command input as text for a shell to execute. The name Bash is an acronym which stands for Bourne-again shell. The name is a pun on the name of the Bourne shell (sh), an early and important Unix shell written by Stephen Bourne and distributed with Version 7 Unix circa 1978, and the concept of being "born again". Bash was created in 1987 by Brian Fox. In 1990 Chet Ramey became the primary maintainer. Bash is the default shell on most GNU/Linux systems as well as on Mac OS X and it can be run on most Unix-like operating systems. It has also been ported to Microsoft Windows using the POSIX emulation provided by Cygwin, to MS-DOS by the DJGPP project and to Novell NetWare. The Bash command syntax is a superset of the Bourne shell command syntax. The vast majority of Bourne shell scripts can be executed by Bash without modification, with the exception of Bourne shell scripts referencing a Bourne special variable or those using builtin Bourne commands.
|
Table of Contents
|
Colorized Shell Prompt
I use the CLI a lot. Especially when the number of concurrent terminal
windows (and therefore terminal sessions) exceeds two or so, folks
tend to confuse terminal sessions with one another — all look the
same (color, prompt, etc.) at first sight ...
What we want/need is to recognize terminal windows/sessions just by
taking a glimpse i.e. are we root with the current session or not, is
the current terminal session used for working remotely or locally and
if working remotely on some server, are we doing so using SSH (Secure
Shell)?
Since Debian ships Bash as its default shell (which I think is an
excellent choice; yeah I know zsh folks think otherwise ;-]) I decided
to finally shorten my todo list for one item and to colorize my bash
prompt.
-
Update: Debian moved to dash for its default shell. Go here for more
details about how to make Bash the default shell — dash is more or
less a sub-set of Bash in terms of functionality i.e. making Bash the
default shell again is just fine.
The Rationale
Anyone who ever wanted to reboot his workstation using init 6, reboot
or something akin but instead caused a remote server to reboot will
agree that having easier to distinct terminals sessions is not just a
blessing but a must-have for any CLI junkie.
I use commands like shutdown to shutdown my subnotebook or workstation
all the time. I use SSH to work on some remote machine and of course I
use the CLI for pretty much anything else too. Even though using the
CLI boosts productivity it is also something to fantastically shoot
yourself into the foot. Because I do not want that to happen, coloring
my prompt is a good thing to do.
I want to be able to easily distinguish if I am root or not (some
standard user e.g. sa). I also want to easily distinguish if I
am working on some local machine (e.g. subnotebook, workstation, etc.)
or if I am working on some remote machine e.g. father's desktop across
the desk or some server hundreds of miles away in some datacenter.
Last but not least, even by making all this magic things happen, I do
not want to heavily change Debian's default prompt appearance i.e. I
am only going to colorize it but not to change its behavior nor its
typical appearance which is username@host:~$ e.g. sa@wks:~$ (me using
my standard user sa on my workstation).
What it looks like
The left image shows me working locally on my subnotebook, using my
standard user sa. Then I become root and what changes is that #
appears red — that is the only thing I changed here compared to
Debian's default setting i.e. Debian's default prompt for root looks
exactly the same except that # is not red but also white as is the
rest of the prompt after becoming root.
With the right image, at first I am working with my standard system
user on my local machine. Then I use SSH to connect to some remote
server i.e. I am now working remotely but I am still sa. As can be
seen, compared to using sa locally where the whole prompt is white it
has become entirely green now. Then I become root on the remote server
— as with becoming root locally — I get a red # but the rest of the
prompt stays green.
The explanation for what can be seen above is as follows:
root no matter where (locally or remotely) gets his red #
- working locally means the prompt appears white
- working remotely
- provides me with a green prompt in case of SSH
- provides me with a blue prompt in case of telnet
- etc.
It took me about 2 days to feel comfortable and get used to this new
setup. Before that I used Debian's standard setup which is the same
except for colors. My opinion is that, aside from looking really nice,
it really helps me a lot with not confusing terminal sessions and
therefore doing something stupid.
Code
There is not much one needs to know in order to understand the basics
of how to colorize the Bash prompt. The Bash manual (man 1 bash) file
for example is an excellent source of information. Aside from it, the
WWW (World Wide Web) is full of hints how to colorize a prompt. The
actual code I use to make things colored can be seen below:
sa@sub:~$ grep -v \# .my_bash_settings
THIS_TTY=tty`ps aux | grep $$ | grep bash | awk '{ print $7 }'`
SESS_SRC=`who | grep $THIS_TTY | awk '{ print $6 }'`
SSH_FLAG=0
SSH_IP=`echo $SSH_CLIENT | awk '{ print $1 }'`
if [ $SSH_IP ] ; then
SSH_FLAG=1
fi
SSH2_IP=`echo $SSH2_CLIENT | awk '{ print $1 }'`
if [ $SSH2_IP ] ; then
SSH_FLAG=1
fi
if [ $SSH_FLAG -eq 1 ] ; then
CONN=ssh
elif [ -z $SESS_SRC ] ; then
CONN=local
elif [ $SESS_SRC = "(:0.0)" -o $SESS_SRC = "" ] ; then
CONN=local
else
CONN=tel
fi
if [ `/usr/bin/whoami` = "root" ] ; then
USR=root
else
USR=notroot
fi
if [ $CONN = local -a $USR = notroot ] ; then
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
elif [ $CONN = local -a $USR = root ] ; then
PS1='${debian_chroot:+($debian_chroot)}\h:\w\[\033[01;31m\]\$\[\033[00m\] '
elif [ $CONN = ssh -a $USR = notroot ] ; then
PS1='\[\033[01;32m\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$\[\033[00m\] '
elif [ $CONN = ssh -a $USR = root ] ; then
PS1='\[\033[01;32m\]${debian_chroot:+($debian_chroot)}\h:\w\[\033[01;31m\]\$\[\033[00m\] '
elif [ $CONN = tel -a $USR = notroot ] ; then
PS1='\[\033[01;34m\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$ \[\033[00m\]'
elif [ $CONN = tel -a $USR = root ] ; then
PS1='\[\033[01;30;45m\]${debian_chroot:+($debian_chroot)}\h:\w\$ \[\033[00m\]'
fi
export PS1
sa@sub:~$
Setup
Now that we have the code available with ~/.my_bash_settings we need
to setup the whole shebang. I am not going to detail why I did what I
did below because the afore mentioned manual file does so already.
Fact is, we want to make this work for root and non-root users as well
i.e. sa in my case. Therefore I make little changes to /root/.bashrc
and ~/.bashrc as can be seen:
1 sa@sub:~$ grep -A0 -B2 my_bash_settings .bashrc
2 # set a fancy prompt
3 #PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
4 source /home/sa/.my_bash_settings
5 sa@sub:~$ grep -A0 -B2 my_bash_settings /root/.bashrc
6 # Changed by Suno Ano
7 #export PS1='\h:\w\$ '
8 source /home/sa/.my_bash_settings
As can be seen in lines 4 and 8, source is used to ... well, source
~/.my_bash_settings every time a new terminal session is
started/spawned. Hint, those who do not know about the source command
might first try type source followed by help source ... and no, there
is no manual file for source because ... well, again, type source :-]
The changes to both /root/.bashrc and ~/.bashrc only affect the
machine locally i.e. if we want a colored prompt locally on our
workstation then it has to be setup there.
Likewise, if we want it on a remote server which is accessed via SSH
(Secure Shell), it has to be setup there as well i.e. putting
~/.my_bash_settings into place and alter /root/.bashrc and ~/.bashrc
as shown above in lines 1 to 8.
Last but not least, in order for bash colorization to take effect no
matter if we use an interactive login shell or just an interactive
shell that is not a login shell, we should uncomment a few lines in
10 sa@sub:~$ grep -v \# .bash_profile | grep .
11 if [ -f ~/.bashrc ]; then
12 . ~/.bashrc
13 fi
14 sa@sub:~$
Everywhere (locally and remote machine, virtualized or non-virtualized
environment) where we have a terminal session and want to have a
colored shell prompt, need we set up the whole shebang — sounds like
a lot of work but actually it is not, it really is not ...
Bash History
The Bourne Again Shell's history mechanism, a feature adapted from the
C Shell, maintains a list of recently issued commands on the CLI
(Command Line Interface), also called events, providing a quick way to
reexecute any of the commands/events in the list. This mechanism also
enables us to execute variations of previous commands and to reuse
arguments. We can replicate complicated commands and arguments that we
used earlier — either in this login session or in a previous one —
and enter a series of commands that differ from one another in minor
ways. The history list also serves as a record of what we have done
i.e. it can prove helpful when we made a mistake and are not sure what
we did, or when we want to keep a record of a procedure that involved
a series of commands.
Involved Files / Variables / Parameters
In order to set up respectively configure bash history behavior to our
likings, we need to know about a few files and variables/parameters
which influence heavily what happens for which users under which
circumstances.
Files
It is always good to know with whom we are dealing with:
/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.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
It is utterly important to understand the meaning of those files with
regards to what kind of shell (login, interactive, etc.) respectively
user (particular user or systemwide) we want to provide settings for.
As we will later see, we are only focusing on my normal user
(sa) but both major types of shells i.e. login and interactive.
Therefore we are going to touch ~/.bash_profile and ~/.bashrc or to be
more precise /home/sa/.bashrc and /home/sa/.bash_profile.
Variables and Parameters
As can be read in detail with man 1 bash, we are interested in
sa@sub:~$ echo $HIST
$HISTCMD $HISTCONTROL $HISTFILE $HISTFILESIZE $HISTSIZE
sa@sub:~$
We want to get our history list bigger plus smarter. Bigger can be
done with HISTFILESIZE and HISTSIZE, smarter with HISTCONTROL,
HISTIGNORE and HISTTIMEFORMAT. Now is a good time to go and read
the man file for bash in order to understand the meaning about those
afore mentioned variables. In short
HISTSIZE, The number of commands/events to remember in the command
history during a session. The default value is 500.
HISTFILESIZE, The maximum number of lines/commands/events contained
in the history file ($HISTFILE) i.e. maximum number of events saved
in between sessions or in other words the number of total history
events saved in a persistent manner. When this variable is assigned
a value, the history file is truncated, if necessary, by removing
the oldest entries, to contain no more than that number of lines —
the default value is 500, same as for HISTSIZE.
HISTCONTROL, A colon-separated list of values controlling how
commands are saved on the history list. If the list of values
includes ignorespace, lines which begin with a space character are
not saved in the history list — this is cool if we want some
commands to NOT be logged. A value of ignoredups causes lines
matching the previous history entry to NOT be saved. A value of
ignoreboth is shorthand for ignorespace and ignoredups. A value of
erasedups causes all previous lines matching the current line to be
removed from the history list before that line is saved. Any value
not in the above list is ignored. If HISTCONTROL is unset, or does
not include a valid value, all lines read by the shell parser are
saved on the history list, subject to the value of HISTIGNORE. The
second and subsequent lines of a multi-line compound command are
not tested, and are added to the history regardless of the value of
HISTCONTROL.
HISTIGNORE, A colon-separated list of patterns (e.g.
HISTIGNORE=ls:ll:la:l:cd:pwd:exit:mc:su:df:clear) used
to decide which command lines should be saved on the history list.
Each pattern is anchored at the beginning of the line and must
match the complete line (no implicit * is appended). Each pattern
is tested against the line after the checks specified by
HISTCONTROL are applied. In addition to the normal shell pattern
matching characters, & matches the previous history line. & may
be escaped using a backslash — the backslash is removed before
attempting a match. The second and subsequent lines of a multi-line
compound command are not tested, and are added to the history
regardless of the value of HISTIGNORE.
HISTTIMEFORMAT, If this variable is set and not null, its value is
used as a format string for strftime to print the timestamp
associated with each history entry displayed by the history
built-in (issue type history && help history for more information).
If this variable is set, time stamps are written to the history
file so they may be preserved across shell sessions.
Configure / Tune
As I said within the File section above, I want the settings to take
effect for one user with his login as well as interactive shells.
First the stuff that does the magic
sa@sub:~$ pwd
/home/sa
sa@sub:~$ cat .my_bash_history_settings
# This file provides bash history settings. It is loaded/sourced in
# ~/.bashrc and ~/.bash_profile with `source
# $HOME/.my_bash_history_settings'.
shopt -s histappend #append to the end of $HISTFILE
export HISTFILESIZE=20000 #number events saved in total
export HISTSIZE=20000 #number events saved during a session
export HISTTIMEFORMAT="%A %Y-%m-%d [%T %z] "
export HISTCONTROL=ignoreboth:erasedups
# Local Variables:
# mode: shell-script
# End:
And then how to apply it for both, interactive login shells as well as
interactive shells for a single user (sa in our particular case).
sa@sub:~$ grep -v \# .bash_profile | grep .
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
sa@sub:~$ grep my_bash_history .bashrc
source $HOME/.my_bash_history_settings
sa@sub:~$
- Hint
-
As of now (September 2008) the
erasedups thingy does not seem to work
in between sessions i.e. only does it erase duplicates made within the
same shell session. Once we end a session (e.g. closing the terminal,
logging out, etc.), shopt -s histappend ensures that the in-memory
history is appended to $HISTFILE.
-
What does this mean? Well, nothing more or less but that
$HISTFILE
actually might contain duplicates if issued in different shell
sessions.
-
A command to get rid of them in a persistent manner is
tac
~/.bash_history | gawk '!seen[$0]++' | tac > ~/.bash_history_no_dups
&& mv ~/.bash_history_no_dups ~/.bash_history (please test before
using it).
Test the Settings made
How it looks like
1 sa@sub:~$ history 10
2 506 Wednesday 2008-09-03 [17:15:46 +0200] source .bashrc
3 507 Wednesday 2008-09-03 [17:18:47 +0200] history -w
4 508 Wednesday 2008-09-03 [18:33:04 +0200] tail .bash_history
5 509 Wednesday 2008-09-03 [18:33:46 +0200] head .bash_history
6 510 Wednesday 2008-09-03 [18:34:01 +0200] history | head
7 511 Wednesday 2008-09-03 [18:34:12 +0200] head .bash_history
8 512 Wednesday 2008-09-03 [18:35:06 +0200] tail -n20 .bash_history | grep -v ^#
9 513 Wednesday 2008-09-03 [18:35:13 +0200] history | tail
10 514 Wednesday 2008-09-03 [18:36:31 +0200] man history
11 515 Wednesday 2008-09-03 [18:40:22 +0200] history 10
12 sa@sub:~$ history | tail
13 506 Wednesday 2008-09-03 [17:15:46 +0200] source .bashrc
14 507 Wednesday 2008-09-03 [17:18:47 +0200] history -w
15 508 Wednesday 2008-09-03 [18:33:04 +0200] tail .bash_history
16 509 Wednesday 2008-09-03 [18:33:46 +0200] head .bash_history
17 510 Wednesday 2008-09-03 [18:34:01 +0200] history | head
18 511 Wednesday 2008-09-03 [18:34:12 +0200] head .bash_history
19 512 Wednesday 2008-09-03 [18:35:06 +0200] tail -n20 .bash_history | grep -v ^#
20 513 Wednesday 2008-09-03 [18:36:31 +0200] man history
21 514 Wednesday 2008-09-03 [18:40:22 +0200] history 10
22 515 Wednesday 2008-09-03 [18:40:27 +0200] history | tail
As can be seen, lines 1 and 12 actually do the same thing. Nice to
note is that, erasedups works just as expected (line 9 is gone after
issuing line 12). Note, that history pools the in-memory history
whereas
23 sa@sub:~$ tail -n20 .bash_history | grep -v ^#
24 exitexit
25 exit
26 source .bashrc
27 source .bashrc
28 history | tail
29 history -w
30 history | tail
31 tail .bash_history
32 head .bash_history
33 history | head
34 sa@sub:~$
asks for the on-disk history which lags behind in time — we can see
that the in-memory (lines 2 to 11 and 13 to 22) history is the same
(except for ignoreboth and erasedups actions) with the on-disk history
(lines 24 to 33) in lines
- 1 to 5 respectively 13 to 17 and
- lines 27 to 33
What is also nice is the result (e.g. Wednesday 2008-09-03 [18:40:27
+0200]) of using export HISTTIMEFORMAT="%A %Y-%m-%d [%T %z]
". So far I am not using HISTIGNORE but I am sure I will some
time.
[ a few days went by ...]
So, has my bash history grown already i.e. does $HISTFILE contain more
than just the default amount of lines/events which we know is 500.
Yes! It works just fine as can be seen:
sa@sub:~$ history 12
764 Thursday 2008-09-04 [20:40:05 +0200] cat /etc/security/time.conf
765 Thursday 2008-09-04 [20:40:43 +0200] cat /etc/security/access.conf
766 Thursday 2008-09-04 [20:42:52 +0200] cat /etc/security/limits.conf
767 Thursday 2008-09-04 [20:55:17 +0200] ban
768 Thursday 2008-09-04 [21:52:05 +0200] uws
769 Thursday 2008-09-04 [21:53:12 +0200] ups
770 Friday 2008-09-05 [07:41:45 +0200] ll
771 Friday 2008-09-05 [07:41:50 +0200] file alltray.desktop
772 Friday 2008-09-05 [07:41:54 +0200] cat alltray.desktop
773 Friday 2008-09-05 [08:39:21 +0200] echo $HISTFILESIZE
774 Friday 2008-09-05 [08:39:30 +0200] history 22
775 Friday 2008-09-05 [08:39:58 +0200] history 12
sa@sub:~$
Exploring the History Features
This section is about a tiny portion of all the fun stuff we can do
using the Bash (Bourne again shell) history and how we can boost our
productivity.
Using Event Designators
I am just providing a few examples. Detailed information can be found
with man 3 history and man 1 bash.
sa@sub:~$ echo "white cat"
white cat
sa@sub:~$ !!
echo "white cat"
white cat
sa@sub:~$ !echo
echo "white cat"
white cat
sa@sub:~$ echo "black duck" !#
echo "black duck" echo "black duck"
black duck echo black duck
sa@sub:~$
Search the history using C-R
I strongly believe, this may be the most frequently used feature of
history. When we have already executed a very long command, we can
simply search history using a keyword and re-execute the same command
without having to type it fully again.
Since we played around with some white cat above, pressing Control+R
and typing for example white gives us a prompt with echo "white cat"
ready to be executed if we hit enter. If we wish to execute echo "red
cat", we do not hit enter immediately but left or right arrow, edit
the former command i.e. replace white with red and then execute with
hitting enter. Wow ... cool ha! ^^ ... I am talking about the red cat
of course ;-]
Repeat the previous Command
Sometime we may end up repeating the previous commands for various
reasons. Following are the 4 different ways to repeat the last
executed command.
- Use the up arrow to view the previous command and press enter to
execute it.
- Type
!! and press enter to execute it.
- Type
!-1 and press enter to execute it.
- Press
C-P will display the previous command, press enter to
execute it.
Execute a specific Command
sa@sub:~$ type uws
uws is aliased to `unison ws_pim_blog.prf'
sa@sub:~$ history | head
1 Wednesday 2008-09-03 [17:12:34 +0200] man vzcpucheck
2 Wednesday 2008-09-03 [17:12:34 +0200] man vzmemcheck
3 Wednesday 2008-09-03 [17:12:34 +0200] man vzsplit
4 Wednesday 2008-09-03 [17:12:34 +0200] man vzquota
5 Wednesday 2008-09-03 [17:12:34 +0200] man usermod
6 Wednesday 2008-09-03 [17:12:34 +0200] man pushd
7 Wednesday 2008-09-03 [17:12:34 +0200] pushd --help
8 Wednesday 2008-09-03 [17:12:34 +0200] uws
9 Wednesday 2008-09-03 [17:12:34 +0200] man rmadison
10 Wednesday 2008-09-03 [17:12:34 +0200] ssh rh0
sa@sub:~$ type !8
type uws
uws is aliased to `unison ws_pim_blog.prf'
sa@sub:~$ history 5
515 Wednesday 2008-09-03 [19:39:02 +0200] echo "white cat"
516 Wednesday 2008-09-03 [19:39:30 +0200] history | head -n22
517 Wednesday 2008-09-03 [19:40:12 +0200] history | head
518 Wednesday 2008-09-03 [19:40:36 +0200] type uws
519 Wednesday 2008-09-03 [19:41:08 +0200] history 5
sa@sub:~$ !515
echo "white cat"
white cat
sa@sub:~$
With the above example, I also wanted to show that substitution (type
!8) works just fine — not just picking a command per its numbered
history entry (!515). The alerted reader might have also noticed, this
works for in-memory as well as on-disk history i.e. for the entire
history.
Subtitute words from History Commands
When we are searching through history, we may want to execute a
different command but use the same parameter from the command that
we have used already.
In the example below, the !!:$ next to the touch command gets the
argument from the previous command to the current command.
sa@sub:/tmp/test$ ll
total 0
sa@sub:/tmp/test$ echo tiger
tiger
sa@sub:/tmp/test$ touch !!:$
touch tiger
sa@sub:/tmp/test$ ll
total 0
-rw-r--r-- 1 sa sa 0 2008-09-03 19:51 tiger
sa@sub:/tmp/test$
In the example below, the !^ next to the touch command gets the first
argument from the previous command (i.e echo command in our current
case) to the current command (i.e touch in our current case.
sa@sub:/tmp/test$ echo blue tiger
blue tiger
sa@sub:/tmp/test$ touch !^
touch blue
sa@sub:/tmp/test$ ll
total 0
-rw-r--r-- 1 sa sa 0 2008-09-03 19:54 blue
-rw-r--r-- 1 sa sa 0 2008-09-03 19:52 tiger
sa@sub:/tmp/test$
So, now we know how to pick the first word from some former executed
command but what if we want to pick the last one or the third out of
six? No problem, watch me
sa@sub:/tmp/test$ ll
total 0
-rw-r--r-- 1 sa sa 0 2008-09-03 19:54 blue
-rw-r--r-- 1 sa sa 0 2008-09-03 19:52 tiger
sa@sub:/tmp/test$ echo blue tiger fish with green stripes
blue tiger fish with green stripes
sa@sub:/tmp/test$ touch !echo:3
touch fish
sa@sub:/tmp/test$ touch !echo:$
touch stripes
sa@sub:/tmp/test$ ll
total 0
-rw-r--r-- 1 sa sa 0 2008-09-03 19:54 blue
-rw-r--r-- 1 sa sa 0 2008-09-03 20:10 fish
-rw-r--r-- 1 sa sa 0 2008-09-03 20:10 stripes
-rw-r--r-- 1 sa sa 0 2008-09-03 19:52 tiger
sa@sub:/tmp/test$
Security Considerations
Suddenly, for all the fellows scratching their heads over security
concerns about what I said above ... I have not forgotten you guys ;-]
Basically, we would alter the same variables as we did already but
assign quite different values. Before I walk us through this subject,
what I did above is providing comfort on boxes as for example
workstations and subnotebooks or other machines used for non critical
stuff and/or only used by a single person ... I would not, and in fact
I do not use this type of setup on some server on the Internet simply
because of security concerns.
First we need to decide, do we want to limit our actions to all users
on a particular system or just to a single user? Whatever one picks,
he has to put his magic into the correct files (see above).
The Idea
For security purposes, we should not use a .bash_history file or limit
what is recorded into it, because secrets such as passwords, keys, or
other sensitive data could possibly be written to the disk — even
these days were the Debian installer enables the novice to set up
full-disk encryption many folks do not do it ... no comment!
-
Once something is written to the disk, it is theoretically always
going to be recoverable — even after deleting the file, writing over
the saved data an arbitrary number of times, and physically damaging
the platters. The only known way to completely destroy data is to
obliterate the platters themselves, i.e. melt 'em down ;-]
The underlying reason is slightly complex and I will not go into
detail here. So, if we need to keep our data secure and security is
critical or we just want to thwart snooping of our data in the case it
is physically stolen then practices like this and lots of good
harddrive encryption is the way to go. On another note, under most
circumstances it is probably still safe (and useful) to keep history
available in our ram memory. Of course, disabling .bash_history means
that when we logout or close the terminal session history will be
lost. Putting that into code it looks something like this (e.g. in
/etc/profile)
export HISTFILESIZE=1
unset HISTFILE
export HISTSIZE=30 #or less
export HISTCONTROL=ignoreboth:erasedups
One might add a HISTIGNORE line to the above (see above). Finally, for
the more paranoid ln -s /dev/null ~/.bash_history.
Bash Programming
WRITEME
Miscellaneous
This section is used to collect bits and pieces that simply do not
justify to provide them with a dedicated section.
Bash Completion
This goes out to all the lazy animals ;-] ... Real wizards are utterly
fond of the CLI simply because time matters. So, why not speeding up
things a bit more i.e. enabling bash completion. In case we want to
enable it for all users on the system, we have to uncomment a few
lines in
sa@wks:~$ grep -A4 -m1 "bash completion" /etc/bash.bashrc
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
sa@wks:~$
In case we want to enable it just for one particular user, we need to
alter his ~/.bashrc i.e. also uncommenting those lines responsible for
bash completion. Once done,
sa@wks:~$ source .bashrc
sa@wks:~$
makes the new settings valid for our current session i.e. no log-out
and log-in necessary as often heard. Ah, and last but not least, one
should of course install the package bash-completion.
Some .bashrc customization I did
Please note that I used GNU Emacs and its allout-mode to structure my
.bashrc file — same mode which I use to structure all my other config
files and the like.
sa@wks:~$ cat .bashrc
###_ main
###_. interactive terminal
# If running interactively, then:
if [ "$PS1" ]; then
###_ , common settings to all interactive terminal types
###_ . local settings
###_ , udate window size
shopt -s checkwinsize
###_ , make extended globs work
shopt -s extglob
###_ . non-local settings (source external files)
###_ , password command sequence
source $HOME/.sec/user_name_and_host_name_pair2password
###_ , bash history
source $HOME/.my_bash_history_settings
###_ , set a fancy prompt
#PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
source $HOME/.my_bash_settings
###_ , set PATH variable
PATH+=:$HOME/0/bash:$HOME/0/bash/photo_utilities
export PATH
###_. interactive, non-dumb terminal
if [ "$TERM" != "dumb" ]; then
###_ , gnupg
GPG_TTY=`tty`
export GPG_TTY
if test -f $HOME/.gpg-agent-info && kill -0 `cut -d: -f 2 $HOME/.gpg-agent-info` 2>/dev/null; then
GPG_AGENT_INFO=`cat $HOME/.gpg-agent-info`
export GPG_AGENT_INFO
else
eval `gpg-agent --daemon`
echo $GPG_AGENT_INFO >$HOME/.gpg-agent-info
fi
###_ , mongodb
export MONGODB_ROOT=$HOME/0/mongodb
alias cdmongodb='cd $MONGODB_ROOT'
###_ , python
export PYTHONSTARTUP=$HOME/.pythonrc
export PYTHONROOT=$HOME/0/python
alias cdpython='cd $PYTHONROOT'
###_ . shells
###_ , bpython
# check out
# http://www.markus-gattol.name/ws/python.html#is_there_a_better_python_shell_interpreter
# for more information
alias bp2='bpython'
alias bp3='python3 -m bpython.cli'
###_ , dreampie
export DREAMPIEROOT=$PYTHONROOT/dreampie/dreampie
alias cddproot='cd $DREAMPIEROOT'
alias dpupdate='cd $DREAMPIEROOT && bzr update && cd'
alias dp2='$DREAMPIEROOT/dreampie >& /dev/null &'
alias dp3='$DREAMPIEROOT/dreampie python3 >& /dev/null &'
###_ . virtualenvwrapper
export WORKON_HOME=$HOME/0/1
alias cdveroots='cd $WORKON_HOME'
###_ . pip
export PIP_VIRTUALENV_BASE=$WORKON_HOME
export PIP_RESPECT_VIRTUALENV=true
export VIRTUALENV_USE_DISTRIBUTE=1
###_ . django
export DJANGO_ROOT=$PYTHONROOT/django
export DJANGO_HEAD=$DJANGO_ROOT/head # always in sync with master/HEAD at http://github.com/django/django
export DJANGO_STABLE=$DJANGO_ROOT/stable # current stable release
export DJANGO_PROJECTS=$DJANGO_ROOT/projects # current projects
export DJANGO_SITES_ROOT=$DJANGO_PROJECTS # needed for django-environment
alias cddjango='cd $DJANGO_ROOT'
alias cddjango_head='cd $DJANGO_HEAD'
alias cddjango_stable='cd $DJANGO_STABLE'
alias cddjango_projects='cd $DJANGO_PROJECTS'
###_ . django_cms
export DJANGO_CMS_ROOT=$DJANGO_ROOT/django_cms
export DJANGO_CMS_HEAD=$DJANGO_CMS_ROOT/head
export DJANGO_CMS_STABLE=$DJANGO_CMS_ROOT/stable
export DJANGO_CMS_PROJECTS=$DJANGO_CMS_ROOT/projects
alias cddjango_cms='cd $DJANGO_CMS_ROOT'
alias cddjango_cms_head='cd $DJANGO_CMS_HEAD'
alias cddjango_cms_stable='cd $DJANGO_CMS_STABLE'
alias cddjango_cms_projects='cd $DJANGO_CMS_PROJECTS'
###_ . pinax
export PINAX_ROOT=$DJANGO_ROOT/pinax
export PINAX_HEAD=$PINAX_ROOT/head
export PINAX_STABLE=$PINAX_ROOT/stable
export PINAX_PROJECTS=$PINAX_ROOT/projects
alias cdpinax='cd $PINAX_ROOT'
alias cdpinax_head='cd $PINAX_HEAD'
alias cdpinax_stable='cd $PINAX_STABLE'
alias cdpinax_projects='cd $PINAX_PROJECTS'
###_ , compass / sass
export COMPASS_PROJECTS=$HOME/0/compass/projects
alias compass_dev='$(gem environment gemdir)/bin/compass'
alias cdcompass_projects='cd $COMPASS_PROJECTS'
###_ , keychain
# eval '/usr/bin/keychain $HOME/.ssh/github_id_rsa $HOME/.ssh/ssh_pka_key_for_user_Suno_Ano C0EC7E38'
###_ , aliases
###_ . command alias
###_ , tree
# don't show git related files/repos, emacs backup files, compiled .py files
alias ta='tree --charset ascii -a -I \.git*\|*\.\~*\|*\.pyc'
alias tap='tree --charset ascii -ap -I \.git*\|*\.\~*\|*\.pyc'
alias td='tree --charset ascii -d -I \.git*\|*\.\~*\|*\.pyc'
alias tad='tree --charset ascii -ad -I \.git*\|*\.\~*\|*\.pyc'
alias tad2='tree --charset ascii -ad -L 2 -I \.git*\|*\.\~*\|*\.pyc'
alias tad3='tree --charset ascii -ad -L 3 -I \.git*\|*\.\~*\|*\.pyc'
alias tas='tree --charset ascii -ash -I \.git*\|*\.\~*\|*\.pyc'
alias tug='tree --charset ascii -aug -I \.git*\|*\.\~*\|*\.pyc'
###_ , ls
eval $(dircolors -b)
alias ls='ls --color=auto'
##list directory content
alias l='ls -1' #short
alias ll='ls -lh' #long
#something with regards to size
alias la='ls -la' #long show hidden
alias lss='ls -1sSh' #short show size sort by size
alias lsn='ls -1sh | grep -v \~' #short show size do not show file with `~' in their names
alias lssn='ls -1sSh | grep -v \~' #short show size sort by size do not show file with `~' in their names
alias lssa='ls -1sah' #short show size show hidden
alias lsssa='ls -1sSah' #short show size sort by size show hidden
#something with regards to mtime
alias lt='ls -lth' #long sort by mtime
alias lat='ls -lath' #long show hidden sort by mtime
alias lst='ls -1t' #short sort by mtime
alias lsat='ls -1at' #short show hidden sort by mtime
###_ , mtime, atime, ctime
alias lsT='echo -e "\033[1m\E[36;40mname\natime\nmtime\nctime\n\e[0m\033[0m" && stat --printf="%n\n%x\n%y\n%z\n\n"'
###_ , file name, file type, permissions, owner, group, etc.
alias lsO='echo -e "\033[1m\E[36;40mname\nfile type\noctal permissions\nhuman readable permissions\ngroup name owner\nuser name owner\nsize in bytes\n\e[0m\033[0m" && stat --printf="%n\n%F\n%a\n%A\n%G\n%U\n%s\n\n"'
###_ , find
#find suid and sgid files -- this one is placed in root's .bashrc
#alias fog='DUMP=find_suid_guid_`date +%s` && touch /tmp/$DUMP && find / -path /proc -prune -perm /6000 -a -type f -printf "%+13i %+6m %u %g %M %p\n" > /tmp/$DUMP'
#alias extr="find ../new -type f -name *.avi -exec mv \'{}\' . \;"
###_ , strace
alias strace="strace -rft"
###_ , cp
alias cp="cp -ia"
###_ , rm
alias rm="rm -rf"
###_ , sync
###_ . calculate upload bandwidth
# see http://www.markus-gattol.name/ws/debian_notes_cheat_sheets.html#limit_bandwidth_usage
source $HOME/.sec/hostnames_mapping
# calculate the available upload bandwidth in kBytes/sec and output it onto the CLI
alias iperf_calculate_upload_bandwidth="iperf --format K -c $backup_host | cut -d \",\" -f9"
# calculate the available upload bandwidth in kbits/sec and
# save it to /tmp/current_upload_bandwidth_in_kbits_per_second
[[ -r /tmp/current_upload_bandwidth_in_kbits_per_second ]] || $(iperf --reportstyle c -c $backup_host | cut -d "," -f9 > /tmp/current_upload_bandwidth_in_kbits_per_second)
# caculate 2/3 of the currently available upload bandwidth
# (and convert it to kBytes/sec) so we can sync data from our
# local machine to some remote machine without negatively
# impacting things like ordinary websurfing and the like.
# Example: if we had 66 kBytes/sec available upload bandwidth,
# rsync would be limited to 44 kBytes/sec using the --bwlimit
# switch.
[[ -r /tmp/current_upload_bandwidth_in_kbits_per_second ]] && upload_bw_limit=$(echo "($(cat /tmp/current_upload_bandwidth_in_kbits_per_second)/8000)*.66" | bc | cut -d "." -f1)
# for work on the local machine i.e. without going trough some insecure network
alias sync="rsync -aSHAXhq --delete"
alias syncv="rsync -aSHAXh --delete --progress --stats"
alias syncnv="rsync -aSHAXh --delete --progress --stats --numeric-ids"
# for stuff that goes trough an insecure WAN (Wide Area Network) e.g. the Internet
syncsec="rsync -aSHAXh --delete --progress --stats --numeric-ids --rsh=ssh"
syncseclimit="rsync -aSHAXh --delete --progress --stats --numeric-ids --rsh=ssh --bwlimit=$upload_bw_limit"
# actual commands we can use
alias syncsec="$syncsec"
alias syncwork="$syncseclimit --exclude-from $HOME/.rsync/exlude_file $HOME/0/ backup:$HOME/backup$HOME/0"
alias syncsi="$syncseclimit --exclude-from $HOME/.rsync/exlude_file $HOME/mm/si/ backup:$HOME/backup$HOME/mm/si"
alias syncmisc="$syncseclimit --exclude-from $HOME/.rsync/exlude_file $HOME/misc/ backup:$HOME/backup$HOME/misc"
alias syncaudio="$syncseclimit $HOME/mm/audio/ backup:$HOME/backup$HOME/mm/audio"
alias syncalbums="$syncseclimit $HOME/0/0/albums website:$HOME/0/0"
alias syncall="syncwork && syncmisc && syncsi && syncalbums && syncaudio"
###_ . to subnotebook
alias tosubsyncaudio="$syncsec $HOME/mm/audio/ sub:$HOME/mm/audio"
alias tosubsyncsi="$syncsec $HOME/mm/si/ sub:$HOME/mm/si"
alias tosubsyncwork="$syncsec $HOME/0/ sub:$HOME/0"
alias tosubsyncmisc="$syncsec $HOME/misc/ sub:$HOME/misc"
alias tosubsyncall="tosubsyncwork && tosubsyncmisc && tosubsyncaudio && tosubsyncsi"
###_ . to workstation
alias towkssyncaudio="$syncsec $HOME/mm/audio/ wks:$HOME/mm/audio"
alias towkssyncsi="$syncsec $HOME/mm/si/ wks:$HOME/mm/si"
alias towkssyncwork="$syncsec $HOME/0/ wks:$HOME/0"
alias towkssyncmisc="$syncsec $HOME/misc/ wks:$HOME/misc"
alias towkssyncall="towkssyncwork && towkssyncmisc && towkssyncaudio && towkssyncsi"
###_ , du
alias dus="du -sh * .* | sort -k1,1rh"
###_ , wc
# I should burn in hell for this crazy-ugly one-liner; do rewrite in Python
alias wcs="find . -maxdepth 1 -type f -exec wc -l {} \; | sort -k1,1rh | column -t | sed s%\./%%g"
###_ , mv
alias mv='mv -i'
###_ , cd
alias cdtmp='cd /tmp'
alias cdhi='cd $HOME/misc/hi/'
alias cddocs='cd /usr/share/doc'
###_ . dirstack related
alias cd='pushd >& /dev/null' # add directory at DIRSTACK[0]
# and change into it; use cd to toggle between
# the last two visited ones same as cd - does
alias db='popd >& /dev/null' # remove directory at DIRSTACK[0] and change into
# it i.e. go back in time, one by one
alias ds='dirs -v' # show DIRSTACK with array index
alias dr='pushd +1 >& /dev/null' # rotate DIRSTACK i.e.
# swap DIRSTACK[0] with DIRSTACK[n-1]
###_ . helper function
function ,, () {
cd ..
}
###_ , xd
# xd is a smart directory change utility; this function passes
# results from xd output directly to cd, thereby speeding up changing
# directories anywhere on the filesystem
function xd () {
cd $(/usr/bin/xd $*)
}
###_ , grep
alias gr='grep -rni --color'
alias pi='ls -la | grep'
alias psa='ps aux | grep'
alias pst='pstree -hAcpul'
###_ , ram
# well, I could use memstat here as well ...
# Issue `ram' in order to get a notion of the twenty most RAM (Random
# Access Memory) (residential set size also known as pages in RAM not
# the whole virtual memory as is reflected by vsz) demanding
# processes.
alias ram_helper_0='ps -eo pmem,rss:8,vsz:8,user:14,comm:20'
alias ram_helper_1='ram_helper_0 | head -n1'
alias ram_helper_2='ram_helper_0 | sort -k 2,2rbn -k 3,3rbn | head -n20'
alias ram='ram_helper_1 && ram_helper_2'
###_ , cpu
# twenty most CPU claiming processes.
alias cpu_helper_0='ps -eo pcpu:4,cputime:9,cp:4,user:14,comm:20'
alias cpu_helper_1='cpu_helper_0 | head -n1'
alias cpu_helper_2='cpu_helper_0 | sort -k 1b,1rbn | head -n20'
alias cpu='cpu_helper_1 && cpu_helper_2'
###_ . getting up-to-date code
source /usr/local/bin/getting_up_to_date_code
###_ . start a program resp. trigger some action
###_ , git
# FIXME: switch from uws to uwp again once a remote backup exists again
# alias cus='cd $HOME/0/0 && git cwh -m "reorganized http://www.markus-gattol.name/pim/lof.6.html" && git push && uwp'
alias cus='cd $HOME/0/0 && git cwh -m "reorganized http://www.markus-gattol.name/pim/lof.6.html" && git push && uws'
###_ , aptitude
alias aps='aptitude search'
###_ , apt-get
alias acs='apt-cache search'
alias acsn='apt-cache search --names-only'
alias acsh='apt-cache show'
###_ , apt-file
alias afl='apt-file list'
alias afs='apt-file search'
###_ , dpkg and dlocate
alias dpl='dpkg -l'
alias dps='dpkg -s'
alias dpp='dpkg -p'
alias dll='dlocate -l'
###_ , imagemagick and friends
alias tst='scrot -b -d 3 -q 85 -t 25 /tmp/screenshot_$(date +%s).png'
alias tsw='scrot -b -d 3 -q 85 -t 25 $HOME/0/0/misc/mm/si/content/$(date +%s).png'
###_ . bins
export BINS_LOCAL=$HOME/mm/si/albums_staging_area
alias bins_update_albums="bins -f $BINS_LOCAL/binsrc -t $BINS_LOCAL/templates.joi $BINS_LOCAL/local $HOME/0/0/albums"
alias bins_cleanup_albums="bins_cleanupgallery $BINS_LOCAL/local $HOME/0/0/albums"
alias crat="cp $BINS_LOCAL/template_album.xml ./album.xml"
alias ual="bins_update_albums && bins_cleanup_albums"
###_ , unison
alias ufs='unison full_sync.prf'
alias ups='unison part_sync.prf'
#alias uws='unison ws_pim_blog.prf'
alias uws='$syncsec $HOME/mm/si/photos/ rh0:$HOME/mm/si/photos && syncsec $HOME/0/0/ rh0:$HOME/0/0'
alias ush='unison stage_hn.prf'
alias uwp='uws && ups'
###_ , context
export CONTEXT_PROJECTS=$HOME/0/context/projects
alias cdcontext_projects='cd $CONTEXT_PROJECTS'
alias cmp='$HOME/misc/software/context/scripts/makeproject.pl'
###_ , openvz
alias nas='dig {yahoo,google,microsoft}.com NS | grep ^ns1 | cut -f6 | xargs -I {} echo -n " --nameserver {}"'
###_ , debian
###_ . dlocate
alias dlc='dlocate -lsconf'
###_ , misc
alias auml='argouml >& /dev/null &'
alias ban='cd /tmp && banshee >& /dev/null &'
alias bani='banshee --query-{artist,title} >& `tty`'
alias bann='banshee --next'
alias ems='emacs-snapshot-gtk --debug-init &'
alias epi='epiphany >& /dev/null &'
alias ht='htop'
alias ia='iceape >& /dev/null &'
alias iw='iceweasel >& /dev/null &'
alias icd='icedove >& /dev/null &'
alias evo='evolution >& /dev/null &'
alias mle='kill `cat ~/.mldonkey/mlnet.pid`'
alias mls='gpg --refresh-keys; mlnet &'
alias ow='qtwengophone >& /dev/null &'
alias pig='pidgin >& /dev/null &'
alias pin='ping -vc 3 google.com'
alias pwg='pwgen -sncB 55 1'
alias san='cd /usr/local/bin/sancho/sancho-0.9.4-59-linux-gtk/ && ./sancho >& /dev/null &'
alias sk='skype >& /dev/null &'
alias toteml='ls -1t | head -n33 | xargs totem >& /dev/null &'
alias vlcl='ls -1t | head -n13 | xargs vlc >& /dev/null &'
alias wr='workrave &'
export JAVA_HOME="/usr/lib/jvm/java-6-sun/jre"
fi
###_. xterm
case $TERM in
xterm*)
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
;;
*)
;;
esac
fi
###_ emacs local variables
# Local Variables:
# mode: conf
# allout-layout: (0 : 0)
# End:
|