如何在cmd或PowerShell中跟随符号/软链接?

11

我的搜索只告诉我如何在cmd中使用mklink创建符号链接。我看到有些东西说要使用readlink,但PowerShell和cmd不知道readlink是什么,而cd显然也不起作用。那么我该怎么跟随一个符号链接呢?

3个回答

17
为了避免您的问题产生混淆,需要明确一点:
  • Windows shortcut files (*.lnk files), which are a feature of the Windows (GUI) shell, are distinct from symbolic links (symlinks), which are a feature of the (NTFS) filesystem.

  • Shortcut files - which you are interested in - store the path of a file or folder they point to inside the file, which is why:

    • You cannot directly cd to a shortcut file's target folder, because filesystem commands such as cd know nothing about the content of files.
    • You must read the content of the shortcut file to determine its target, which you can then pass to cd or Set-Location (in PowerShell).
    • The file format of shortcut file is a binary one that can be read via an in-box COM component that exposes Windows shell functionality; e.g., to determine the target folder of a shortcut file named Samples.lnk and change to that folder, use PowerShell:

      # NOTE: * Despite the name "CreateShortcut()", the method is also
      #         used to *read* shortcut files.
      #       * Prefixing the filename with "$PWD/" is needed in order
      #         to target a file in the current directory, because
      #         the method doesn't know what PowerShell's current dir. is.
      cd (New-Object -ComObject WScript.Shell).CreateShortcut("$PWD/Samples.lnk").TargetPath
      
  • Symlinks, by contrast:

    • (typically) transparently redirect to their target, i.e., the filesystem item (file or folder) they point to.

    • You can therefore use cd directly with a symlink to a folder, but note that it is still the symlink's path that is shown.

    • To print a symlink's target - akin to what the readlink utility does on Unix-like platforms - use PowerShell; e.g., to print the target of a symlink named Samples in the current directory:

       (Get-Item Samples).Target
      
       # Or, after running `cd Samples`:
       (Get-Item .).Target
      
    • Note that it's not straightforward to get a symlink's target in cmd.exe, but if you use
      dir /al <link-path>*, the listing will also show the link's target path, after the name, enclosed in [...]; note that the trailing * is necessary in order to show information about the link itself, not its target's contents; note that, although unlikely, that may match other links that start with the same path as well.


与快捷方式不同,符号链接在Windows世界中仍然很少见,这主要是因为在Windows 10之前,它们无论如何都需要管理员权限才能创建;在Windows 10中,如果开启开发者模式(由管理员),即使是非管理员用户/非提升进程现在也可以创建符号链接-请参见https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/,其中还解释了为什么符号链接未来可能会越来越常见。


谢谢提供额外信息。你知道如何创建硬链接吗?即使使用管理员权限的命令提示符,我也无法创建它们。我认为这是因为Windows默认将所有文件夹设置为只读。取消只读框只适用于文件夹内的文件。 - Deoxal
@Deoxal:硬链接只能针对 _文件_,所以如果你想要目标是 _文件夹_,那么你需要使用 符号链接 或 _联接点_。我建议使用符号链接,因为它们提供最大的灵活性(它们还可以针对其他卷/机器上的文件夹)。 - mklement0
我想知道如何跟随硬链接。Windows应用程序似乎经常使用它们,例如Windows终端,$env:localappdata\Microsoft\WindowsApps\wt.exe。fsutil似乎会输出二进制代码。 - js2010
@js2010,你不能真正地“跟踪”硬链接,但你可以看到所有其他连接到相同数据的路径。在 Windows PowerShell 中,你只能检查 Get-ChildItem / Get-Item 返回的 .Target 属性(这个属性已从 PowerShell Core 中移除)。 - mklement0
1
我猜重解析点(reparsepoints)是Windows应用程序的一个例外。这些没有目标属性。我发布了一个问题。https://dev59.com/rcTra4cB1Zd3GeqPvw9u - js2010

5

针对您的问题,我制作了这个批处理文件:

mkdir truedir
dir > truedir\fileone.txt
mklink /d symdir truedir
cd symdir
dir

我发现使用命令提示符获取符号链接到目录的内容没有问题。 在PowerShell 5.1(win 10)中也没有问题:

Get-ChildItem C:\Users\<user>\OneDrive\Desktop\test2\symdir

你能提供一个代码示例(批处理或PowerShell都可以),以复制你的问题吗?

1
谢谢你的帮助。我以为.lnk文件是符号链接,但现在我意识到这不是情况。你知道如何跟踪一个.lnk吗?如果不知道,我可以创建实际的符号链接。 - Deoxal
1
请查看此处:https://dev59.com/EqXja4cB1Zd3GeqPOUFd - bdn02
1
谢谢您指引我正确的方向。现在我把术语搞清楚了,应该可以做到了。 - Deoxal

1

好的,我刚刚在另一个类似的问题中发布了这个答案,所以我觉得我也应该在这里发布。我希望这个问题能像其他问题一样在搜索中出现,因为@mklement0的答案很棒。但这是我的解决方案,它能够在PowerShell中跟随嵌套链接到真正的文件或目录(我正在寻找PS特定的解决方案,而不是CMD)。

到目前为止,双cd方法是我能找到的处理文件名和目标中混合相对/绝对路径情况最可靠/通用的方法,并且我测试了几种情况。

function getLinkTarget($fn) {
    $op=$PWD #Save original path
    while($t=(Get-Item $fn).Target) { #Get link target
        cd (Split-Path -Parent $fn) #cd to parent of file/dir
        cd (Split-Path -Parent $t) #cd again to parent of target
        $fn=(Split-Path -Leaf $t) #Set filename to relative target
    }
    $fn=(Join-Path $PWD $fn) #Make path absolute
    cd $op #Change back to original path
    return $fn
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接