Discussion:
Absolute path of a path
Nikolai Weibull
2010-10-27 09:25:57 UTC
Permalink
How do I get the absolute path of a path? The only thing I can find
is the :a modifier for history expansion.
Jérémie Roquet
2010-10-27 09:34:44 UTC
Permalink
Hi,
How do I get the absolute path of a path?  The only thing I can find
is the :a modifier for history expansion.
your_path(:a)

For example .(:a) is pwd

Best regards,
--
Jérémie
Nikolai Weibull
2010-10-27 09:37:28 UTC
Permalink
Post by Jérémie Roquet
How do I get the absolute path of a path?  The only thing I can find
is the :a modifier for history expansion.
your_path(:a)
Argh. Obviously. Why didn’t I try that?

Thanks!
Vincent Lefevre
2010-10-27 16:44:54 UTC
Permalink
Post by Jérémie Roquet
How do I get the absolute path of a path?  The only thing I can find
is the :a modifier for history expansion.
your_path(:a)
For example .(:a) is pwd
BTW, is there a way to get the canonicalised absolute pathname
with zsh? (i.e. what the "realpath" command gives.)
--
Vincent Lefèvre <***@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Jérémie Roquet
2010-10-27 16:54:17 UTC
Permalink
Post by Vincent Lefevre
Post by Jérémie Roquet
How do I get the absolute path of a path?  The only thing I can find
is the :a modifier for history expansion.
your_path(:a)
For example .(:a) is pwd
BTW, is there a way to get the canonicalised absolute pathname
with zsh? (i.e. what the "realpath" command gives.)
your_path(:A) I guess :)

Best regards,
--
Jérémie
Vincent Lefevre
2010-10-28 10:44:51 UTC
Permalink
Post by Jérémie Roquet
Post by Vincent Lefevre
BTW, is there a way to get the canonicalised absolute pathname
with zsh? (i.e. what the "realpath" command gives.)
your_path(:A) I guess :)
No. The zsh man path says:

A As `a', but also resolve use of symbolic links where possible.
Note that resolution of `..' occurs before resolution of sym‐
bolic links. This call is equivalent to a unless your system
has the realpath system call (modern systems do).

but Linux doesn't have a realpath system call.

ypig:~> man 2 realpath
No manual entry for realpath in section 2

FYI:

ypig:~> realpath symlink/../vlefevre/symlink
/home/vlefevre

ypig:~> echo symlink/../vlefevre/symlink(:A)
/home/vlefevre/vlefevre/symlink

where symlink is a symbolic link to ".".
--
Vincent Lefèvre <***@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Vincent Lefevre
2010-10-28 10:46:45 UTC
Permalink
Post by Jérémie Roquet
Post by Vincent Lefevre
BTW, is there a way to get the canonicalised absolute pathname
with zsh? (i.e. what the "realpath" command gives.)
your_path(:A) I guess :)
^^^^^^^^^^^^

I meant the zshexpn man page.
--
Vincent Lefèvre <***@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Vincent Lefevre
2010-10-28 10:52:50 UTC
Permalink
Post by Vincent Lefevre
ypig:~> realpath symlink/../vlefevre/symlink
/home/vlefevre
ypig:~> echo symlink/../vlefevre/symlink(:A)
/home/vlefevre/vlefevre/symlink
where symlink is a symbolic link to ".".
I think that this is even a bug in zsh, as

ypig:~> echo symlink/../vlefevre/symlink2(:A)
zsh: no match

