[comp.unix.shell] Csh question: Doing cd .. from a symbolically linked directory

jerry@slhisc.uucp (Jerry Liebelson) (10/24/90)

*SEND REPLIES TO: uunet!slcpi!slhisc!jerry
Organization: Shearson Lehman Brothers, Inc.
------------------------------------------------------------------------------
 SITUATION:

   1. cd /tmp	
   2. mkdir -p a/b
   3. ln -s a/b c

 PROBLEM:

   1. cd /tmp/c
   2. pwd    (output is "/tmp/c")
   3. cd ..
   4. pwd    (output is "/tmp/a", not "/tmp" ! )

 QUESTION:
   Is there a way to set things in the csh such that when I do the cd ..
 from /tmp/c, I will end up in /tmp and not in /tmp/a?
 I tried setting the hardpaths variable but that just changes the output
 of pwd when I am in /tmp/c (displaying "/tmp/a/b" instead of "/tmp/c").

 COMMENT:
   I know the behavior I want can be achieved in the Korn Shell.  But I
 am stuck with the Csh for now.

--
         Jerry Liebelson                   uunet!slcpi!slhisc!jerry   
    Distributed Infrastructure             (212) 341-3166  FAX: (212) 528-0101
   Shearson Lehman Brothers, Inc.         
--
         Jerry Liebelson                   uunet!slcpi!slhisc!jerry   
    Distributed Infrastructure             (212) 341-3166  FAX: (212) 528-0101
   Shearson Lehman Brothers, Inc.         

maart@cs.vu.nl (Maarten Litmaath) (10/25/90)

In article <JERRY.90Oct24110101@sky.slhisc.uucp>,
	jerry@slhisc.uucp (Jerry Liebelson) writes:
)...
) SITUATION:
)
)   1. cd /tmp	
)   2. mkdir -p a/b
)   3. ln -s a/b c
)
) PROBLEM:
)
)   1. cd /tmp/c
)   2. pwd    (output is "/tmp/c")
)   3. cd ..
)   4. pwd    (output is "/tmp/a", not "/tmp" ! )
)
) QUESTION:
)   Is there a way to set things in the csh such that when I do the cd ..
) from /tmp/c, I will end up in /tmp and not in /tmp/a?

Yes:
	alias	cd	'cd `xcd $cwd \!*`'

...where `xcd' is the following shell script, located somewhere in your
PATH.  (You may have to change the `cd' in the alias to `chdir'.)

--------------------cut here--------------------
#!/bin/sh
#
# alias cd 'cd `xcd $cwd \!*`'

case $# in
1)
	echo $HOME
	exit 0
	;;
2)
	case $2 in
	/*)
		echo "$2"
		exit 0
		;;
	*..*)
		;;
	*)
		echo "$1/$2"
		exit 0
	esac
esac

# /a/b/c/symlink1/symlink2/../../src -> /a/b/c/src

SED='
: loop
	s|/[^/]*/\.\.||g
	t loop
'
echo "$1/$2" | sed "$SED"
--------------------cut here--------------------
--
Waiting for this to work: cat /internet/cs.vu.nl/finger/maart

kivinen@cs.hut.fi (Tero Kivinen) (10/25/90)

In article <JERRY.90Oct24110101@sky.slhisc.uucp> jerry@slhisc.uucp (Jerry Liebelson) writes:
>      Is there a way to set things in the csh such that when I do the cd ..
>    from /tmp/c, I will end up in /tmp and not in /tmp/a?

Try alias .. 'cd /$cwd:h' in your .cshrc, and then typing .. works.
This will work in csh or in tcsh.
--
  ______ ______ _   ,	!Tero_Kivinen@hut.FI  ! Work : +358-0-451 4032 !
    /      /   ' ) /	!Tero Kivinen         ! Voice: +358-0-523 542  ! 
 --/    --/     /-<	!                     ! Data : +358-0-524 207  ! 
