Softpanorama
(slightly skeptical) Open Source Software Educational Society

May the source be with you, but remember the KISS principle ;-)

Google   


Advanced Unix Filesystem Navigation

News Recommended Links cdpath ln Command completion   History reuse
pushd/popd/dirs Norton Change Directory
(NCD) clones
OFM Dotfiles Unix shells history Humor Etc

There are a surprising number of wrong ways to get from one point of Unix filesystem directory to another and the only one right way (to use orthodox file manager style like mc ;-). Still we do not always have OFM installed by default on most UNIX systems.

If you do not have mc or similar OFM you've ever been tempted to write a dozen or more aliases to move among different directories (such aliases are essentially a collection of bookmarks). You can also imitate favorites using symlinks from you home directory. 

cd - is also useful despite its obvious limitations (Entering cd - return you to the last directory we used; entering it a second time "toggles" us back again). This might be more or less convenient way to work between two directories but it does not scale to three directory though.  BTW another useful shortcut is  cd ~  or simply cd . It returns you to your home directory ( "~" is a shortcut for home directory like in  . ~/.profile).  You can manipulate this point of return by changing variable $HOME but this is a stretch...

Designed of Unix system and developers of first shells understood that something is wrong here but never were able to figure out what actually is wrong. Only John Socha was able to find a better way by creating his famous Norton Commander functionality of which was later generalized in the concept of orthodox file managers. Part of this functionality are also available in Norton Change Directory (NCD) clones

Naive and inconsistent attempts to fix the problem can be seen in various Unix command. The first is  pushd/popd/dirs  troika introduced in C shell. The idea was brilliant like many innovations intoduced by Bill Joe in c-shell, but its implementation is almost useless as the data structure used (stack) is not very conductive to the task and there is no obvious way to imitate favorites with this troika.  Another negative factor is that instead of extending cd command in pretty obvious way three new were introduced. Later in Korn shell a limited version on return to prev directory was implemented as cd -. 

The second command that was enhanced to simplify navigation in Unix was "cd with replacement":

cd [new] [old]

This is ksh only trick, but this is very nice trick if you get used to it.  This form of "cd" takes two arguments. The first argument is a string to insert in the previous cd [whatever] command, and the second argument is the string we want it to replace.

For example, if we'd last typed

cd /spam/DB/etc

Then we could jump over to  /spam/Logs/etc by entering

cd DB Logs

If directory is not given, the value of the HOME shell variable is used.

But the most successful (albeit very limited) attempt to simplify navigation in Unix was the introduction of the variable CDPATH.  If the shell variable CDPATH exists, it is used as a search path. If directory begins with a slash or dot, CDPATH is not used.