So, it seems that resolution as been done correctly (it is
detected that symlink/../vlefevre/symlink exists but not
symlink/../vlefevre/symlink2), however the output for the
former one /home/vlefevre/vlefevre/symlink doesn't exist
(there's no vlefevre file or directory in /home/vlefevre).
--
Vincent Lefèvre <***@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Vincent Lefevre
2010-12-20 10:26:45 UTC
Permalink
Post by Vincent Lefevre
Post by Vincent Lefevre
ypig:~> realpath symlink/../vlefevre/symlink
/home/vlefevre
ypig:~> echo symlink/../vlefevre/symlink(:A)
/home/vlefevre/vlefevre/symlink
where symlink is a symbolic link to ".".
I think that this is even a bug in zsh, as
ypig:~> echo symlink/../vlefevre/symlink2(:A)
zsh: no match
So, it seems that resolution as been done correctly (it is
detected that symlink/../vlefevre/symlink exists but not
symlink/../vlefevre/symlink2), however the output for the
former one /home/vlefevre/vlefevre/symlink doesn't exist
(there's no vlefevre file or directory in /home/vlefevre).
I've reported the following bug on the Debian BTS about this:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=607615
--
Vincent Lefèvre <***@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Peter Stephenson
2010-12-20 14:44:34 UTC
Permalink
On Mon, 20 Dec 2010 11:26:45 +0100
Post by Vincent Lefevre
Post by Vincent Lefevre
Post by Vincent Lefevre
ypig:~> realpath symlink/../vlefevre/symlink
/home/vlefevre
ypig:~> echo symlink/../vlefevre/symlink(:A)
/home/vlefevre/vlefevre/symlink
where symlink is a symbolic link to ".".
I think that this is even a bug in zsh, as
ypig:~> echo symlink/../vlefevre/symlink2(:A)
zsh: no match
So, it seems that resolution as been done correctly (it is
detected that symlink/../vlefevre/symlink exists but not
symlink/../vlefevre/symlink2), however the output for the
former one /home/vlefevre/vlefevre/symlink doesn't exist
(there's no vlefevre file or directory in /home/vlefevre).
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=607615
I'm not convinced this is a bug. It may be strange, but as it's an
example manufactured to show strangeness, that's probably not
too surprising.

Let's leave (:A) out of this to begin with. We only need one fact about
it: it's in a set of globbing flags, so that means it forces the
expression to be treated as a glob, with 'no match' (or equivalent)
behaviour:

% cd ~/tmp
% ln -s . symlink
% echo symlink/../tmp/symlink(N)
symlink/../tmp/symlink
% echo symlink/../tmp/symlink2(N)
# empty

This behaviour I've shown so far is correct: symlink/../tmp/symlink is
an entry in the file system (it's a symbolic link to nothing, but that's
not a 'no match' condition), whereas symlink/../tmp/symlink2 isn't.
Until *after* you applied :A, zsh just passes it as a string to the OS,
which blindly follows it: down into symlink (doesn't change the physical
directory), then up (does), then back down into tmp... oh look, there's
a symlink entry here, so it exists.

It's only at this stage that the flags in globbing are applied. So zsh
follows the entirely different rules in this case:

Note that resolution of ‘..’ occurs before resolution of symbolic links

So we get (in my case, which is exactly parallel to yours)

/home/pws/tmp/symlink/../tmp/symlink

becomes

/home/pws/tmp/tmp/symlink

This is the key point. This is a different rule from how the OS tracks
a file name during globbing. We do not want to mess about with the
globbing rules just because the file name is going to be modified in
some way after use; in particular, we don't know in general that a
modifier is going to produce a real file name, consider :t.

Now we try and do the following:

Resolve use of symbolic links where possible
^^^^^^^^^^^^^^

Well, it's not possible. /home/pws/tmp/tmp doesn't exist, so we're
stuck at that point. Note also the rule inherited from :a

Note that the transformation takes place even if the
file or any intervening directories do not exist.

So it's not an error that we can't do anything more, it just stops
trying to do anything with it at that point and returns what it's got.

If you don't want it to check for an entry in the file system, i.e. you
don't want globbing rules on the file before the :A modifier is applied,
you need to use parameter substitution,
e.g. ${${:-symlink/../tmp/symlink}:A}, and this gives the same answer in
both cases (and in both cases the filename is useless). But this is the
right thing to do if you know you're about to create a path which
initially (during globbing) might do something different from what
happens after you've applied the :A rules.

The moral is "don't expect globbing to follow rules applicable to
directory string transformation".

The problem underlying this is the vain attempt to make symbolic links
work logically with respect to ".." when the rule applied to entries in
the filesystem is different. You can disguise a certain amount of the
illogic from the user, but you can't disguise it from the OS.
--
Peter Stephenson <***@csr.com> Software Engineer
Tel: +44 (0)1223 692070 Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
Vincent Lefevre
2010-12-25 14:43:15 UTC
Permalink
Post by Peter Stephenson
I'm not convinced this is a bug. It may be strange, but as it's an
example manufactured to show strangeness, that's probably not
too surprising.
Let's leave (:A) out of this to begin with. We only need one fact about
it: it's in a set of globbing flags, so that means it forces the
expression to be treated as a glob, with 'no match' (or equivalent)
% cd ~/tmp
% ln -s . symlink
% echo symlink/../tmp/symlink(N)
symlink/../tmp/symlink
% echo symlink/../tmp/symlink2(N)
# empty
This behaviour I've shown so far is correct: symlink/../tmp/symlink is
an entry in the file system (it's a symbolic link to nothing, but that's
not a 'no match' condition), whereas symlink/../tmp/symlink2 isn't.
Until *after* you applied :A, zsh just passes it as a string to the OS,
which blindly follows it: down into symlink (doesn't change the physical
directory), then up (does), then back down into tmp... oh look, there's
a symlink entry here, so it exists.
It's only at this stage that the flags in globbing are applied. So zsh
Note that resolution of ‘..’ occurs before resolution of symbolic links
This is confusing because the OS resolved symbolic links (during the
filename generation) before the :A rule was applied, thus before the
"resolution" of '..'. Moreover what zsh does with '..' is *not* the
standard resolution (which is to go to the parent directory). IMHO,
the documentation should say exactly what is done with '..' (this is
also true for :a) and there should be a note to say that this may not
be consistent to what has been done by the OS for filename generation
(if the result is applied of the result of filename generation).
Post by Peter Stephenson
So we get (in my case, which is exactly parallel to yours)
/home/pws/tmp/symlink/../tmp/symlink
becomes
/home/pws/tmp/tmp/symlink
This is the key point. This is a different rule from how the OS tracks
a file name during globbing. We do not want to mess about with the
globbing rules just because the file name is going to be modified in
some way after use; in particular, we don't know in general that a
modifier is going to produce a real file name, consider :t.
OK, but then I think that the documentation is very unclear and is even
lying by using the word "resolve". It isn't a resolution because what
is done by zsh doesn't correspond to what is done by the OS. It's just
a string transformation, just like :t.

Regards,
--
Vincent Lefèvre <***@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Jérémie Roquet
2010-10-28 12:19:54 UTC
Permalink
Post by Jérémie Roquet
Post by Vincent Lefevre
BTW, is there a way to get the canonicalised absolute pathname
with zsh? (i.e. what the "realpath" command gives.)
your_path(:A) I guess :)
 A    As  `a',  but also resolve use of symbolic links where possible.
      Note that resolution of `..' occurs before  resolution  of  sym‐
      bolic  links.   This  call is equivalent to a unless your system
      has the realpath system call (modern systems do).
but Linux doesn't have a realpath system call.
ypig:~> man 2 realpath
No manual entry for realpath in section 2
ypig:~> realpath symlink/../vlefevre/symlink
/home/vlefevre
ypig:~> echo symlink/../vlefevre/symlink(:A)
/home/vlefevre/vlefevre/symlink
where symlink is a symbolic link to ".".
Strange, it works for me.

$ pwd
/udir/jroquet
$ ls -l .screenrc
lrwxrwxrwx 1 jroquet kmem 37 2009-10-16 14:56 .screenrc ->
/udir/jroquet/Arkonf/screen/.screenrc
$ ls -l .screenrc(:A)
-rw-r--r-- 1 jroquet kmem 1521 2010-02-24 18:44
/udir/jroquet/Arkonf/screen/.screenrc
$ echo .screenrc(:A)
/udir/jroquet/Arkonf/screen/.screenrc

I'm running Ubuntu Linux 10.04, zsh 4.3.10
--
Jérémie
Vincent Lefevre
2010-10-28 13:17:24 UTC
Permalink
Post by Jérémie Roquet
Strange, it works for me.
Simple examples work, but not complex ones.
--
Vincent Lefèvre <***@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Benjamin R. Haskell
2010-10-28 12:45:17 UTC
Permalink
Post by Vincent Lefevre
Post by Jérémie Roquet
BTW, is there a way to get the canonicalised absolute pathname with
zsh? (i.e. what the "realpath" command gives.)
your_path(:A) I guess :)
A As `a', but also resolve use of symbolic links where possible.
Note that resolution of `..' occurs before resolution of sym‐
bolic links. This call is equivalent to a unless your system
has the realpath system call (modern systems do).
but Linux doesn't have a realpath system call.
ypig:~> man 2 realpath
No manual entry for realpath in section 2
I think "system call" should be "library call" there. (so, man 3
realpath)
--
Best,
Ben
Mikael Magnusson
2010-10-27 16:54:32 UTC
Permalink
Post by Vincent Lefevre
Post by Jérémie Roquet
Post by Nikolai Weibull
How do I get the absolute path of a path? The only thing I can find
is the :a modifier for history expansion.
your_path(:a)
For example .(:a) is pwd
BTW, is there a way to get the canonicalised absolute pathname
with zsh? (i.e. what the "realpath" command gives.)
If you mean resolving symlinks, try :A
--
Mikael Magnusson
Benjamin R. Haskell
2010-10-27 16:57:32 UTC
Permalink
Post by Jérémie Roquet
How do I get the absolute path of a path?  The only thing I can find
is the :a modifier for history expansion.
your_path(:a)
For example .(:a) is pwd
BTW, is there a way to get the canonicalised absolute pathname with
zsh? (i.e. what the "realpath" command gives.)
With new enough Zsh, you can use: the ':A' modifier.

As a workaround, though, since I have to use older Zsh'es on various
systems, I have:

# uses Perl, since that tends to be more consistent than 'realpath'
# across the systems I was using this on:

A () { reply=("$(perl -MCwd=realpath -we 'print realpath shift' $REPLY)") }

Then, instead of:

your_path(:A) -- returns the realpath in new Zsh'es.

you can do:

your_path(+A) -- calls the 'A' function above to find the realpath
--
Best,
Ben
Continue reading on narkive:
Loading...