(_/    (_/     /   )    +---------------------+------------------------+

maart@cs.vu.nl (Maarten Litmaath) (10/26/90)

In article <KIVINEN.90Oct25125016@deathstar.hut.fi>,
	kivinen@cs.hut.fi (Tero Kivinen) writes:
)In article <JERRY.90Oct24110101@sky.slhisc.uucp>
)	jerry@slhisc.uucp (Jerry Liebelson) writes:
)>      Is there a way to set things in the csh such that when I do the cd ..
)>    from /tmp/c, I will end up in /tmp and not in /tmp/a?
)
)Try alias .. 'cd /$cwd:h' in your .cshrc, and then typing .. works.
)This will work in csh or in tcsh.

But that doesn't deal nicely with `cd ../../foo/bar'...
Following is a solution that does _and_ is completely builtin!
Piece of cake right?  :-)

--------------------cut here--------------------
alias	cd	'set tmp=(\!*); eval cd$#tmp $cwd \!*/. ../ ~; echo $cwd'
alias	cd0	'chdir \!$'
alias	cd1	'if (x\!:2 !~ x../*) set status=1'\
		'&& eval cd2 /\!^:h \!:2-:s-../--'\
		'|| chdir \!:2'
alias	cd2	'if (x\!:2 !~ x../*) set status=1'\
		'&& eval cd2 /\!^:h \!:2*:s-../--'\
		'|| chdir \!^/\!:2'
--------------------cut here--------------------
--
Waiting for this to work: cat /internet/cs.vu.nl/finger/maart

maart@cs.vu.nl (Maarten Litmaath) (10/27/90)

Here's a slight improvement; check the output of `cd /'; furthermore
you won't get into trouble if you accidentally type `cd foo/ bar' or
if there is a subdirectory `0' and you type `cd0'.
--------------------cut here--------------------
alias	cd	'set tmp=(\!*); eval _cd_$#tmp $cwd \!*//. ../ ~; echo $cwd'
alias	_cd_0	'chdir \!$'
alias	_cd_1	'if (x\!:2 !~ x../*) set status=1'\
		'&& eval _cd_x /\!^:h \!:2-:s-../--'\
		'|| chdir \!:2:h'
alias	_cd_x	'if (x\!:2 !~ x../*) set status=1'\
		'&& eval _cd_x /\!^:h \!:2*:s-../--'\
		'|| chdir \!^/\!:2:h'
alias	pwd	'echo $cwd'
--------------------cut here--------------------
--
Waiting for this to work: cat /internet/cs.vu.nl/finger/maart

