批处理文件(Windows cmd.exe)测试目录是否为链接(符号链接)

15

我刚刚学到一种方法,可以在批处理文件中测试文件是否为链接:

dir %filename% |  find "<SYMLINK>" && (
   do stuff
)

如何测试一个目录是否是符号链接?我该如何进行类似的测试呢?仅仅将 <SYMLINK> 替换为 <SYMLINKD> 是行不通的,因为 dir %directoryname% 列出的是目录的内容而非目录本身。

看起来我需要一些方法来让 dir 以与在父目录中询问时相同的方式告诉我有关该目录的信息。 (就像 Unix 中的 ls -d 命令一样)。

或者还有其他测试目录是否为符号链接的方法吗?

谢谢!

8个回答

22

你有三种方法

解决方案1:fsutil reparsepoint

使用符号链接/连接点和fsutil reparsepoint query,并检查%errorlevel%以获得成功,像这样:

set tmpfile=%TEMP%\%RANDOM%.tmp

fsutil reparsepoint query "%DIR%" >"%tmpfile%"
if %errorlevel% == 0 echo This is a symlink/junction
if %errorlevel% == 1 echo This is a directory

这个方法可行,因为fsutil reparsepoint query无法对普通目录进行操作,并会报错。但是权限错误也会导致%errorlevel%=1

解决方案2:dir + find

使用dir列出父目录的链接,用find过滤输出并检查%errorlevel%是否成功,例如:

set tmpfile=%TEMP%\%RANDOM%.tmp

dir /AL /B "%PARENT_DIR%" | find "%NAME%" >"%tmpfile%"
if %errorlevel% == 0 echo This is a symlink/junction
if %errorlevel% == 1 echo This is a directory

解决方案3:使用for循环(最佳)

使用for循环获取目录的属性,并检查其中的最后一个,因为这表示链接。我认为这是更智能和最佳的解决方案。

for %i in ("%DIR%") do set attribs=%~ai
if "%attribs:~-1%" == "l" echo This is a symlink/junction

注意:此解决方案不依赖于%errorlevel%,因此您也可以检查“有效错误”!

来源


关于解决方案3:实际上不是最后一个字符,而是第9个字符 - %attribs:~8,1%。在Windows 8.1上总共返回11个字符。 - CodeManX
对于解决方案1,为了避免出现“无效错误”问题,请使用以下命令进行验证:fsutil reparsepoint query scripts 2>&1 | findstr /r "^Tag\ Value:\ Symbolic\ Link$" > /nul - setempler
1
@setempler,我认为根据退出代码触发比解析人类可读输出更稳定。另一方面,你也可以使用我的解决方案将 STDERR 重定向到 /nul - andras.tim
方案3的IF语句加上@CodeManX的内容失败了,好像比较对象没有被展开。 - Unknow0059

12

通用代码:

fsutil reparsepoint query "folder name" | find "Symbolic Link" >nul && echo symbolic link found || echo No symbolic link

判断当前文件夹是否是符号链接:

fsutil reparsepoint query "." | find "Symbolic Link" >nul && echo symbolic link found || echo No symbolic link

判断父文件夹是否为符号链接:


fsutil reparsepoint query ".." | find "Symbolic Link" >nul && echo symbolic link found || echo No symbolic link

太好了,谢谢 - 有一般和一些特定的例子真的很有帮助,我刚刚发现还有fsutil...还有更多需要学习的东西! - GreenAsJade
5
这只能在英文版的Windows上运行。由于某种原因,微软喜欢本地化命令行字符串... 解决方法就是不使用 find 命令(没有必要,errorlevel 已经足够)。 - Camilo Martin
我在这里总是根据特定用户的特定问题提供答案。批处理文件/cmd命令行绝不是适用于所有“类似”问题的解决方案。此外,这不仅限于Windows,你也可以将其应用于Linux系统。 - Endoro
很好...如何检测路径中的一个文件夹是否是符号链接...不仅是直接父文件夹...还包括任何祖先文件夹??? - ZEE

6

更新: 这个方法解决了我的问题,但是评论者指出,dir 命令会显示目录符号链接和目录联接。如果有联接,则该方法是错误的。


简单的 dir /A:ld 命令可以正常工作。

dir /?:

DIR [drive:][path][filename] [/A[[:]attributes]] …

/A          Displays files with specified attributes.  
attributes   D  Directories                R  Read-only files  
             H  Hidden files               A  Files ready for archiving  
             S  System files               I  Not content indexed files  
             L  Reparse Points             -  Prefix meaning not  

请注意,要仅针对非链接文件夹执行命令,可以使用属性否定形式:
for /F "usebackq" %%D in (`dir /A:D-L /B some-folder`) do (
    some-command some-folder\%%D
)

1
不过就目前而言,这并不是问题的答案,因为它并没有“测试”一个目录是否是符号链接,它只是列出了那些是符号链接的。要回答这个问题,你需要详细说明如何测试结果。顺便问一下,“重分析点”是什么? - GreenAsJade
“重解析点”是指任何文件符号链接,目录符号链接或目录联接点:如果存在,则可以通过DIR A:L命令列出所有这些内容。 - Ed999
@Ed999,好的,我明白了,谢谢。我没有使用连接点,所以它运行得很好。 - zxcat

