Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: :a modifier resolves symlinks - docs say it shouldn't



On Sat, May 30, 2026 at 5:13 AM Langbart <Langbart@xxxxxxxxxxxxxx> wrote:
>
> Guten Tag,
>
> the :a modifier doc claims it operates on the logical path, but testing when CWD
> is a symlink says otherwise.
>
> ```txt
> man zshexpn | grep -C9 'not the physical directory'
>        modifiers also work on the result of filename generation and parameter
>        expansion, except where noted.
>
>        a      Turn a file name into an absolute path:  prepends the current
>               directory, if necessary; remove `.' path segments; and remove
>               `..' path segments and the segments that immediately precede
>               them.
>
>               This transformation is agnostic about what is in the filesystem,
>               i.e. is on the logical, not the physical directory.  It takes
>               place in the same manner as when changing directories when
>               neither of the options CHASE_DOTS or CHASE_LINKS is set.  For
>               example, `/before/here/../after' is always transformed to
>               `/before/after', regardless of whether `/before/here' exists or
>               what kind of object (dir, file, symlink, etc.) it is.
>
>        A      Turn a file name into an absolute path as the `a' modifier does,
>               and then pass the result through the realpath(3) library
>               function to resolve symbolic links.
> ```
>
> To reproduce:
>
> `test.zsh` script
>
> ```zsh
> #!/usr/bin/env zsh --no-rcs
>
> tmp_dir=$(mktemp -d)
> {
>   mkdir -p ${tmp_dir}/real
>   ln -s ${tmp_dir}/real ${tmp_dir}/link
>   cd ${tmp_dir}/link
>   dir=x
>
>   echo "PWD     ${PWD}"
>   echo "pwd -L  $(pwd -L)"
>   echo "pwd -P  $(pwd -P)"
>   echo
>   echo ":a      ${dir:a}"
>   echo ":A      ${dir:A}"
>   echo ":P      ${dir:P}"
> } always {
>   rm -rf ${tmp_dir}
> }
> ```
>
> Expected for ':a':  /tmp/.../link/x
>
> Actual   for ':a':  /tmp/.../real/x
>
> ```zsh
> podman run --quiet --rm -v $PWD/test.zsh:/test.zsh:ro alpine sh -c '
> apk add --quiet zsh
> zsh /test.zsh'
>
> PWD     /tmp/tmp.JcNaha/link
> pwd -L  /tmp/tmp.JcNaha/link
> pwd -P  /tmp/tmp.JcNaha/real
>
> :a      /tmp/tmp.JcNaha/real/x
> :A      /tmp/tmp.JcNaha/real/x
> :P      /tmp/tmp.JcNaha/real/x
> ```
>
> The issue came up in a bug report: https://github.com/junegunn/fzf/issues/4816
>
> P.S. I also ran it on macOS (15.7.7) with a very recent zsh dev version; the
> issue persists (ZSH_PATCHLEVEL zsh-5.9.0.2-test-325-ga58ad1a).

This is exactly what the documentation says will happen. You gave "x"
to the :a modifier so the current directory (/tmp/tmp.JcNaha/real) is
prepended, then that has no relative segments and we are done. Note
that if you change dir to ${tmp_dir}/link/x then the output is:
:a      /tmp/tmp.XUdbboXIdJ/link/x
:A      /tmp/tmp.XUdbboXIdJ/real/x
:P      /tmp/tmp.XUdbboXIdJ/real/x

I suppose you may expect it to prepend $PWD rather than the current
directory for relative paths, but that is not the case.

-- 
Mikael Magnusson




Messages sorted by: Reverse Date, Date, Thread, Author