Skip to content
shellmap

lnCreate a hard link or symbolic link to a file or directory across all 5 shells

Equivalents in every shell

Bashunix
ln -s target linkname

`ln source target` creates a HARD LINK (same inode, file content shared, both pointers must be on the same filesystem). `ln -s source target` creates a SYMBOLIC link (a pointer file containing the source path, can cross filesystems, can point to dirs). `-f` overwrites an existing target; `-r` (`--relative`, GNU only) makes a relative symlink from absolute paths.

Zshunix
ln -s target linkname

Same external `/bin/ln`. macOS BSD `ln` lacks GNU's `-r` flag — for relative symlinks compute the path manually or `brew install coreutils` and use `gln -sr`. macOS extended attribute `com.apple.quarantine` is INHERITED through symlinks but NOT through hardlinks.

Fishunix
ln -s target linkname

Same external. Fish has no built-in linker. The argument order is a frequent confusion: `ln -s SOURCE LINK_NAME` — i.e., the link gets created with the second name, pointing at the first. Mnemonic: same order as `cp source destination`.

PowerShellwindows
New-Item -ItemType SymbolicLink -Path linkname -Target target

PowerShell-native (PS 5.0+). `-ItemType SymbolicLink` creates a symlink; `-ItemType HardLink` creates a hard link (FILES only — Windows hard links cannot point to directories). On Windows < 10 build 14972, creating symlinks requires ADMIN privileges; from 14972+ enable Developer Mode for non-admin symlink creation.

cmd.exewindows
mklink linkname target

Built-in (Vista+). `mklink linkname target` creates a SYMBOLIC link to a file; `mklink /D linkname target` for a directory symlink; `mklink /H linkname target` for a hard link (files only); `mklink /J linkname target` for a JUNCTION (similar to dir-symlink but locally only, since NTFS Vista). Note argument order is REVERSED from Unix `ln`: `mklink LINK TARGET` (Windows) vs `ln -s TARGET LINK` (Unix).

Worked examples

Create a symbolic link to a file

Bash
ln -s /opt/app/bin/myapp /usr/local/bin/myapp
PowerShell
New-Item -ItemType SymbolicLink -Path C:\bin\myapp.exe -Target C:\opt\app\bin\myapp.exe
cmd.exe
mklink C:\bin\myapp.exe C:\opt\app\bin\myapp.exe

Create a hard link to a file

Bash
ln original.txt copy.txt
PowerShell
New-Item -ItemType HardLink -Path copy.txt -Target original.txt
cmd.exe
mklink /H copy.txt original.txt

Create a symbolic link to a directory

Bash
ln -s /var/log logs
PowerShell
New-Item -ItemType SymbolicLink -Path .\logs -Target C:\Users\me\AppData\Local\App\Logs
cmd.exe
mklink /D logs C:\Users\me\AppData\Local\App\Logs

Gotchas

  • cmd `mklink` argument order is REVERSED from Unix `ln`. `mklink LINK TARGET` makes the link with name LINK pointing at TARGET; Unix `ln -s TARGET LINK` makes the link with name LINK pointing at TARGET. So the names go in opposite positions. This is the single most common Windows-Unix porting mistake on links.
  • Creating SYMBOLIC links on Windows historically required SeCreateSymbolicLink privilege (admin). Starting Windows 10 build 14972 (Creators Update), enabling DEVELOPER MODE in Settings unlocks non-admin symlink creation. For CI / CD this matters: GitHub Actions Windows runners run as admin and can always make symlinks; local non-admin dev boxes may need Developer Mode enabled.
  • NTFS Junctions (`mklink /J`) and Symlinks (`mklink /D`) BOTH point at directories but are NOT the same. Junctions are an older mechanism, local-only (cannot point to UNC paths), and have different security semantics — non-admins can create junctions on Vista+ without Developer Mode. Symlinks are POSIX-compatible. Prefer `/D` symlinks for new code.
  • Hard links on Windows can ONLY point at files, not directories — same as Linux. Hard links also cannot CROSS volumes (drive letters) — `mklink /H D:\copy.txt C:\orig.txt` ERRORS. Symlinks can cross volumes. On Linux, hardlinks also cannot cross filesystems (mountpoints).
  • A "broken symlink" (target deleted or never existed) is silently valid — `ls -l` shows it red, but `ls -l` alone might miss it. Use `test -e linkname` (true if target exists) or `test -L linkname` (true if it's a symlink, target or not). PowerShell `(Get-Item linkname).Target` returns the link target string; `Test-Path -PathType Leaf linkname` returns true only if the target exists.

WSL & PowerShell Core notes

pwsh`New-Item -ItemType SymbolicLink` works on every pwsh platform. On Linux/macOS pwsh, the system `ln` binary also works for shell-style usage. Cross-platform link creation: `New-Item -ItemType SymbolicLink -Path $link -Target $target` is the most portable PowerShell idiom — same code on Windows, Linux, macOS.
WSLSymlinks inside WSL's native ext4 filesystem behave like Linux symlinks. Symlinks ACROSS the `/mnt/c` boundary (WSL link pointing to a Windows file, or vice-versa) work but with caveats: WSL2 cannot create symlinks on `/mnt/c` paths unless `metadata` is enabled in `/etc/wsl.conf` AND Developer Mode is on in Windows. Without `metadata`, WSL falls back to Win32 lnk-style shortcuts which Linux tools may not recognize.

Related commands