4

其实,如果在文件名后面加上星号,DIR命令就可以正常工作,示例如下:

dir %filename%* |  find "<SYMLINKD>" && (
   do stuff
)

GreenAsJade提到了当目录中有另一个与%filename%*匹配的条目时,此解决方案会失败。我相信以下内容适用于所有情况:

set MYPATH=D:\testdir1
set FILENAME=mylink
set FULL=%MYPATH%\%FILENAME%
set SP1=0
for /f "tokens=4,5 delims= " %%A IN ('dir /L /N %FULL%*') do (
    if %%B EQU %FILENAME% (
    if "%%A" EQU "<SYMLINKD>" set SP1=1
    )
)
if %sp1% EQU 0 echo It's not there.
if %sp1% EQU 1 echo BINGO!
Pause

如果目录中有其他与%filename%*匹配的文件怎么办? - GreenAsJade
如果存在这样的文件,它仍然可以工作,因为它们不会返回“<SYMLINKD>”。如果有另一个目录符号链接与%filename%*匹配,则会失败。 - Frank
你提出了一个帮助,让我受益匪浅。因为我正在编写的文件由于这个问题而失败,而我之前没有考虑到它。据我所知,以下内容在所有情况下都有效: set MYPATH=D:\testdir1 set FILENAME=mylink
set FULL=%MYPATH%%FILENAME% set SP1=0
for /f "tokens=4,5 delims= " %%A IN ('dir /L /N %FULL%*') do ( if %%B EQU %FILENAME% ( if "%%A" EQU "<SYMLINKD>" set SP1=1 ) ) if %sp1% EQU 0 echo 它不存在。 if %sp1% EQU 1 echo 找到了! 暂停
- Frank
抱歉格式很糟糕。我还没搞清楚,在五分钟的编辑窗口时间内就超时了。 - Frank
也许把那个新信息放在实际答案中 :) - GreenAsJade
显示剩余3条评论

3
这也可以实现:

dir /al|find /i "java"|find /i "junction" && ( echo 目录是符号链接 )


2
适当的DIR命令在以下批处理文件(reparse.bat)中显示 -
  ::  Specify the Directory to search
  SET directory=C:\Users\%username%\Desktop\TEST1

  ::  Results Text
  echo SEARCH OF DIRECTORY FOR REPARSE POINTS & echo.

  ::  List files with ATTRIBUTE L (Reparse Points)
  DIR "%directory%" /A:L

  echo. && echo  Notes - && echo.
  echo  There are 3 types of Reparse points: && echo.
  echo  ^<JUNCTION^> is a Directory Junction
  echo  ^<SYMLINKD^> is a Directory SymLink
  echo  ^<SYMLINK^>  is a File SymLink
  echo. && echo.

1

另一种方法是将三种重解析点类型分别处理,使用以下批处理文件(reparse2.bat),可以轻松修改以仅搜索您感兴趣的链接类型 -

  ::  Directory to Search
  SET directory=C:\Users\%username%\Desktop\TEST1

  ::  Results Text
  echo SEARCH OF DIRECTORY: %directory% & echo.

  ::  Find FILE SymLinks in directory
  dir "%directory%" | find "<SYMLINK>" && (
    echo This is a SymLink FILE
  ) && ( echo. )

  ::  Find DIRECTORY SymLinks in directory
  dir "%directory%" | find "<SYMLINKD>" && (
    echo This is a SymLink DIRECTORY
  ) && ( echo. )

  ::  Find JUNCTIONS in directory
  dir "%directory%" | find "<JUNCTION>" && (
    echo This is a Directory JUNCTION
  ) && ( echo. ) && ( echo. )

1

一个适用于Windows 10的简单示例脚本。

信息:如果在%localappdata%\MegaDownloader文件夹中以SymLink存在,执行MegaDownloader.exe。如果它不作为%localappdata%\MegaDownloader中的SymLink存在,则使用mklink创建当前文件夹的PortableData路径到%localappdata%\MegaDownloader,然后运行MegaDownloader.exe

fsutil reparsepoint query "%localappdata%\MegaDownloader" | find "Substitute" >nul && GOTO MD || mklink /D /J "%localappdata%\MegaDownloader" "%cd%\PortableData" >nul 2>&1
    
:MD
"%~dp0\MegaDownloader.exe"

或者

对于符号和/或目录检查,这个命令更加健壮:

set CheckFolder=D:\ExampleFolder

FOR /f "delims=<> tokens=2" %g in ('dir %CheckFolder%* ^| find "<"') do ( IF %g==DIR (echo %CheckFolder% 是一个真实的目录。) ELSE (IF %g==JUNCTION (echo %CheckFolder% 是一个符号链接/联接点。) ) )

FOR /F "tokens=3*" %s IN ('fsutil reparsepoint query "%CheckFolder%" ^| findstr /ic:"Print Name:"') do SET "SymLinkDir=%s"

(如果"%SymLinkDir%"不存在(echo 但是该联接点的目标目录("%SymLinkDir%")不存在!)否则(如果"%SymLinkDir%"存在(echo 并且该联接点的目标目录("%SymLinkDir%")存在。)))


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