g | x | w | all
Bytes Lang Time Link
148JavaScript Node.js250601T174558Zl4m2
05505AB1E221128T140436ZKevin Cr
066C# Visual C# Interactive Compiler221130T160537Zjdt
099Retina 0.8.2221129T001958ZNeil
101JavaScript Node.js221128T172534ZArnauld
087Python221128T175906Zcorvus_1
081Python 3221128T180545ZJoe

JavaScript (Node.js), 148 bytes

a=>b=>'cd '+(b[(y=((x=(a+`/@${b}/`).replace(/~/g,'/home/h').match(/(.*\/)(.*)@\1(.*)/))[2].replace(/\w+/g,'..')+x[3]).slice(0,-1)).length]?y||'.':b)

Try it online!

Not based on builtin path lib

05AB1E, 60 56 55 bytes

Ëi'.ë'~…/€¨/:'/©δ¡ζ.γË}¦˜2ôøðδK`®ýsg…../×ì®Ü}Iθ)éн…cd ì

-4 bytes thanks to @JonathanAllan

Inputs as a pair.

Try it online or verify all test cases.

Explanation:

Ëi              # If both paths in the (implicit) input-pair are the same:
  '.           '#  Push "."
 ë              # Else:
  '~     :     '#  In the strings of the (implicit) input-pair, replace all "~"
    …/€¨/       #  with dictionary string "/home/"
  '/©          '#  Push "/", and save it in variable `®` (without popping)
     δ          #  Map over the pair, with "/" as argument:
      ¡         #   Split the paths in the strings by this "/"
  ζ.γË}¦˜2ôøðδK #  Remove the matching path-prefixes:
  ζ             #   Zip/transpose; swapping rows/columns,
                #   using a " " as filler-character if the paths are of unequal length
   .γ }         #   Then group the pairs by:
     Ë          #    Check if the two values in the pair are the same
      }¦        #   After the group-by: remove the first group
        ˜       #   Flatten it to a single list
         2ô     #   Split it back into pairs
           ø    #   Zip/transpose these pairs back
             δ  #   Map over each inner list:
            ð K #    Remove all spaces
  `             #  Pop and push both lists separated to the stack
   ®ý           #  Join the second list with "/" delimiter
   s            #  Swap so the first list is at the top of the stack
    g           #  Pop and push its length
     …../×      #  Pop this length, and repeat string "../" that many times
   ì            #  Prepend it in front of the other string
    ®Ü          #  And trim a potentially trailing "/"
 }              # Close the if-else statement
  Iθ            # Push the second string of the input-pair
)               # Wrap all values on the stack into a list
 é              # Sort it by length
  н             # Pop and leave just the first/shortest one
   …cd ì        # Prepend "cd " in front of it
                # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why …/€¨/ is "/home/".

C# (Visual C# Interactive Compiler), 66 bytes

(a,b,c)=>"cd "+((c=Path.GetRelativePath(a,b)).Length<b.Length?c:b)

Try it online!

Retina 0.8.2, 99 bytes

$
¶$%`
¶
/¶
m`^~(?=/.*¶)
/home/golfer
^(.*/)(.*¶)\1
$2
\G.*?/
../
1`¶

/¶
¶
O#$`
$.&
1G`
^$
.
^
cd 

Try it online! Takes input on separate lines but link is to test suite that splits on space for convenience. Explanation:

$
¶$%`

Duplicate the last (to) line.

¶
/¶

Append / to the first two (original from and to) lines.

m`^~(?=/.*¶)
/home/golfer

Expand any leading ~ on the first two lines.

^(.*/)(.*¶)\1
$2

Remove any common prefix (ending in /) on the first two lines.

\G.*?/
../

Change any remaining "from" directories to ...

1`¶

Join those ..s with the remaining "to" directories.

/¶
¶

Remove the trailing /.

O#$`
$.&

Sort numerically by length.

1G`

Take the first i.e. shortest string.

^$
.

If it's the empty string then replace it with ..

^
cd 

Prefix cd to the string.

JavaScript (Node.js), 101 bytes

Expects [ current_dir, target_dir ].

a=>'cd '+((s=require('path').relative(...a.map(s=>(q=s).replace(/~/,'/home/@')))||".")[q.length]?q:s)

Try it online!


JavaScript (Node.js), 66 bytes

Expects (current_dir)(target_dir).

Assumes a *nix system where ~ redirects to /home/some_user. On TIO, ~ is /home/runner/~. So this may fail because of that.

a=>b=>'cd '+((s=require('path').relative(a,b)||".")[b.length]?b:s)

Try it online!

Python, 87 bytes

lambda t,s:"cd "+[t,r:=relpath(t:=expanduser(t),s)][len(r)<len(t)];from os.path import*

Attempt This Online!

Expects target, start.

Python 3, 81 bytes

lambda p:'cd '+min(relpath(*map(expanduser,p)),p[0],key=len)
from os.path import*

Try it online!

This utilizes the os.path.relpath function to get a relative path. The shortest path command is either the relative path or the absolute path, whichever is shorter, so the code just checks which using min. expanduser is used to expand the ~ directory to the user's home directory, which doesn't have to be home/golfer to meet the requirements. This is necessary to handle cases with ~ in the path name.