batch file (windows cmd.exe) test if a directory is a link (symlink)
Asked Answered
C

8

15

I learned just now that this is a way to test in a batch file if a file is a link:

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

How can I do a similar trick for testing if a directory is a symlink. It doesn't work to just replace <SYMLINK> with <SYMLINKD>, because dir %directoryname% lists the contents of the directory, not the directory itself.

It seems like I need some way to ask dir to tell me about the directory in the way that it would if I asked in the parent directory. (Like ls -d does in unix).

Or any other way of testing if a directory is a symlink?

Thanks!

Carabiniere answered 18/9, 2013 at 23:17 Comment(0)
E
12

general code:

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

figure out, if the current folder is a symlink:

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

figure out, if the parent folder is a symlink:

fsutil reparsepoint query ".." | find "Symbolic Link" >nul && echo symbolic link found || echo No symbolic link
Euton answered 19/9, 2013 at 0:57 Comment(4)
Sweet, thanks - it was really helpful to have the general and some specific examples, and I just found out that there is fsutil ... some more learning to do!Carabiniere
This will only work with English-language Windows. For some reason MS loves to localize command-line strings... The fix is just don't use find (no need to, the errorlevel is enough).Neurogenic
I always make my answers here for a specific question by a specific user. A batch file/cmd line is never the solution for all similar questions. Moreover, this is not a Windows specific issue, you can localise Linux as well.Euton
Nice... how to detect if one of the folders in path is a SymLink... not only the immediate parent... but any ancestor folder ???Transubstantiate
L
22

You have three methods

Solution 1: fsutil reparsepoint

Use symlink/junction with fsutil reparsepoint query and check %errorlevel% for success, like this:

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

This works, because fsutil reparsepoint query can't do anything on a standard directory and throws an error. But the permission error causes %errorlevel%=1 too!

Solution 2: dir + find

List links of the parent directory with dir, filter the output with find and check %errorlevel% for success, like this:

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

Solution 3: for (the best)

Get attributes of the directory with for and check the last from it, because this indicates links. I think this is smarter and the best solution.

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

FYI: This solution is not dependent on %errorlevel%, so you can check "valid errors" too!

Sources

Lightly answered 9/3, 2014 at 14:5 Comment(4)
Regarding solution 3: it's actually not the last, but the 9th character - %attribs:~8,1%. Eleven characters are returned in total on Windows 8.1.Demonetize
For solution 1, to not run into the invalid error problem, verify with findstr as such: fsutil reparsepoint query scripts 2>&1 | findstr /r "^Tag\ Value:\ Symbolic\ Link$" > /nulSuppositive
@setempler, I think triggering on the exit code is much stable thing, then parse the human-readable output. In other hands, you can redirect the STDERR to /nul w/ my solution also.Lightly
solution 3's IF statement with @Demonetize 's addition fails, as if the comparand is not expanded.Darb
E
12

general code:

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

figure out, if the current folder is a symlink:

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

figure out, if the parent folder is a symlink:

fsutil reparsepoint query ".." | find "Symbolic Link" >nul && echo symbolic link found || echo No symbolic link
Euton answered 19/9, 2013 at 0:57 Comment(4)
Sweet, thanks - it was really helpful to have the general and some specific examples, and I just found out that there is fsutil ... some more learning to do!Carabiniere
This will only work with English-language Windows. For some reason MS loves to localize command-line strings... The fix is just don't use find (no need to, the errorlevel is enough).Neurogenic
I always make my answers here for a specific question by a specific user. A batch file/cmd line is never the solution for all similar questions. Moreover, this is not a Windows specific issue, you can localise Linux as well.Euton
Nice... how to detect if one of the folders in path is a SymLink... not only the immediate parent... but any ancestor folder ???Transubstantiate
T
6

Update: this solved my problem, but as commenters noted, dir will show both directory symlinks and directory junctions. So it's wrong answer if junctions are there.


Simple dir /A:ld works fine

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  

Note that to execute a command only for non-link folders, you can use the attribute negation form:

for /F "usebackq" %%D in (`dir /A:D-L /B some-folder`) do (
    some-command some-folder\%%D
)
Trinl answered 16/11, 2016 at 16:32 Comment(3)
Not that as it stands this isn't an answer to the question, because it doesn't test whether a directory is a symlink, it simply lists those that are. To answer the question, you'd need to elaborate on how to test the result. Out of interest, what is a "reparse point"?Carabiniere
A reparse point is any file symlink, or directory symlink, or directory junction: all of which will (if present) be listed by the DIR A:L command.Remiss
@Ed999, ok, I see, thanks. I used this without junctions, so it worked fineTrinl
A
4

Actually, DIR works fine if you append an asterisk to the filename, thus:

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

GreenAsJade called my attention to this solution's failure when there is another entry in the directory that matches %filename%*. I believe the following wiull work in all cases:

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
Acquah answered 29/10, 2014 at 22:38 Comment(8)
What if there are other files in the directory that match %filename%*?Carabiniere
It would still work if there were such files because they would not return "<SYMLINKD>". It would fail if there was another directory symbolic link that matched %filename%*.Acquah
You have done me a favor by bringing this up because the file I am writing would fail due to this problem, and I had not thought about it. As far as I can tell, the following works in all cases: 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! PauseAcquah
Sorry about the terrible formatting. The five-minute window for editing timed out before I got it figured out.Acquah
Maybe put that new info in the actual answer :)Carabiniere
What if <SYMLINKD> is part of a non-symlink filename? This will also fail.Marhtamari
<SYMLINKD> cannot be part of a file or folder name because "<" and ">" are not legal in file and folder names.Acquah
Surely a more practical approach is to specify a directory and search its entire contents, listing all symbolic links or junctions that are present in it - see my proposed batch file solution elsewhere on this page. You are then searching potentially dozens of files at once. There would also, then, be no possibility of conflicting duplicate filenames, since the NTFS file system excludes that possibility.Remiss
H
3

This also works:

dir /al|find /i "java"|find /i "junction" && ( echo directory is a symlink )

Helbonia answered 2/12, 2014 at 21:28 Comment(0)
R
2

The appropriate DIR command is shown in the following batch file (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.
Remiss answered 20/1, 2017 at 20:20 Comment(0)
R
1

An alternative approach is to treat each of the three types of reparse point separately, in the following batch file (reparse2.bat), which can be easily modified to search only for the type of link you are interested in -

  ::  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. )
Remiss answered 20/1, 2017 at 20:25 Comment(0)
C
1

A simple example script for Windows 10.

Info: If it exist as SymLink in %localappdata%\MegaDownloader folder, execute MegaDownloader.exe. If it doesn't exist as a SymLink in %localappdata%\MegaDownloader, use mklink to create SymLink PortableData path of current folder to %localappdata%\MegaDownloader, then runs 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"

OR

For symbolic and/or directory check, this commands is more robust:

set CheckFolder=D:\ExampleFolder

FOR /f "delims=<> tokens=2" %g in ('dir %CheckFolder%* ^| find "<"') do ( IF %g==DIR (echo %CheckFolder% is real a directory.) ELSE (IF %g==JUNCTION (echo %CheckFolder% is a SymbolicLink/Junction.) ) )

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

(IF NOT EXIST "%SymLinkDir%" (echo But the junction's target directory ^("%SymLinkDir%"^) is not existed!) ELSE ( IF EXIST "%SymLinkDir%" (echo And the junction's target directory ^("%SymLinkDir%"^) is existed.) ) )

Corrode answered 16/7, 2020 at 11:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.