As we mentioned before in cd command if  the directory is `-', it is equivalent to $OLDPWD.

The return status is zero if the directory is successfully changed, non-zero otherwise.

 

CDPATH

The shell variable CDPATH is a useful but underutilized feature of ksh and bash. This variable is similar to PATH and provides is a list of paths that the "cd" command will search for whatever subdirectory you provide as its argument. for example you can have:

export CDPATH="/usr/local/"

you can "cd" to any of the subdirectories in the /usr/local below the directories in this list by typing cd [subdirectory] without typing the entire path - regardless of your current directory.

What happens if we have a local directory with the same name as one of the others defined in $CDPATH? What I have found that in ksh and bash:

  1. If you put a trailing slash "/" on each path in $CDPATH, you'll "cd" to the local directory.
  2. If you don't put a trailing slash on each pathname, you'll "cd" to the first pathname in the $CDPATH list that contains a matching subdirectory.  In this case you need to cd to local directory using cd ./name. Or you  can use directory completion for any local directory which actually is not a bad idea...

Still it's a very good idea to use those trailing slashes if you want to change to local subdirectories.

Also note that CDPATH concept works for partial pathnames too. If you have a /usr/local/lib/X11 directory, cd lib/X11 is a shortcut to this location for the given example.


Pathname Completion

The shells ksh and bash both provide another useful feature, which, among other things, can help us get across directories. These shells have the ability to "guess" the directory name you're typing after you've typed the first few characters. Here's an example. In ksh, if we enter

cd /usr/loc

and stop there, before entering the text, and then type the escape key twice, the shell completes the pathname for us:

cd /usr/local/

and the cursor waits at the end of the line for us to add the next part of the path. After some practice, pathname and filename completion can save a lot of keystrokes!

What happens if there are two or more directories that match the part we've typed? For instance, if we enter

cd /usr/lo

and type the escape key twice, no completion is performed. This will happen whenever the text we've entered matches two or more possible directories in the given path.

In this case, we can type the sequence [esc][=] instead. The following text is then displayed:

$ cd /usr/lo      
1) local/
2) lost+found/
$ cd /usr/lo

what's happened is that a list of the possible selections that match the text is displayed. The unfinished command is reprinted, and the cursor waits for us to add some additional characters so we can complete enough of the pathname for completion to work properly.

bash needs no equivalent for the [esc][=] sequence, since it will automatically generate a list of possible entries if more than one exists:

bash$ cd /home/j
john jrl jsiler
bash$ cd /home/j

For more information about pathname completion see Command completion
 


Notes:
  • Those pages are written by people for whom English is not a native language. Some amount of grammar and spelling errors should be expected.
  • This is a Spartan WHYFF (We Help You For Free) site. It cannot replace the best teachers and the best books.
  • The site contain some obsolete pages as it develops like a living tree... Some links on older pages are broken. Please try to use Google, Open directory, etc. to find a replacement link (see HOWTO search the WEB for details). We would appreciate if you can mail us a correct link.

Search Amazon by keywords:

Google   
Open directory

Research Index

 

Old News ;-)

[Sep 27, 2007] freshmeat.net Project details for Closebracket

This is essentially reinvention and re-implementation of OFM context sensitive linkage of extension to commands (via ext file) with he additional twist that if there is no extension file type (for example as discovered by file) is used.

Closebracket lets you define multiple shell actions in a single command to speed up the typing of the most repetitive shell commands. It includes ']' and '][' commands, which are located near the "Enter" key and are easy to type quickly. They invoke primary and secondary actions respectively.

wcd 3.1.6

kcd looks to better for Linux users

Sep 29, 2005 OS: MS-DOS/Windows 3.1/95/98/ME/NT/2000 License: Freeware

N/A Wcd is a program to change directory fast (another Norton Change Directory clone). It saves time typing at the keyboard. One needs to type only a part of a directory name and wcd will jump to it. Wcd has a fast selection method in case of multiple matches and allows aliasing and banning of directories. Wcd also includes a full-screen interactive directory browser with speed search. Features:

Phil Braham this not NCD variant but attempt to enhance pushd/popd functionality.

cdll

readme

Bash scripts A replacement for cd. Keeps unlimited history, setup special directories for quick access

cdll allows easy moving about between directories. When changing to a new directory the current one is automatically put onto a stack. By default 50 entries are kept but this is configurable. Special directories can be kept for easy access - by default up to 10 but this is configurable. The most recent stack entries and the special entries can
be easily viewed.

The directory stack and special entries can be saved to, and loaded from, a file. This  allows them to be set up on login, saved before logging out or changed when moving project to project.

In addition, cdll provides a flexible command prompt facility that allows, for example, a directory name in colour that is truncated from the left if it gets too long.

History of visited directories in BASH LG #109

Do you realize how many times you type cd per day? Do you realize how many times you retype the same directory names again and again? Ever since I migrated from 4DOS/NT shell on Windows to using Bash on Unix platforms, I've missed its cd history access. In 4DOS/NT the history of the visited directories can be navigated by Ctrl+PgUp/Dn. Every time you go to a new directory by cd, its name automatically goes on top of an easily accessible history list.

In Bash, cd - switches between the last two directories. This is a function in the right direction but many times I wanted to go to the directory before the last, I dreamed of something like cd -2.

A little scripting creates some sanity in the directory navigation of Bash.

Installing the CD history function

To install the modified CD function, copy acd_func.sh to any directory in your $PATH, or even your home directory. At the end of your .bashrc add source acd_func.sh. Restart your bash session and then type cd --.

lotzmana@safe$ cd --
0  ~

Type cd -- to verify if the installation works. Above you may see the result 0 ~. This shows that you have one directory in your history.

lotzmana@safe$ cd work
lotzmana@safe$ cd scripts
lotzmana@safe$ pwd
/home/petarma/work/scripts
lotzmana@safe$ cd --
 0  ~/work/scripts
 1  ~/work
 2  ~
lotzmana@safe$ cd -2
lotzmana@safe$ pwd
/home/petarma

The cd command works as usual. The new feature is the history of the last 10 directories and the cd command expanded to display and access it. cd -- (or simply pressing ctrl+w) shows the history. In front of every directory name you see a number. cd -num with the number you want jumps to the corresponding directory from the history.

How CD with history works

lotzmana@safe$ nl -w2 -s' '  acd_func.sh
 1 # do ". acd_func.sh"
 2 # acd_func 1.0.5, 10-nov-2004
 3 # petar marinov, http:/geocities.com/h2428, this is public domain

 4 cd_func ()
 5 {
 6   local x2 the_new_dir adir index
 7   local -i cnt

 8   if [[ $1 ==  "--" ]]; then
 9     dirs -v
10     return 0
11   fi

12   the_new_dir=$1
13   [[ -z $1 ]] && the_new_dir=$HOME

14   if [[ ${the_new_dir:0:1} == '-' ]]; then
15     #
16     # Extract dir N from dirs
17     index=${the_new_dir:1}
18     [[ -z $index ]] && index=1
19     adir=$(dirs +$index)
20     [[ -z $adir ]] && return 1
21     the_new_dir=$adir
22   fi

23   #
24   # '~' has to be substituted by ${HOME}
25   [[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}"

26   #
27   # Now change to the new dir and add to the top of the stack
28   pushd "${the_new_dir}" > /dev/null
29   [[ $? -ne 0 ]] && return 1
30   the_new_dir=$(pwd)

31   #
32   # Trim down everything beyond 11th entry
33   popd -n +11 2>/dev/null 1>/dev/null

34   #
35   # Remove any other occurence of this dir, skipping the top of the stack
36   for ((cnt=1; cnt <= 10; cnt++)); do
37     x2=$(dirs +${cnt} 2>/dev/null)
38     [[ $? -ne 0 ]] && return 0
39     [[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}"
40     if [[ "${x2}" == "${the_new_dir}" ]]; then
41       popd -n +$cnt 2>/dev/null 1>/dev/null
42       cnt=cnt-1
43     fi
44   done

45   return 0
46 }

47 alias cd=cd_func

48 if [[ $BASH_VERSION > "2.05a" ]]; then
49   # ctrl+w shows the menu
50   bind -x "\"\C-w\":cd_func -- ;"
51 fi

4-7: cd_func() is a function, variables are declared local and are automatically deleted at the end of the function

8-11: if the function is called with a parameter "--" then it dumps the current content of the directory history. It is stored in the same place pushd/popd keep names -- the directory stack. Storage is the same, access is different.

12-13: Argument $1 is transferred into $the_new_dir for some post-processing. Immediately after that, if there are no parameters we assume that user asked for his home directory.

14-22: If parameter begins with '-' then the user is attempting to access one of the names in the history list. $index gets the number of the directory, then we extract the corresponding name into $adir. For example, dirs +3 dumps directory #3 from the stack.

At this point in $the_new_dir we have either a name specified explicitly as a parameter or a name obtained from the history of previously visited directories.

23-25: If a directory name begins with '~' then this character has to be replaced by the actual home directory name.

26-30: pushd does the actual 'cd'. It also puts the name on top of the directory stack. stdout is redirected to /dev/null in order to completely imitate how 'cd' works. Notice that any output to stderr, for example a message telling that the directory specified by the user doesn't exist will show up, which is again similar to what 'cd' does. The function aborts if pushd fails. We also need the new directory name for further analysis and $the_new_dir carries it down the function.

31-33: Keeping track of more than 10 directories is unproductive. Since we have just pushed one on top of the stack, we trim off any that fall below 11 names deep.

34-44: We loop through all the names in the directory stack. Any name that matches the new current directory is eliminated. Again, we have to translate any name from the list which begins with '~' to its format of fully expanded home directory.

47: We assign cd to be cd_func().

48-51: If the bash version allows for macros to be assigned we make ctrl+w summon the history of visited directories.

This script defines a function. It must be sourced and not executed, so that cd_func() is parsed and stored in the current environment. Try env and you must see it after all environment variables.

Documentation page of the script

Visit the acd_func.sh man page.

For comments on this article please visit or join zepp mailing list.
The text of this page is public domain.

[Mar 27, 2003]Accelerator for Changing Directory

An interesting idea of first letter abbreviations. Implementation can be better, but idea is sound.

Since I moved to Win XP my old and trusted companion for easily jumping between different spots in the directory tree, NCD (Norton Change Directory) has ceased to work.
NCD worked by building a database and by using NCD to make and remove directories, the database could be kept in sync, well almost anyway.
If the directory you wanted to go to had a unique name all you had to type was NCD dir_name but if it was a common name like test you might have had to recall the commandline one or more times to get to the destination.

Another approach would be to note that if you consider part of or the whole branch, from root to the destination, the situation will be less ambigous or even unique Using that idea I came up with this simple solution which IMHO works quite well. The user interface may be rendered idiosyncratic by some, but I welcome you to suggest improvements. The documentation is nothing fancy just a few examples included in the code. The program is tested under Win XP, but I think it could work on other OS's with some minor tweaks. PS. As directory delimiter "\", "/" or even "," can be used. The comma is due to laziness, because on the Swedish keyboard one has to use Shift or Alt Gr key to get slashes!!

So instead of typing
cd "C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\Machin eKeys"
at the DOS prompt, typing the more dense command of
a ,d,a,a,m,c,r,m
will suffice. Or even horrors a ,d,,,,,r,m ;-), but that one is tougher on the filesystem.

@perl -Swx %0 %*
@c:\a_cd.bat
@goto :eof

#!perl
# 
# Utility for quickly changing directory
# Named to "a.bat" in homage to Pr1mOS's change working directory comm
+and *a* (attach) ;-]
# 
# Syntax: 
#   a ,wi,ja,pa ===> cd \Windows\java\Packages
#   a ...\me    ===> cd \Windows\Media
#   a           ===> cd \Windows\Media\Microsoft Office 2000 *OR* a se
+lection of subdirectories
#   a /         ===> cd \
#   a mys,d,*
#   [a] /mysql/data/mysql/
#   [b] /mysql/data/tast/
#   [c] /mysql/data/test/
#   [d] /mysql/Docs/Flags/
#   select:
#
# if ambigous the correct target is selected with alpha keys /a .. zz/

#
# Versions:
# 0.2 2003-02-22 Cleanup
# 0.1 2003-01-31 First working
# 0.0 2003-01-15 Start of Coding
#

use strict;
use warnings;

use Cwd;

my $DEBUG = 0;
my $DELIM = qr{,|\\|\/};  ## Either "," or "/" or \" 
  
my @to = @ARGV ? split(/$DELIM/, $ARGV[0] ) : ();

my @cwd = split(/$DELIM/, cwd);
shift @cwd;  # Remove disk

unless ( @ARGV ) {
    push @to, @cwd, '*';
}
elsif ( $ARGV[0] =~ /^$DELIM/ and not @to ){ 
}
elsif ( $to[0] eq '' ) {
    shift @to;
}
else {
    unshift @to, @cwd;
}

## Lazy-dots
foreach my $part (0 .. $#to) {
    if ( $to[$part] =~ /\.(\.+)/ ) {
        $to[$part] = join('/',  ('..') x length($1));
    }
}

@to = split(/\//, join('/', @to));

## Rel2Abs
my @fixed;
for (@to) {
    if ($_ eq '..') {
        pop @fixed if @fixed;
    } elsif($_ eq '.') {
        ## Skip
    } else {
        push @fixed, $_
    }
}

my @choices = expand('/', @fixed);


my %hash;
my $enum = 'a';
my $choice = '';
if (1 == @choices) {    # Autoselect if only one item to choose
    $hash{a} = $choices[0];
    $choice = $enum;
} elsif(1 < @choices) {
    foreach my $c (@choices) {
        ($hash{$enum} = $c) ;
        print '[', $enum++, "] $c\n";
    }
    
    print "select: ";
    $choice = <STDIN>;
    chomp $choice;
}

# Create a batch file to change the directory in the shell.
open (CD, '>', 'C:/A_CD.BAT') or die "Failed to create CD bat file $!\
+n";
if ( defined $hash{$choice} ) {
    $hash{$choice} =~ s/\//\\/g; # Make windows happy
    print CD "\@CD \"$hash{$choice}\"\n";
} else {
    print CD "\@echo No match\n";
}
close CD;

sub expand {
    my ($bough, @twigs) = @_;

    return $bough unless @twigs; ## Looked it up in the thesaurus ;-]
    
    opendir(my $dh, $bough) || die "Can not check $bough for twigs due
+ to $!\n";
    my $regexp = shift @twigs;
    $regexp =~ s/\*/.*/;
    my @found;  
    foreach my $f ( grep { $_ =~ /^$regexp/i and $_ !~ /^\./}  readdir
+($dh) ) {
        push @found, expand("$bough$f/", @twigs) if (-d "$bough$f");
    }     
    closedir($dh) || die "Bad close for $bough $!\n";
    
    return @found;
}             

__END__

Backtracking with bash

This is a novice take or the subject, all info is wrong ;-)
I was working with linux quite a bit today, and frequently changing between directories, when I wondered if there was a way to go back to the directory I was in previously.

Turns out there is a way:

 cd ~-
So if I was doing something like this:
[pete@bigred /]$ cd /etc
[pete@bigred etc]$ cd /usr/local
[pete@bigred local]$ cd ~-
[pete@bigred etc]$ pwd
/etc
If you want to create a command so you don't have to type ~- you can create an alias:
alias cdb='cd ~-'
This ~- thing works great if you only need to go back one directory, but what if you wanted to go back two directories. Continuing the last code sample:
[pete@bigred etc]$ cd ~-
[pete@bigred local]$ cd ~-
[pete@bigred etc]$ pwd
/etc
We are back to /etc and not / our starting point. What I want is something that keeps a history of the directories I've been to.

It turns out that the Bash (the "Bourne again shell") has a directory stack builtin. Three command line tools for manipulating the stack are avaliable dirs, pushd, and popd. More info about the directory stack in bash here.

If we pushd a directory onto the directory stack, we can retreive the top of the stack using dirs +1. I tried setting up some aliases to get it to work the way I wanted:

alias cdd='pushd'
alias cdb='cd `dirs +1`'
Those worked a bit, but I ran into a lot of problems, especially when in the home directory. Also when you run pushd, popd, or dirs it always prints the contents of the stack, I don't know how to suppress that. So I figured I would post it here, and see if anyone can come up with a solution, or if anyone knows of a better way of going about this.

Isn't it funny how software developers will spend hours of time trying to save a few seconds of their future time.
 

On 01/23/2004 at 01:19 AM John wrote:
cd - works. I don't think you need cd ~-.

 

On 04/24/2004 at 04:50 AM Pritam wrote:
You can suppress the output redirecting the output to /dev/null e.g. pushd <dir-name> >> /dev/null popd >> /dev/null

Recommended Links

Internal links

External links


Copyright © 1996-2007 by Dr. Nikolai Bezroukov. www.softpanorama.org was created as a service to the UN Sustainable Development Networking Programme (SDNP) in the author free time. Submit comments This document is an industrial compilation designed and created exclusively for educational use and is placed under the copyright of the Open Content License(OPL). Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

Standard disclaimer: The statements, views and opinions presented on this web page are those of the author and are not endorsed by, nor do they necessarily reflect, the opinions of the author present and former employers, SDNP or any other organization the author may be associated with. We do not warrant the correctness of the information provided or its fitness for any purpose.

Last modified: March 15, 2008