It is possible, albeit extremely awkward, to create a symlink in MSYSGIT.
First, we need to make sure we are on Windows. Here's an example function to check that:
windows() { [[ -n "$WINDIR" ]]; }
Now, we can't do cmd /C
, because MSYSGIT will fornicate with this argument and turn it into C:
. Also, don't be tempted to use /K
, it only works if you don't have a K:
drive.
So while it will replace this value on program arguments, it won't on heredocs. We can use this to our advantage:
if windows; then
cmd <<< "mklink /D "${link%/}" "${target%/}"" > /dev/null
else
ln -s "$target" "$link"
fi
Also: note that I included /D
because I'm interested in directory symlinks only; Windows has that distinction. With plenty of effort, you could write a ln() { ... }
function that wraps the Windows API and serves as a complete drop-in solution, but that's... left as an exercise for the reader.
Edit: As a thank-you for the accepted answer, here's a more comprehensive function.
# We still need this.
windows() { [[ -n "$WINDIR" ]]; }
# Cross-platform symlink function. With one parameter, it will check
# whether the parameter is a symlink. With two parameters, it will create
# a symlink to a file or directory, with syntax: link $linkname $target
link() {
if [[ -z "$2" ]]; then
# Link-checking mode.
if windows; then
fsutil reparsepoint query "$1" > /dev/null
else
[[ -h "$1" ]]
fi
else
# Link-creation mode.
if windows; then
# Windows needs to be told if it's a directory or not. Infer that.
# Also: note that we convert `/` to ``. In this case it's necessary.
if [[ -d "$2" ]]; then
cmd <<< "mklink /D "$1" "${2////\}"" > /dev/null
else
cmd <<< "mklink "$1" "${2////\}"" > /dev/null
fi
else
# You know what? I think ln's parameters are backwards.
ln -s "$2" "$1"
fi
fi
}
Also note a few things:
- I just wrote this and briefly tested it on Win7 and Ubuntu, give it a try first if you're from 2015 and using Windows 9.
- NTFS has reparse points and junction points. I chose reparse points because it's more of an actual symlink and works for files or directories, but junction points would have the benefit of being an usable solution in XP, except it's just for directories.
- Some filesystems, the FAT ones in particular, do not support symlinks. Modern Windows versions do not support booting from them anymore, but Windows and Linux can mount them.
Bonus function: remove a link.
# Remove a link, cross-platform.
rmlink() {
if windows; then
# Again, Windows needs to be told if it's a file or directory.
if [[ -d "$1" ]]; then
rmdir "$1";
else
rm "$1"
fi
else
rm "$1"
fi
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…