LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-09-2010, 10:41 PM   #1
Spyes
LQ Newbie
 
Registered: Jan 2010
Distribution: Gentoo
Posts: 18

Rep: Reputation: 0
source code for cd (change directory)


Hey guys

I want to modify the source of cd (the 'change directory' command) to do a little extra for me, but I can't seem to find the source code anywhere.. maybe I didn't look for it well enough, and googling "source code cd" and variants of that doesn't exactly help... I was wondering if anyone knew where I could find the src?

Thanks
~Lewis
 
Old 02-09-2010, 10:44 PM   #2
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
The current working directory is part of the environment. 'cd' *cannnot* be implemented as an external program. A simple way to demonstrate this is to run
Code:
#include <unistd.h>
int main()
{
   chdir("/");
   return 0;
}
The main take-away, is that 'cd' must always be implemented as a shell builtin.
 
Old 02-09-2010, 10:50 PM   #3
Spyes
LQ Newbie
 
Registered: Jan 2010
Distribution: Gentoo
Posts: 18

Original Poster
Rep: Reputation: 0
Oooh I see, so the 'cd' command is part of bash (for example) and not an actual program?
That makes sense, because "which cd" returns an error (and also because a program can't change the directory of its parent process, or so I understand it...)

The thing I wanted to do is modify cd so that it saves the current directory in a file, ~/.cd_history, and then changes to the specified dir. Then what I can do is call cdb (cd-back) or cdf (cd-forward) and go back (or forward) to previous directories.
Not much, but it could prove useful, I suppose...

So how would I go about implementing this then? I tried writing both a perl and a bash script before realizing that they cannot change the directory of the parent process...

Thanks,
~Lewis
 
Old 02-09-2010, 11:38 PM   #4
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
Quote:
Originally Posted by Spyes View Post
So how would I go about implementing this then? I tried writing both a perl and a bash script before realizing that they cannot change the directory of the parent process...
The trick is twofold.
  1. Hang on to that bash script. That's the one you want to use.
  2. Instead of calling it the normal way, use the "." command to call it.
For a proof of concept, run this script:
Code:
cat > 2.sh <<EOD
cd /
EOD
echo before calling the script, the current working directory is:
pwd
. ./2.sh
echo after calling the script, the current working directory is:
pwd
You'll get output something like this:
Code:
before calling the script, the current working directory is:
/u/wally/tuesday/2
after calling the script, the current working directory is:
/
Hope this helps.
 
Old 02-09-2010, 11:55 PM   #5
Spyes
LQ Newbie
 
Registered: Jan 2010
Distribution: Gentoo
Posts: 18

Original Poster
Rep: Reputation: 0
Awesome, thanks wje_lq , that does help

To run it globally, I coppied it to /usr/local/bin and ran it like this: ". cd.sh"
So I suppose I could just write an alias cd that does that for me.

Thanks again
 
Old 02-10-2010, 12:10 AM   #6
Spyes
LQ Newbie
 
Registered: Jan 2010
Distribution: Gentoo
Posts: 18

Original Poster
Rep: Reputation: 0
Hrmm...
it appears that copying it to /usr/local/bin and running it with ". cd.sh" doesn't work.. it goes into an infinite loop, apparently.
Code:
echo $PWD >> ~/.cd_history
if [ $# -lt 1 ]
then
	cd ~
else
	cd "${1}"
fi
I also aliased it in .bashrc:
Code:
alias cd='. cd.sh'
But obviously that doesn't work...

Any ideas?
 
Old 02-10-2010, 12:39 AM   #7
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Rocky 9.2
Posts: 18,363

Rep: Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751
How about making it a fn, declared in your .bash_profile ?
http://tldp.org/LDP/abs/html/functions.html

You may need the export trick here http://www.cyberciti.biz/faq/bash-sh...tion-examples/
 
Old 02-10-2010, 08:30 AM   #8
mjones490
Member
 
Registered: Sep 2005
Distribution: LFS
Posts: 60

Rep: Reputation: 22
This is already implemented in bash as pushd and popd.

Thought I'd point that out so you won't spend great effort trying to do this if it's a must-have. Of course, if you're doing that as a learning exercise, by all means, go forth and program!
 
Old 02-10-2010, 08:53 AM   #9
orgcandman
Member
 
Registered: May 2002
Location: new hampshire
Distribution: Fedora, RHEL
Posts: 600

Rep: Reputation: 110Reputation: 110
Put the following into your .bashrc or .bash_profile

Code:
# #-- CD History
CDHIST[0]=$PWD
alias cd=cdh

if [ -e $HOME/.cdhist ]
    then
    . $HOME/.cdhist
fi

cdh()
{
    typeset -i cdlen i
    
    if [ "$#" -eq 0 -a "$PWD" != "$HOME" ]
        then
        set -- $HOME
    fi
    
    cdlen=${#CDHIST[*]}
    
    case "$@" in
        -l)
            i=0
            while ((i < cdlen))
              do
              printf "%3d %s\n" $i "${CDHIST[i]}"
              ((i = i + 1))
            done
            return ;;
        -[0-9]|-[0-9][0-9])
            i=${1#-}
            'cd' "${CDHIST[i]}"
            return
            ;;
        *)
            if [ ! -e "$@" ]
                then
                echo "bash: cd: $@: No such file or directory"
                return
            fi

            if [ ! -d "$@" ]
                then
                echo "bash: cd: $@: Not a directory"
            fi

            'cd' "$@"
            ;; 
    esac
    
    CDHIST[cdlen]="$PWD"

    return
}

#-- end CD History
Restart your bash process. Now, when you run 'cd' it preserves every directory to which you've been.
If you want to see the list, cd -l
If you want to change to a specific (lets say #10) directory, cd -10

The big problem with pushd/popd is that you can't run to an arbitrary directory in the stack. You MUST pop down the line.
 
Old 02-10-2010, 09:10 AM   #10
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
I haven't tested orgcandman's solution, but it doesn't pay sufficient attention to just which file should contain it. Also, you can't export an alias; more on exporting stuff, and initialization files, below.
Quote:
Originally Posted by mjones490 View Post
This is already implemented in bash as pushd and popd.
Not quite (as orgcandman points out), because:
Quote:
Originally Posted by Spyes View Post
Then what I can do is call cdb (cd-back) or cdf (cd-forward) and go back (or forward) to previous directories.
pushd and popd will help with cdb, but not with cdf.
Quote:
Originally Posted by chrism01 View Post
How about making it a fn, declared in your .bash_profile ?
http://tldp.org/LDP/abs/html/functions.html

You may need the export trick here http://www.cyberciti.biz/faq/bash-sh...tion-examples/
*** the basic solution (but nowhere near complete) ***

Put the following into your ~/.bash_profile, or your ~/.profile. If you have neither one, pick either one.
Code:
cd() {
echo $PWD >> ~/.cd_history
if [ $# -lt 1 ]
then
        builtin cd ~
else
        builtin cd "${1}"
fi
}

export -f cd
Then try it out. You'll find that it works.

chrism01's second link advises that last export statement. But it doesn't explain why.

*** what happens if you don't use export ***

Here's why you need it. You don't need it when you're in your login window. But if, say, you do this:
Code:
xterm &
and move to that other window, you'll find that the new definition disappears. That's because neither .profile nor .bash_profile is run on any shell except the login shell. (Those are the customary terms; what they really mean is "any instantiation of the shell except at login".)

What you use for other shells is ~/.bashrc. So why not just put the code there? Because .bashrc is not used for login shells, just for the others!

This can actually be a feature. You can decide to have one operating context for login shells, and another for other shells, and this is a clean way to divide them. But I think most people won't care. If that's the case, you might be tempted to make .bashrc duplicate .profile (or .bash_profile), or the other way around. Don't do this. Why? Because when you make a change to one, you might forget to make a change to the other. The solution to this is either to put this:
Code:
. ~/bashrc
in your profile file, and put all your real stuff in .bashrc, or the other way around. (A link, symbolic or otherwise, from one to the other sounds useful, but it complicates things if you decide later that the two files should have slightly different content.)

I'm boring you with all these details because it's a good idea to know the relationships among these initialization files. You won't need to know this for your current purposes, however, because you're going to use the export statement, right?

*** what the export statement doesn't solve: .profile versus .bash_profile ***

If your home directory contains either .profile or .bash_profile , but not both, that file will be executed whenever you fire up a login shell.

But.

If both files exist, it will run .bash_profile and ignore .profile, without warning.

This is not a feature. This is a dangerous bug. Steam is coming out of my ears as I write this.

*** this dangerous bug doesn't affect your situation ***

I gather from your reference to /etc/profile that you want this to be a universal feature on your system. Go ahead and put your code there. Because you'll be using export, you'll not need /etc/bashrc. This is a good thing, because bash doesn't look at any such file. And it doesn't look at /etc/bash_profile, either, so you don't have to worry about that.

Hope this helps.
 
Old 02-10-2010, 09:25 AM   #11
ForzaItalia2006
Member
 
Registered: Dec 2009
Location: Walldorf, Germany
Distribution: (X)Ubuntu, Arch, Gentoo
Posts: 205

Rep: Reputation: 67
Hey,

Quote:
Originally Posted by Spyes View Post
Oooh I see, so the 'cd' command is part of bash (for example) and not an actual program?
That makes sense, because "which cd" returns an error (and also because a program can't change the directory of its parent process, or so I understand it...)
just a bit late and possibly already out-of-context , but you could use the type command of the bash to verify that 'cd' is built-in:

Code:
[root@andihellmund 4.4.3]# type cd
cd is a shell builtin
[root@andihellmund 4.4.3]# type gcc
gcc is hashed (/usr/bin/gcc)
Though, just for completeness ...

- Andi -
 
Old 02-10-2010, 09:30 AM   #12
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
Quote:
If both files exist, it will run .bash_profile and ignore .profile, without warning.

This is not a feature. This is a dangerous bug. Steam is coming out of my ears as I write this.
erm, it *is* a feature, just like the difference between .bashrc and .bash_profile. It allows me to have use a different context for a bash login shell than if I happen to use zsh or ksh as a login shell. This behaviour is quite clearly documented, and I'd find it a *bug* if it tried to source more than one system profile and more than one user profile, because that assumes a workflow for the user that may not really be the case.

Also, DON'T export functions like cd. Although it might sound nifty, exporting these functions also affects shell scripts and may cause them to fail in strange and mysterious ways.

Last edited by tuxdev; 02-10-2010 at 09:32 AM.
 
Old 02-10-2010, 09:31 AM   #13
jschiwal
LQ Guru
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,733

Rep: Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682
The book "Learning Bash" implement a popd and pushd of their own as an exercise. It may provide clues on how to do what you want.
 
Old 02-10-2010, 09:44 AM   #14
Spyes
LQ Newbie
 
Registered: Jan 2010
Distribution: Gentoo
Posts: 18

Original Poster
Rep: Reputation: 0
Wow, that's a lot more information than I expected! :P Thanks guys!
I will look into the various solutions available and whatnot, but yeah, it was mostly just as an exercise I guess..

Anyways, thanks again for all the info guys Much appreciated!
 
Old 02-10-2010, 10:45 AM   #15
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
Quote:
Originally Posted by tuxdev View Post
It allows me to have use a different context for a bash login shell than if I happen to use zsh or ksh as a login shell. This behaviour is quite clearly documented, and I'd find it a *bug* if it tried to source more than one system profile
I would consider that a bug also. But the problem with saying the current situation is "clearly documented" is that, in the real world, it's easy for someone to be confused by this. IMO.

I'm not saying that bash should read both files. That would be horrendous. I'm saying that if bash finds both files, it should heed .bash_profile, just as it does now, but issue a warning to stderr unless there's something in the .bash_profile which indicates that the warning should not be issued. That covers both those who read all the documentation and those who could have missed this.
Quote:
Originally Posted by tuxdev View Post
Also, DON'T export functions like cd. Although it might sound nifty, exporting these functions also affects shell scripts and may cause them to fail in strange and mysterious ways.
A user (or, for /etc/profile, a site admistrator) could make the judgment call that a function named cd has been sufficiently well written, and sufficiently transparent, that no scripts will be broken, and take this risk. I sense that this is a religious issue.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
change default vsftp anonymous accout directory /var/ftp to other directory? hocheetiong Linux - Newbie 2 01-24-2010 06:33 PM
perl: need a few lines to change source directory within a bioinformatics program pwd_pwd_omg_pwd Programming 4 11-18-2008 05:57 PM
Reload this Page Where is the kernel module source code directory? Unregistered Slackware 1 10-13-2007 10:06 PM
why we can't change the block size in ext2 filesystem in source code nagesh20k Linux - General 3 08-23-2006 04:47 PM
kde: i want to access the logout source code and change it. Doomhammer Linux - Software 1 10-18-2004 01:13 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 12:52 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration