GreenAsJade
GreenAsJade

Reputation: 14685

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

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!

Upvotes: 17

Views: 24254

Answers (8)

pureocean
pureocean

Reputation: 81

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.) ) )

Upvotes: 2

zxcat
zxcat

Reputation: 2114

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
)

Upvotes: 7

andras.tim
andras.tim

Reputation: 2054

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

Upvotes: 23

Ed999
Ed999

Reputation: 3081

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. )

Upvotes: 1

Ed999
Ed999

Reputation: 3081

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.

Upvotes: 2

Hames
Hames

Reputation: 31

This also works:

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

Upvotes: 3

Frank
Frank

Reputation: 71

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

Upvotes: 4

Endoro
Endoro

Reputation: 37569

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

Upvotes: 12

Related Questions