Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

On my server I have a directory structure looking something like this:

/myproject/code

I normally have an ssh connection to the server and 'stand' in that directory:

root@machine:/myproject/code#

When I deploy a new version of my code, the code directory is removed so I'm left with:

root@machine:/myproject/code# ./run
-bash: ./run: No such file or directory

And the only solution I've found is to cd out and back in:

root@machine:/myproject/code# cd ../code
root@machine:/myproject/code# ./run
Running...

Can I avoid this? It's a somewhat strange behavior. If you have a nice explanation why this happens I would appreciate it.

share|improve this question
5  
Have you thought about removing the files in your code directory and not the code directory itself? –  StrongBad Apr 8 at 11:26
7  
You are mistaken that the newly created directory run is the same as the old directory. It only has the same name and parent directory. Compare this to you shredding your old car and buying a new car of the exact same color and model: You would not want to sit in the car being shredded and hope you end up on the new one unharmed, would you? –  Anthon Apr 8 at 11:46
1  
Anthon: What I assume is that the path is what identifies the directory. To me the "cd ../code" is a noop. I'm very interested into hearing why it isn't. –  Markus Johansson Apr 8 at 11:58
2  
@MarkusJohansson cd ../code is not a noop. .. is a shortcut for the parent of the path that you have, or used to have. If your current directory is deleted the parent path might still exist, and in this case be reachable by evaluating ... In that directory a search is done for a directory with name 'code'. –  Anthon Apr 8 at 13:46
1  
@MarkusJohansson Instead of removing and tarring code, I would highly recommend to use any version control tool available. Far more easy to share update (just push or pull) and less options to accidentally delete the wrong files. And you keep older version by default. –  Bernhard Apr 9 at 14:15

6 Answers 6

up vote 23 down vote accepted

To me the "cd ../code" is a noop. I'm very interested into hearing why it isn't.

Because files and directories are fundamentally filesystem inodes, not names -- this is perhaps an implementation detail specific to the filesystem type, but it is true for all the ext systems, so I'll stick to it here.

When a new directory code is created, it is associated with a new inode, and that's where it is. There is no record kept of previously deleted files and directories, so there is no means by which the system could check what inode it used to occupy and perhaps shuffle things around so that it is the same again; such a system would quickly become unworkable, and in any case, it is probably no guarantee that you would be back there again -- that would be sort of undesirable, since it means you could also accidentally end up somewhere else if a directory is created that takes your (currently unused) inode.

I'm not sure if this last possibility exists, or if the inode of the deleted directory currently assigned to your present working directory is tracked so that nothing will be assigned to it for the duration, etc.

share|improve this answer
3  
This is the real answer here. –  karan.dodia Apr 9 at 7:08

Your shell doesn't every time do a cd to the path that it was in during the last command, before executing the next command.

You deleted the current directory and created a directory with the same name, which is not the same directory, just something with the same name/path.

File browsers like Nautilus and Windows Explorer normally "go up" the directory tree if a directory gets deleted on a local file system. However this is not always true for networked file systems, in that case sometimes the deletion does not get noticed and the reappearance could have you ending up in the new directory.

A shell could cd into the current directory before executing the next command, I am not aware of any that do (or can be configured to do so).

share|improve this answer
    
Fol illustration - in theory, there could even exist a file system where the old, deleted (or rather unlinked) directory still exists and is readable, while the new one is already in use too. That would not be useful in practice with directories, but with files, it is pretty common. –  Volker Siegel Apr 9 at 7:42

On most UNIX-like systems, the "current directory" for a process is stored in the kernel as a file descriptor pointing to that directory. The kernel doesn't actually store the path of the current directory: that information is tracked by your shell.

A filesystem object (file or directory) is only destroyed for good when all filesystem links to it are gone, and there are no file descriptors pointing to that object.

So, if a directory is removed while there's still a process holding it as its current working directory, the process's cwd will keep the directory from being truly deleted. The filesystem links that anchor the directory (its entry in the parent directory, and all of its contents) will be gone, but the directory itself will continue to exist as a sort of "zombie". Meanwhile, you can create a brand new directory at the same location as the old one, which is a completely different filesystem object but which shares the same path.

Thus, when you do cd ../code (or, on many shells, cd .), you are actually traversing the filesystem hierarchy and going to the new directory that resides at the old address.

By analogy, removing a directory would be like forcefully moving a house to the garbage dump (breaking ties to the previous address). If there was still someone living there (using it as their cwd), they'd have to leave before the house could be razed. In the meantime, a brand-new house could be built at the old address.

share|improve this answer

@Anthon cleared reasons, why it happens
As solution you may use alias, as example:

alias 1234='PROJECT=`pwd`; cd $PROJECT ; ./run'

aliases for bash are keept in ~/.bashrc

share|improve this answer

Confirming The current working directory IS based on the inode number, not what you looked up to get there. Since you are using bash, you can use $PWD as follows to cd to the new directory of the same name:

cd $PWD

To illustrate, I made a dummy deploy command:

set -x
cd ~/tmp
rm -rf code
mkdir code
echo echo hello from $* > code/run
chmod +x code/run

Created the first deployment, cd'd to code and then checked contents with ls -lai so you can see the inodes:

ianh@abe:~/tmp$ ./,deploy first
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from first
++ chmod +x code/run
ianh@abe:~/tmp$ cd code
ianh@abe:~/tmp/code$ ls -lai
total 12
22945913 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   22 Apr  9 23:12 run

Now run the 2nd deploy

ianh@abe:~/tmp/code$ ../,deploy 2nd
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from 2nd
++ chmod +x code/run

And check the directory contents ... now there isn't anything in the directory! not even '.' and '..'! From this you can see that bash is not using the '..' directory entry when you run cd .. since '..' no longer exists - I presume its part of its $PWD handling. Some other/older shell's don't handle cd .. in this situation, you have to cd to an absolute path first.

ianh@abe:~/tmp/code$ ls -lai
total 0

Cd to $PWD and try again:

ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ls -lai
total 12
22945914 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   20 Apr  9 23:12 run
ianh@abe:~/tmp/code$ ./run
hello from 2nd

Note how the inode for the current directory (.) changed?

If your deploy script moved the old directory to some other name, eg mv code code.$$ in the ,deploy script above, then ./run would work, but until you use cd $PWD you would be running the old code, not the new.

ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ ../,deploy 3rd
++ cd /home/ianh/tmp
++ '[' -d code ']'
++ mv code code.9629
++ mkdir code
++ echo echo hello from 3rd
++ chmod +x code/run
ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ./run
hello from 3rd

Deploying using capistrano has the same issue (They have a symlink from the name current to the current release), so I use aliases to cd to the production/staging areas as well as set RAIL_ENV appropriately:

alias cdp='export RAILS_ENV=production; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/www.example.com/current'
alias cds='export RAILS_ENV=staging; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/staging.example.com/current'
share|improve this answer

What I assume is that the path is what identifies the directory.

The path to something is how you get there, not the thing itself. The path to your bed may be through your room, but once you are in bed, if someone picks it up and carries it outside, you are no longer in your room.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.