0

I wrote this small function in my .zshrc file to make moving back in the directory tree faster:

#: Move back x director(y/ies). function bak () { local x="" local limit="$1" local msg="Can't move back $limit directories" [ -z "$limit" ] && limit=1 for ((i=0;i<limit;i++)); do x="../$x" done if ! cd "$x"; then echo "$msg"; fi } 

It works just fine except for 2 caveats:

  1. While the function runs and I can move back in the directory tree, if I ever try to move past the limit (root "/") the function doesn't print out the error message. So basically this part

    if ! cd "$x"; then echo "$msg"; fi 

    just doesn't do anything.

  2. If I remove that part (the if statement to print error message), the function no longer works.


Can anyone help me get the error message part to work, please? Also if anyone can explain why removing the error message part breaks the function that would be great.

2
  • 1
    There's a .. entry in the root directory, pointing right back to the root directory (run ls -lid / /. /.., and you'll see that all three have the same inode number, i.e. they're all the exact same thing). Also, when you removed the if statement, did you remove the cd along with it? Commented Aug 10, 2021 at 8:05
  • @Gordon Davisson yeah I removed the entire if statement (from if to fi) Commented Aug 10, 2021 at 10:38

1 Answer 1

2

On most systems the /.. path refers to the same file as /, the root directory. That's allowed though not required by POSIX:

The special filename dot-dot shall refer to the parent directory of its predecessor directory. As a special case, in the root directory, dot-dot may refer to the root directory itself.

Even on systems where /.. is not the same as /, as you're calling cd without -P, that defaults to cd -L where the shell does a logical cd, whereby when $PWD is /a/b/c (where /a, /a/b or /a/b/c could very well be symbolic links to other directories) and you do cd ../.. for instance, instead of doing chdir("../.."), cd does chdir("/a") and if you do cd ../../../../../../.., cd does a chdir("/") (as required by POSIX).

Also note that error messages should go to stderr:

bak() { local x limit="${1-1}" repeat "$limit" x+=../ cd "$x" && return local ret=$? print -u2 "Can't cd back $limit directories" return "$ret" } 

Though that message is likely to be superfluous as if cd failed it will already have written an error message.

If you want to return failure if bak is given a limit greater than the number of components in $PWD, you can do:

bak() { local depth=0 dir=$PWD x repeat "${1-1}" { if [[ $dir = / ]]; then print -u2 "The current working directory is only $depth level deep" return 1 fi dir=$dir:h x+=../ ((depth++)) } cd "$x" } 
1
  • sorry for the late reply I had to run some errands just now. Thank you so much for such a great answer (and links to the documentation are the cherries on top!). I'll be reading up on the docs for now. Thank you again! Commented Aug 10, 2021 at 10:35

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.