| Bytes | Lang | Time | Link |
|---|---|---|---|
| 148 | JavaScript Node.js | 250601T174558Z | l4m2 |
| 055 | 05AB1E | 221128T140436Z | Kevin Cr |
| 066 | C# Visual C# Interactive Compiler | 221130T160537Z | jdt |
| 099 | Retina 0.8.2 | 221129T001958Z | Neil |
| 101 | JavaScript Node.js | 221128T172534Z | Arnauld |
| 087 | Python | 221128T175906Z | corvus_1 |
| 081 | Python 3 | 221128T180545Z | Joe |
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)
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)
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)
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)
Python, 87 bytes
lambda t,s:"cd "+[t,r:=relpath(t:=expanduser(t),s)][len(r)<len(t)];from os.path import*
Expects target, start.
Python 3, 81 bytes
lambda p:'cd '+min(relpath(*map(expanduser,p)),p[0],key=len)
from os.path import*
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.