rbp@investor.pgh.pa.us (Bob Peirce #305) (11/01/90)

In article <8060@star.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>--------------------cut here--------------------
>alias	cd	'set tmp=(\!*); eval _cd_$#tmp $cwd \!*//. ../ ~; echo $cwd'
>alias	_cd_0	'chdir \!$'
>alias	_cd_1	'if (x\!:2 !~ x../*) set status=1'\
>		'&& eval _cd_x /\!^:h \!:2-:s-../--'\
>		'|| chdir \!:2:h'
>alias	_cd_x	'if (x\!:2 !~ x../*) set status=1'\
>		'&& eval _cd_x /\!^:h \!:2*:s-../--'\
>		'|| chdir \!^/\!:2:h'
>alias	pwd	'echo $cwd'
>--------------------cut here--------------------

What do you do if your csh doesn't have eval and doesn't set cwd?
-- 
Bob Peirce, Pittsburgh, PA				  412-471-5320
...!uunet!pitt!investor!rbp			rbp@investor.pgh.pa.us

rbp@investor.pgh.pa.us (Bob Peirce #305) (11/01/90)

My brain damaged csh lacks eval and it doesn't set cwd.  It also runs on
an Altos with worknet -- top level directories may be / or @node. 
However, we do have symbolic links, so here is my solution.  I have been
hacking on this for about the last day or two.  It now handles 99% of
anything we might want to do here.  I would dearly love to know how I
can improve it. 

#  Handle typical .. moves from a symbolically linked directory
#  You can go home, rel, abs, .. or ../something.  That's it.
#  On an Altos with worknet, / may also be @node
#  Some aliases may add extraneous /s so we have to squeeze them
#  Logic is to check if you are going home.  If not, check the first
#  char of the arg to see if it is dot, /,  or  @.
#  If we lead off with a dot and the arg is the same as the tail of
#  the arg we are just doing ..  Otherwise we are doing ../something.
#  If we .. all the way to /, we have to set /.
#  If we lead off with  / or @ it is absolute.
#  If we do not lead off with dot, / or @ it is relative so
#  we append the arg to $cwd/.
set cwd = `pwd`
alias	cd	'\\
	set nwd;\\
	set tmp;\\
	set tgt = \!*;\\
	if (x\!* == "x") set nwd = $home;\\
	if (x$nwd != x$home) set tmp = `echo \!* | cut -c1`;\\
	if ("x\$tmp" == 'x\\\\.' && $tgt == $tgt:t) set nwd = $cwd:h;\\
	if ("x\$tmp" == 'x\\\\.' && $tgt != $tgt:t) set nwd = $cwd:h/$tgt:t;\\
	if ("x\$tmp" == 'x\\\\.' && $nwd == "") set nwd = /;\\
	if (x$nwd != x$home && x$tmp == 'x/' || x$tmp == 'x@') set nwd = \!*;\\
	if (x$nwd == "x" && \!* != '..') set nwd = $cwd/\!*;\\
	chdir $nwd;\\
	set cwd = `echo $nwd | tr -s '/'`'

-- 
Bob Peirce, Pittsburgh, PA				  412-471-5320
...!uunet!pitt!investor!rbp			rbp@investor.pgh.pa.us

tchrist@convex.COM (Tom Christiansen) (11/02/90)

In article <1990Oct31.164203.20518@investor.pgh.pa.us> rbp@investor.pgh.pa.us (Bob Peirce #305) writes:
>What do you do if your csh doesn't have eval and doesn't set cwd?

Get a real system. :-)

--tom

rbp@investor.pgh.pa.us (Bob Peirce #305) (11/03/90)

Yesterday I posted a note on the problem facing this user of csh who
has sym links but lacks eval and a setting mechanism for cwd.  After
thinking about it more today I decided the best solution was to build
the path with a small C program and to use a short alias to drive it.
The results follow.  The C program could be made smaller and, possibly
faster by not using stdio, but this works.  Setting the sticky bit
also might help.

============================== csh alias ==============================
#  Handle typical .. moves from a symbolically linked directory
set cwd = `/bin/pwd`
alias	pwd	'echo $cwd'
alias	rpwd	/bin/pwd
alias	rcd	chdir
alias	cd	'\\
	if (\!* == "") set tmp = $home;\\
	if (\!* != "") set tmp = `glob \!*`;\\
	set cwd = `/usr/local/lib/chd $cwd $tmp`;\\
	chdir $cwd'
============================== C program ==============================
/*  @(#) chd.c
	C program for cd
*/

#include <stdio.h>

main(argc,argv)
char **argv;
int argc;
{
	int	i, j;
	char	path[256];

	if (argc != 3) exit();		/*  silent failure  */

	/*  Top dir in Altos Worknet may be @node */
	if (argv[2][0] == '/' || argv[2][0] == '@')
		printf ("%s\n", argv[2]);
	else {
		strcpy(path, argv[1]);
		strcat(path, "/");
		strcat(path, argv[2]);
		i = j = 0;
		while (path[i] != '\0') {
			if ( j != i) path[j] = path[i];
			if (path[i] == '.' && path[i+1] == '.') {
				++i;
				if (j >= 2) {
					j -= 2;
					while (path[j--] != '/')
						;
				}
				else j = -1;
			}
			++i;
			++j;
		}
		if (j == 0)
			strcpy (path, "/");
		else
			path[j] = '\0';
		printf ("%s\n", path);
	}
}
============================== END ==============================
-- 
Bob Peirce, Pittsburgh, PA				  412-471-5320
...!uunet!pitt!investor!rbp			rbp@investor.pgh.pa.us