Question: Share your bash tips?
Posted by Steve on Fri 29 Apr 2005 at 02:27
GNU Bash is one of the most common shells in the Linux world, it's also the default shell on Debian systems. People who use it frequently and browse the manual usually learn something new, here I'm going to share two tips I cannot live without. What are yours?
AutocompletionSwitching to the previous directoryautocompletion is literally what it's name might suggest, you start to type something and it's completed for you.
This is usually enabled for simple things such as file and directory names, and by default it will be activated by the "TAB" key.
For example if you wish to look at the system's password file you might wish to run:
less /etc/passwdTo save keystrokes you can actually type:
lesTAB /eTAB/passTABAs you proceed to type the words pressing TAB will automatically complete things for you.
In the Debian bash package there is a file installed called /etc/bash_completion, this adds a lot more useful behaviours to bash including:
- Auto completion of hostnames, for SSH
- Auto completion of Debian specific utilities
To cause your shell to use it run the following command, then login again:
echo '. /etc/bash_completion' >> ~/.bashrcThis will now give you a lot more completions, most usefully I find the following :
apt-get upgTABThis becomes the familiar "apt-get upgrade", other apt-get, and dpkg commands suddenly understand completion too, so instead of typing "dpkg --search" you can cut this down to "dpkg --seaTAB".
To be honest I don't know the full extent of the completion offered as some of the code in the /etc/bash_completion file is pretty hard to follow, but I know it saves me time.
Why not have a look yourself?
Argument ReuseAssuming that you work in the shell for moving around, and working on files then it's often common to switch directories a lot.
One thing that I often find I want to do is move to a long directory path, do something, then go elsewhere. Frequently I wish to go back to the long directory and do something else i've forgotten.
Even with directory completion it's often a pain to have to retype out the previous directory.
Consider the following example:
cd /home/www/www.debian-administration.org/htdocs/ # do something cd /home/www/www.steve.org.uk/htdocs # do something else cd /home/www/www.debian-administration.org/htdocs/ # Ooops forgot something.Here we want to move back to a directory we just left, and rather than typing out the full path we can take advantage of the fact that bash remembers our previous directory and sets up an alias for it: -.
To change to the previous directory just run:
cd -Here's an example showing it in use:
# Change to a long directory. steve@skx:~$ cd /home/www/www.debian-administration.org/htdocs steve@skx:/home/www/www.debian-administration.org/htdocs$ # # Do something .. # # Go to /tmp steve@skx:/home/www/www.debian-administration.org/htdocs$ cd /tmp # # Realise we wanna go back # steve@skx:/tmp$ cd - /home/www/www.debian-administration.org/htdocsOther solutions to this problem exist, including pushd, and popd, but I admit I find the simplicity of the "cd -" command much more useful.
Your tipsIf you're used to running commands from the shell a lot one thing that's incredibly useful is the ability to reuse argumetns from previous commands.
Say you wished to run the following commands:
cp /etc/passwd my-password-copy emacs my-password-copyHere we copy a file somewhere, then attempt to edit it.
Instead of typing out the filename we can take advantage of another of bash's shortcuts - it remembers the last argument to the previous command, and allows you to insert it into the current shell with "Esc .".
Run the following to see how it works:
cat /etc/passwd cp ESC. .(That is press Esc, then press '.' afterwards' - the last argument to the previous command is inserted into the command line).
What features of the bash shell do you find the most useful? Do you have any interesting tips to share?
On a blank command line, hit control-r to do a "reverse incremental search". As you type, bash will search your command history and auto-fill the most recent command that matches the pattern you type in. Hit control-r again to go back to the next most recent match. I use this one all the time. :)
--Nato
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
reverse-search-history (C-r) Search backward starting at the current line and moving ‘up’ through the history as necessary. This is an incremental search. forward-search-history (C-s) Search forward starting at the current line and moving ‘down’ through the history as necessary. This is an incremental search.
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
If you press ^s while in a screen session, your session will 'freeze'.
[ Parent | Reply to this comment ]
stty -ixon
[ Parent | Reply to this comment ]
$ stty -aAnd put these lines to your ~/.profile
stty stop '^-'Those are not "Control", but char (^) followed by char(-). They disable those terminal settings.
stty start '^-'
Jari Aalto
[ Parent | Reply to this comment ]
Works as a nice honeypot too, if you have the time to discreetly disable your Scroll Lock key. ;)
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
They are mainly to find things into long outputs from certain commands.
My conventions is repeating the last letter of the long output command. The examples will clarify things inmediatly
-To see something coming into ls output: lss
alias lss='ls -lrt | grep $1'
-To check a process is running in a box with a heavy load: pss
alias pss='ps -ef | grep $1'
-To check the existence of an environment variable: envv
alias envv='env | grep $1'
-To see if a package or packages are installed in the system: dpkgg
alias dpkgg='dpkg -l | grep $1'
etc.
This may admit lots of modifications to make these aliases fit better your needs, like, including more arguments ( $2, $3, etc), or piping more commands to suit some long operation that one perform frequently, etc
So, to use them you simply type
lss something
pss process, or process number, or process parent or any data you now it comes in the process line output
envv variable
etc.
Hope this helps.
Fernando
[ Parent | Reply to this comment ]
If you want to do something more complicated, look at bash functions.
Note that the examples will still work (and are still very useful), the '$1' business is just a NOP.
[ Parent | Reply to this comment ]
du -kx ./ | sort -n
Isn't a really bash tip, but it help me in my work ;)
my 2 cents
Marco Bertorello <marco(at)bertorello(dot)ns0(dot).it
[ Parent | Reply to this comment ]
usage () {
echo "usage: ${0##*/} "
exit 1
}
The use of ${0##*/} prevents one from having to shellout to basename(1).
[ Parent | Reply to this comment ]
That's not a Bashism, it's standard POSIX shell.
The only non-POSIX shells that seem to be in wide use are csh and tcsh (which aren't descended from Bourne and Korn anyway), and Solaris sh.
Sadly, Solaris sh is a big reason for people continuing to use extrememly crude constructions in their "portable" shell scripts.
--Branden Robinson
[ Parent | Reply to this comment ]
--asg
[ Parent | Reply to this comment ]
sam@io:/usr/a/very/long/and/annoying/to/type/path$ pushd /etc/apache
/etc/apache /usr/a/very/long/and/annoying/to/type/path
sam@io:/etc/apache$ cd ssl
#Some more stuff here
sam@io:/etc/apache/ssl$ popd
/usr/a/very/long/and/annoying/to/type/path
sam@io:/usr/a/very/long/and/annoying/to/type/path$
^a and ^e (beginning of line and end of line) and ^w (delete word) are incredibly useful too.
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Good example.
Of all the keyboard shortcuts the only ones I seem to use are:
^a Beginning of the line. ^r Search through history, backwards. ^k Kill to the end of the line. ^u Kill to the beginning of the line.
I never seem to have to move to the end of the line!
Steve
-- Steve.org.uk
[ Parent | Reply to this comment ]
[ Send Message | View redbeard's Scratchpad | View Weblogs ]
I use the following keyboard shortcuts frequently (in addition to some of the other mentioned shortcuts)
Meta-f Forward one word Meta-b Backward one word Meta-d Delete forward one word
Of course, meta translates to Alt on PC keyboards (or the Esc, if you don't like pressing two keys at once :)
BTW, I just found the site (thanks to the Debian Weekly News). From what I've seen, I'll be using it a lot.
Michael
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
Ubuntu and Fedora (those I have used recently) do this out of the box, but not debian.
Regards,
Daniel
[ Parent | Reply to this comment ]
[ Send Message | View redbeard's Scratchpad | View Weblogs ]
From /etc/inputrc:
# mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving "\e[5C": forward-word "\e[5D": backward-word "\e\e[C": forward-word "\e\e[D": backward-word
I can confirm that it works.
[ Parent | Reply to this comment ]
keith@fugit:/tmp$ ls -la foo
-rw-r--r-- 1 keith keith 20 Apr 29 13:21 foo
keith@fugit:/tmp$ cat $_
This is some text.
keith@fugit:/tmp$
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
I previously used that a lot, but then I discovered 'Esc .' inserted it directly into the command line.
For me it's easier to remember to do that, as it allows editting when necessary.
Steve
-- Steve.org.uk
[ Parent | Reply to this comment ]
shabbl:~# echo this > that
shabbl:~# cat !$
cat that
this
[ Parent | Reply to this comment ]
If you can remember the number of the command in your bash_history, `!` will repeat that particular command in your history. i.e:
!4
Will repeat command number 4 in your history.
Typing `!` will repeat the last instance of that command in history. i.e if, the last 'cat' command issued was `cat /tmp/file`, typing this:
!cat
Will repeat the `cat /tmp/file` command again
Typing `!cat:p` will simply output the full command executed, and not actually execute it. This might be useful if you executed a large grep|awk|sort type thing and wanted to copy and paste a chunk of it into your next grep|awk|sort.
[ Parent | Reply to this comment ]
~# cat /etc/passwd
(look at it)
want to edit it ?
~# vi !-1:1
vi /etc/passwd
ESC "." is much more useful in this case, but sometimes you are glad to get just an argument of a previous command, not just the last one or the full command. E.g, using the third argument from the command before the last one :
~# cmd !-2:3
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
bilke@hydrogen:~$ ls /var account cache local log mail run tmp yp backups lib lock lost+found opt spool www bilke@hydrogen:~$ ^var^home ls /home bilke export ftp igor joejoe lost+found mirjam pivo samba bilke@hydrogen:~$best regards, bilke
[ Parent | Reply to this comment ]
It's possible that this is only (or mostly) a problem with old, stable (Woody), which, yes, I still use on a number of machines where continuing to just work is more important than newer versions of things. All those servers in closets that might or might not even have monitors if an upgrade should go awry...
Anyway, with the fancy scripted completion turned on, I find that tab completion's leading side effect works less well, or sometimes not at all. That's hitting tab (twice) to see what all is in a directory. Very handy for context when groping for an obscure config file you haven't had to look at in a couple years, let me tell you. The failures seem to be erratic, aside from obvious things like only getting directories when the command is cd and so forth. On the whole the smarter tab completion seems well worth it, but there may be a few disruptions if you're already accustomed to using tab completion. - MartinManey
[ Parent | Reply to this comment ]
"\e[Z": complete-filename
Therefore, TAB uses bash_completion and SHIFT+TAB performs a filename completion.
[ Parent | Reply to this comment ]
$ cd M[Esc-=]
Mail/ Mp3Kult/ Music/
$ cd Mu[Esc-Esc] => cd Music
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
That only clears the visible part of the terminal. You can still shift-PGUP to see what was there.
If you want to clear the terminal buffer so that they cannot shift-PGUP to see what was done do:
echo -en \\0033c
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
shopt -s extglob
Then I can for example cd into a directory full of mp3s, and find any file that isnt an mp3..
ls -lh !(*.mp3)
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
That's very handy, and much simpler than my approach for the same gob:
ls -1 | grep -v \.mp3$
Although that works well for finding directories, with the following alias:
alias lsd='ls -l | grep ^d'
Steve
-- Steve.org.uk
[ Parent | Reply to this comment ]
ls -ld */
Nosklo
[ Parent | Reply to this comment ]
To change to the previous directory just run:
cd -
Along the same lines, you can refer to the previous PWD as "~-" for example:
cd /etc/ ; cd /tmp ; cp ~-/passwd . ; will copy /etc/passwd to /tmp/passwd
[ Parent | Reply to this comment ]
Well, I,m not sure if this one is really necessary - except in cases, when you are forced to write sensitive data as an option in a command like passwords *shudder* - but it may be good to know, that there are environment variables, with which you can control the behaviour of saving commands to the history file: one way is to set
$ HISTCONTROL=ignorespace
Afterwards you can type commands beginning with a space, that will not show up in your history file.
$ ll
.... lot of files
$ _ls -a
.... again lot of files
[UP]
$ ll
Many more things are possible. Just "man bash" and "/HISTCONTROL".
Best regards and thanks for hints of many I didn't know ;-))
[ Parent | Reply to this comment ]
(BTW I am comparing to bash 2.05; maybe bash 3 is better.)
Will
[ Parent | Reply to this comment ]
/usr/src/linux-2.6.11.5$ ls -1 */*.c | tail security/dummy.c security/root_plug.c security/root_plug.mod.c security/seclvl.c security/security.c sound/last.c sound/sound_core.c sound/sound_firmware.c usr/gen_init_cpio.c /usr/src/linux-2.6.11.5$ echo $BASH_VERSION 3.00.16(1)-release /usr/src/linux-2.6.11.5$ cat /etc/debian_version testing/unstable
[ Parent | Reply to this comment ]
And another one a use very frequently is brace expansion. Ex: "echo a{1,2,3}" prints "a1 a2 a3" on the screen. Very useful for: "mv /a/very/long/pathname{,.OLD}"
[ Parent | Reply to this comment ]
[...]
To cause your shell to use it run the following command, then login again:
echo '. /etc/bash_completion' >> ~/.bashrc
[...]
Do you actually have a reason to login again after editing your .bashrc?
You don't have to, just use the same command as you just added to your .bashrc, but now with your just edited .bashrc.
Just run:
. .bashrc
And .bashrc is executed in your current shell instead of in a subshell.
my 2 cents,
Nok
[ Parent | Reply to this comment ]
. /etc/bash_completion
It's possible that your .bashrc might contain something you only want done once, when your shell starts up.
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
'[\u@\h:\w]$ '. This makes it much easier to copy/paste user@host:/path to other shell windows.
In order to keep all bash configuration in sync on many hosts my .bashrc sources a couple of files that are kept in cvs. One of those files is a 'cvs update' :-)
[ Parent | Reply to this comment ]
# If this is an xterm set the title to user@host:dir
case $TERM in
xterm*)
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
;;
*)
;;
esac
This way, the title of the term will be updated when you change host, dir or user.
Also, if you use ssh/scp a lot, bash_completion complete hosts and remote filenames by default if you use ssh-agent:
scp local_file root@hTAB/remTAB/paTAB
would then expand as :
scp local_file root@host:/remote/path/
you'll need of course a fast and low-latency connection for it to be useful. Waiting several seconds after typing TAB becomes annoying with time ;)
[ Parent | Reply to this comment ]
set completion-ignore-case On #tab complete without needing to get the case right
set show-all-if-ambiguous On #show list on first tab, no need to hit tab again
set visible-stats On # not sure what this one does...
set mark-symlinked-directories On # handy
Now, some functions from my .bashrc:
These are just nice shortcuts for searching for a string in filenames under the current directory
findme() { find -iname "*$@*" -or -iname ".*$@*"; }
findmewhole() { find -iwholename "*$@*" -or -iwholename ".*$@*"; }
This takes a string and provides a top-like display of matching lines from ps. The 'grep -v grep' bit is because otherwise the 'grep -i $@' line matches itself!
running() { watch -n1 "ps aux | grep -i $@ | grep -v grep"; }
iain
[ Parent | Reply to this comment ]
It doesn't look like there are too many of us 'vi' mode users based on the responses I saw.
But, if you do use the VI edit mode (set -o vi) be aware that you cannot use the 'ESC-...' stuff mentioned here for EMACS mode.
For example, the 'ESC-.' that fills in the last arg from the prior command for EMACS mode, will repeat the last edit if in VI mode. So:
cp[ESC-.]
produces:
cpcp
Which is probably not too useful ;)
Bob
[ Parent | Reply to this comment ]
emacs mode works fine though.
The strange thing is that I use vim for all my text editing needs...
iain
[ Parent | Reply to this comment ]
Ok, now that the troll part is done, I'd say that vi mode is for me actually unusable in the CLI, even though I'm a lot more acustomed to vim than to emacs.
but sometimes I find myself typing ESC afer a command, then :x to quit the shell ;)
[ Parent | Reply to this comment ]
> be confused with a shell or an OS ? ;)
Yeah, vim isn't as useful a shell or OS as emacs is.
:p
iain
[ Parent | Reply to this comment ]
fcThe command line is executed immedietly after I quit vi.
You can use any editor you like, but it should not fork itself into a new process. To test this, run your editor from the command line, and if your shell prompt returns before you quit the editor window, you can't use it for things like this.
[ Parent | Reply to this comment ]
[ Send Message | View dkg's Scratchpad | View Weblogs ]
do remember that whatever you type is going to be executed when the editor closes, though! that can sometimes be a surprise.
[ Parent | Reply to this comment ]
gcc -O99 -march=formula1 and-some-more-things
and you want to strip away the -O99 option remembering what was there:
gcc $(# -O99 ) -march=formula1 and-some-more-things
[ Parent | Reply to this comment ]
Especially for commenting on arguments, which must be in one line, except if the line end is escaped, but then again technically to the shell it is still one line.
My disappointment was very big, when it didn't work.
I used bash 3.2.17(1)-release (i386-apple-darwin9.0) on MacOSX 10.5.5 and none of the following worked.
I tried the brackets without spaces, with only a space after the opening bracket, and then a space after/before both brackets.
ls -l $(#display-as-list) -a $(#all) -H $(#human readable)
ls -l $( #display-as-list) -a $( #all) -H $( #human readable)
ls -l $( #display-as-list ) -a $( #all ) -H $( #human readable )
[ Parent | Reply to this comment ]
It's just like the op said. $(# text ).
Number sign, space, text, space.
[ Parent | Reply to this comment ]
Example:
# Make a backup of xterm.c.
$ cp xterm.c{,~}
# Patch it.
$ patch -p0 </tmp/xterm_patch.diff
# Get warned about offsets, fuzz, and rejected hunks.
# Use vim to hand-merge rejected hunks.
$ vim -O xterm.c{,.rej}
# Create new diff that applies cleanly.
$ diff -u xterm.c{~,} >/tmp/good_xterm_patch.diff
I have found that simple use of brace-expansion like this saves me a lot of typing. Even tab-completion can get tedious if you're operating on things deep within a directory structure, and for whatever reason don't want to cd in there. (Think xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c.)
--Branden Robinson
[ Parent | Reply to this comment ]
in vim:
:r! echo ServerAlias {www.,}domain{-,}part.{com,biz,net,info,me,name,{org,co}.uk}
[ Parent | Reply to this comment ]
~$ vim --version | grep compiled VIM - Vi IMproved 6.3 (2004 June 7, compiled Sep 1 2005 16:51:12) ~$ echo $BASH_VERSION 3.00.16(1)-release
[ Parent | Reply to this comment ]
VIM - Vi IMproved 6.3 (2004 June 7, compiled Apr 24 2005 15:44:11)
bash version: 2.05b.0(1)-release
What about something like:
:r! /bin/bash -c 'echo {www.,}foo{-,}bar.{com,net}'
And take it from there? And if that doesn't work, try it at the command line (where it should definitely work), and if not, find out what's wrong with bash's brace expansion.
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
CTRL + SHIFT + _ UNDO
[ Parent | Reply to this comment ]
for fileordir in `ls /some/dir`;
do
somecommand $fileordir;
someothercommand $fileordir;
done
Use ctrl+z to stop a running process and bg to start in in the background.
Use ctrl+u to cut left, ctrl+k to cut right, and ctrl+y to insert the cutted text/command.
some nice variables:
$RANDOM contains a random number. Really useful for creating tempfiles in bash scripts
$? contains exit status of last process executed.
The while loop is nice if you need to check the status of something and do something if the status change.
Test commands list -z $SOMEVAR to see if $SOMEVAR is an empty string or undefined.
--Simon Østengaard
[ Parent | Reply to this comment ]
Ctrl-a -> go to the start of command line
Ctrl-e -> go to the end of command line
Ctrl-p -> previous command in history
Ctrl-n -> next command in history
Ctrl-f -> next character in command line
Ctrl-b -> previous character in command line
Ctrl-r -> reverse search in history file
Ctrl-d -> delete current character
Ctrl-k -> delete from the prompt to the end of command line
Ctrl-_ -> undo (yes, but limited)
Meta-< -> go to beginning of history file
Meta-> -> go to end of history file
Meta-f -> go to next word in command line
Meta-b -> go to previous word in command line
Meta-d -> delete next word in command line (from the actual position of the prompt)
and that's all i can remember. There is a lot more, you can find that in books about bash (oreilly i think).
Enjoy! ;-)
[ Parent | Reply to this comment ]
Handy little trick for vim and bash.
To open the last file you edited, just alias:
alias lvim="vim -c \"normal '0\""
[ Parent | Reply to this comment ]
ctrl-] character
To seach backward
esc ctrl-] character
Anyone know how to repeat the search..
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
I wanted BASH to keep a list of all the directories I visited so that
I could jump to any visited directory by providing a few characters from its name or even go back and forth through the list of visited directories.
Now, BASH already provides a few things that I could use:
1) I could use CDPATH environment variable
If I put in my .bashrc someting like
export CDPATH="/path/dir:/path/dir2"
Next time I do 'cd blah' BASH will check /path/dir and /path/dir2 to see if any of their sudirectories is 'blah'. But every time I create a new directory that has subdirectories of my interest I need to update CDPATH and restart my terminal. Not to mention that NOT all subdirectories will be of my interest so if I have a few 'bin' sudirectories, and I do 'cd bin' BASH will go to the first one found. CDPATH is useful but it's quite annoying if it sends you to the wrong directory.
2)'cd -' can take you to the previously visited directory. But I want more than that. I want to be able to go through the entire history of visited directories.
*) If you know of any other method that pertains to my problem, let me know.
MY SOLUTION
Well, it took me some time but I figured out how to do it.
First I needed to use BASH lists (BASH Arrays).
Arrays are declared like this:
arr=(zero one two three four)
echo ${arr[0]} # gives zero
echo ${arr[@]} # lists entire array as one string
echo ${#arr} # gives the number of elements in an array
Of course, you can combine it with a different input.
arr=(`ls`) # grabs the output of 'ls' into an array
arr=(`cat myfile`) # grabs the file into an array
# every line from the file is assigned to one array element
Little tangent on delimiters
-----------------------------
Strings from `cat myfile` are delimited based on \n (new line)
that is why our 'arr' takes one whole line per element.
If you want your strings to be delimited in some other way,
use IFS="/", where '/' will become a delimiter
If you put in your .bashrc
IFS="
"
then the newline \n will become a delimiter again
(This business with IFS could be a pain.)
-----------------------------
I also needed to do some arithmetic in here, for which I used the
double parentheses expression: (( math ))
m="1" # always use "", even for numbers
((m++)) #increments m
((m--)) #decrements m
((n=m+3))
echo "m=$m n=$n" #gives m=1 n=4
Before the code: How to Use it
-------------------------------
This is how you can use my code below.
You need to put it in .bashrc and restart the terminal.
Suppose you have some directories:
MyDocuments, Test, CodeOfMyProject and its subdir "Two words".
cd MyDocuments # now the history has remembered MyDocuments
cd # You go back to ~
cd Test # Test is also remembered
# And so on for every directory you visit
......
dir save # saves the history into .dir_history in your home directory
# Now every time you open a terminal this history will be loaded
# so you don't have to type it again
cd Two # Sends you to CodeOfMyProject/Two words
cd .. # Sends you to CodeOfMyProject
cd # Sends you home ~
cd - # Sends you backwards in history to CodeOfMyProject
cd - # Sends you backwards again to CodeOfMyProject/Two words
cd + # Sends you forwards in history
cd T # Sends you to Test
# NOTE: all forward history is now deleted
think of it the way web browsers behave!
dir load # loads the history (if you don't want it to load automatically)
cd My # Sends you to MyDocuments
ANOTHER NOTE: If you want to use a regular 'cd' command type \cd
The same thing applies to \dir
c # The alias 'c' will allow you to choose a dir from a list
dir choose # Does the same thing as 'c'
dir clear # clears history
THIRD NOTE: I made the search case sensitive. You can make it insensitive by adding an -i option in 'grep -E $regexp'
FINAL NOTE: If you have too many directories in history the search might become slow. I guess I will add some upper limit on how many directories you can have in history. Also, the history will NOT save itself. You have to do 'dir save'.
You can also put 'dir save' in .bash_logout
NOW THE CODE:
--------------
# put this in your .bashrc to see how it works
# I tried to make useful comments
# but you are welcome to delete them
# -----SECTION: Moving through directories --------
# declaring variables
export dirarr dircnt dirarr_fhist dircnt_fhist
# dirarr is where I keep visited directories (no duplicates)
# dircnt is its length, ${#arr} was giving me some trouble
# dirarr_fhist a an array of forward history
if [ -z $dircnt ]
then dircnt="1"
dirarr=("`pwd`")
fi
if [ -z $dircnt_fhist ]
then
dircnt_fhist="0"
dirarr_fhist=
fi
# some aliases that will save us the trouble of too much typing
alias cd='push'
alias p='push'
alias o='pop'
alias c='choose'
alias dir='dir_utility'
# loads and saves history,
# lists and chooses directories
dir_utility() {
case "$@" in
s|sa|sav|save)
save_dirhist
;;
lo|loa|load)
load_dirhist
;;
l|li|lis|list)
dirl
;;
c|ch|cho|choo|choos|choose)
choose
;;
*)
\dir "$@"
;;
esac
}
# Used by push() function (see below)
pop() {
popd "$@" > /dev/null
}
# This is where 'cd' command is parsed
push(){
case "$@" in
"")
pushd ~ > /dev/null
;;
"-") # going backward in history
prevdir="`pwd`"
popd > /dev/null
dirarr_fhist[$dircnt_fhist]=$prevdir
((dircnt_fhist++))
;;
"+") # going forwards in history
if [ "$dircnt_fhist" == "0" ]
then
echo "Forward list empty"
return 1
fi
((dircnt_fhist--))
dir=${dirarr_fhist[$dircnt_fhist]}
if [ ! -z $dir ]
then
pushd "$dir" > /dev/null
fi
;;
*) # parsing cd
if [ -a "$@" ]
then
pushd "$@" > /dev/null
clear_fhist
curdir="`pwd`"
for ((i=0; $i < $dircnt; i++)); do
if [ "${dirarr[$i]}" == "$curdir" ] ; then
return
fi
done
dirarr[$dircnt]="$curdir"
dircnt=$((++dircnt))
else
cdpartial "$@"
fi
;;
esac
export dirarr dircnt
export dirarr_fhist dircnt_fhist
}
# list history
dirl() {
for ((i=0; $i < $dircnt; i++))
do
if [ "$1" == "-n" ] ; then
echo -e "${dirarr[$i]}\n"
else
echo "${dirarr[$i]}"
fi
done
}
# choose a directory from history
choose() {
if [ ! -z "$1" ] ; then
if (( $1 >= 1 && $1 <= $dircnt )) ; then
num=$1
((num--))
pushd "${dirarr[$num]}" > /dev/null
clear_fhist
return 0
fi
fi
# make IFS take \n as a separator
IFS="
"
PS3="jump to directory # "
select dir_ans in `dirl -n`
do
if [ ! -z $dir_ans ]
then
pushd "$dir_ans" > /dev/null
clear_fhist
break
fi
done
}
# save history
save_dirhist() {
dirl | sort > ~/.dirhistory
}
#load history
load_dirhist() {
# this should go to .bash_login
if [ -r ~/.dirhistory ]; then
# TODO Test validity of directories
#cat .dirhistory | while read line
#do
# echo $line
#done
IFS="
"
dirarr=(`cat ~/.dirhistory`)
#dircnt=${#dirarr} #NOT WORKING
dircnt="`cat ~/.dirhistory|wc -l`"
fi
}
# find a directory in History based on a partial string
cdpartial() {
if [ $dircnt -eq 0 ]
then return
fi
for ((i=0; $i < $dircnt; i++))
do
regexp="$@[^/]*$"
if [ `echo ${dirarr[$i]}| grep -E $regexp | wc -l` -gt 0 ]
then
\cd ${dirarr[$i]}
clear_fhist
return
fi
done
echo "$@: directory not found"
}
# clears forward history
clear_fhist() {
export dirarr_fhist=
export dircnt_fhist="0"
}
# clears history
clear_hist() {
export dirarr=
export dircnt="0"
}
# loads history in .bashrc
load_dirhist
# -----END SECTION: Moving through directories --------
# P.S. I'm using the newest BASH - 3.x
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
# apt-aliases
alias apt-search="apt-cache search"
alias apt-policy="apt-cache policy"
alias apt-install="apt-get install"
alias apt-remove="apt-get remove"
alias apt-clean="apt-get clean"
alias apt-update="apt-get update"
alias apt-upgrade="apt-get upgrade"
this has proven to lower the confusion for novices i introduced to debian administration, when i comes to package management.
hope you find it helpful, too.
[ Parent | Reply to this comment ]
--
"It's Not Magic, It's Work"
Adam
[ Parent | Reply to this comment ]
~$ some-big-heavy-long-running-cmd
CTRL+Z
~$ do-something-else
....
~$ fg
results of some-big-heavy-long-running-cmd
[ Parent | Reply to this comment ]
and
grep -Hirn string *
[ Parent | Reply to this comment ]