How do I use the DOS Command dir in T-SQL
Well, the short answer is you don't. The modified answer is that you can use the code listed in this post. The longer answer is that you can use xp_cmdshell to do this (Which is what the stored procedure in this post does), and must be either a member of the sysadmin account, or granted execution, say to a new role, and users can be placed in that role.
There is a caveat to that. From Books Online:
Execute permissions for xp_cmdshell default to members of the sysadmin fixed server role, but can be granted to other users.
Important If you choose to use a Windows NT account that is not a member of the local administrator's group for the MSSQLServer service, users who are not members of the sysadmin fixed server role cannot execute xp_cmdshell.
Also, the long and short of it is, that having to build it, then to parse out the data, and to worry about security measures, I thought it might be a good idea just to create a stored procedure. Now I'm sure someone may have done this already, but I thought I'd give it a shot. This makes looking at your directories as easy as issuing the command EXEC Dir 'C:\*.*'. Well you say, why not just do EXEC xp_cmdshell 'Dir C:\*.*'. Well for one, you won't have to grant your developers access to xp_cmdshell, so you gain more control. A developer could reak havoc with your server. I've seen it. Also, the information is now in a usable format. Your developers can now call this stored procedure and place the results in to a table, or, (since it's all done with smoke and mirrors), they can access the underlying directory table. As an afterthought, there are several commands that can be turned in to this type of functionality, and you can specialize them to “extend“ dos commands. Currently I'm working on an archiving sproc that will make an archive directory for a directory supplied. The idea is that when I'm done with all the files in my processing directory, I will move everything to the archive, so as to clean out the directory for the next processing cycle. I'll post that when it's done.
One additional caveat is that this is Windows 2000 Server and up. Windows NT produced different ouput results from the dir dos command. If you need the old structure, let me know and I can post it. I know there's away around this, I'm just not sure at the moment on how to do this. If anyone remembers, I'd like to know. Again thanks for reading.
Here's the code, and good luck.
CREATE TABLE [dbo].[Directory_Contents_Stage] (
[dir] varchar(255)
, [dir_output] varchar(255)
)
GO
CREATE TABLE [dbo].[Directory_Contents] (
[dir] varchar(255)
, [Create_Time] datetime
, [File_Size] int
, [File_Name] varchar(255)
, [Struct_Type] char(9)
)
GO
CREATE PROC Dir(@path varchar(2000), @Supress int = 0)
AS
SET NOCOUNT ON
TRUNCATE TABLE Directory_Contents_Stage
DECLARE @cmd varchar(4000)
SELECT @cmd = 'Dir "' + @path + '"'
INSERT INTO Directory_Contents_Stage(dir_output) EXEC master..xp_cmdshell @cmd
IF EXISTS (SELECT * FROM Directory_Contents_Stage
WHERE dir_output = 'The system cannot find the file specified.')
BEGIN
PRINT 'The system cannot find the file specified.'
GOTO Dir_Error
END
IF EXISTS (SELECT * FROM Directory_Contents_Stage
WHERE dir_output = 'File Not Found')
BEGIN
PRINT 'File Not Found'
GOTO Dir_Error
END
IF EXISTS (SELECT * FROM Directory_Contents_Stage
WHERE dir_output = 'The system cannot find the path specified.')
BEGIN
PRINT 'The system cannot find the path specified.'
GOTO Dir_Error
END
UPDATE Directory_Contents_Stage SET [dir] = @path
DELETE FROM Directory_Contents WHERE [dir] = @path
INSERT INTO Directory_Contents (Create_Time, File_Size, [File_Name], [dir], [Struct_Type])
SELECT CONVERT(datetime,SUBSTRING(dir_output,1,20)) AS [Create_Time]
, CONVERT(int,LTRIM(RTRIM(REPLACE(SUBSTRING(dir_output,21,19),',','')))) AS [File_Size]
, SUBSTRING(dir_output,40,(LEN(dir_output)-39)) AS [File_Name]
, [dir]
, 'FILE'
FROM Directory_Contents_Stage
WHERE SUBSTRING(dir_output,1,1) <> ' '
AND (SUBSTRING(dir_output,1,1) <> ' '
AND SUBSTRING(dir_output,25,5) <> CHAR(60)+'Dir'+CHAR(62))
INSERT INTO Directory_Contents (Create_Time, [File_Name], [dir], [Struct_Type])
SELECT CONVERT(datetime,SUBSTRING(dir_output,1,20)) AS [Create_Time]
, SUBSTRING(dir_output,40,(LEN(dir_output)-39)) As [File_Name]
, [dir]
, CHAR(60)+'Dir'+CHAR(62) AS [Struct_Type]
FROM Directory_Contents_Stage
WHERE SUBSTRING(dir_output,25,5) = CHAR(60)+'Dir'+CHAR(62)
IF @Supress = 0
SELECT [dir], Create_Time, File_Size, [File_Name], [Struct_Type]
FROM Directory_Contents
WHERE [dir] = @path
ORDER BY [Struct_Type] DESC, [Create_Time] DESC
GO
SET NOCOUNT OFF
Dir_Exit:
SET NOCOUNT OFF
RETURN
Dir_Error:
-- Add Error Handling
GOTO Dir_Exit
GO
EXEC Dir 'C:\*.*'
GO
DROP PROC Dir
GO
DROP TABLE Directory_Contents, Directory_Contents_Stage
GO
Legacy Comments
robvolk
2005-06-29 |
re: How do I use the DOS Command dir in T-SQL I've got one here that might simplify this process a little: http://weblogs.sqlteam.com/robv/articles/4107.aspx You get a lot more control over the formatting of the directory output, and a little DOS redirection would allow you to use bcp or BULK INSERT too. |
Brett Kaiser
2005-06-30 |
Thanks Rob Thanks Rob, but how does that get the information into a table so you can utilize inside of T-SQL. For example, I just finished an Archive stored procedure that utilizes the Dir stored procedure. It get's called in the stored procedure and checks for the existance of the files, then it will Archive everything in that existing directory, by adding a new timestamped Archive folder. Do you just bcp the echoed results in? |
robvolk
2005-06-30 |
re: How do I use the DOS Command dir in T-SQL Yeah, you can bcp or BULK INSERT the echo'd results, or just INSERT...EXEC like the current proc does and parse it. It's easier in the fact that you don't have to deal with the differences in DIR output that varying operating systems have. Another nicety is that FOR can recurse directories and present the full path and file information, which DIR cannot. |
Brett Kaiser
2005-07-01 |
re: How do I use the DOS Command dir in T-SQL Rob, I get an error. What am I doing wrong here. This EXE master..xp_cmdshell 'for %a in (*.*) do @echo %a,%~za,%~tam' Produces Server: Msg 170, Level 15, State 1, Line 1 Line 1: Incorrect syntax near '.'. Got an example? |
robvolk
2005-07-02 |
re: How do I use the DOS Command dir in T-SQL You, ummmmm, spelled "EXEC" wrong. :) |
Brett Kaiser
2005-07-06 |
re: How do I use the DOS Command dir in T-SQL Good lord EXEC master..xp_cmdshell 'for %a in (*.*) do @echo %a,%~za,%~tam' It seems like it finding ALL files, not just the ones in the root. Also since the data comes out in csv format, you'd probably need to use a function instead of just having to use substring. Plus there are no directory info there... |
robvolk
2005-07-06 |
re: How do I use the DOS Command dir in T-SQL You can modify the variable to include drive letter, path, etc., like so: echo %~dpnxa,%~za,%~tam And you can choose another character to delimit each section, not just a comma. And if you changed the output a little, you could format it as a fixed-width line that you can parse easily...it all depends on exactly what you need. All of these modfiers and examples are in the Windows help file. |
Rashed Ahmed
2005-08-30 |
re: How do I use the DOS Command dir in T-SQL I want to more about Dos-command. |
Raj
2005-08-30 |
re: How do I use the DOS Command dir in T-SQL edit |
Greg Milner
2005-10-12 |
re: How do I use the DOS Command dir in T-SQL Brett, Do you mind if I site this entry on my blog (with full credit to you of course) ? Thanks. |
Brett
2005-10-12 |
But of Course Why no, but of course.....at least someone will post a reference and a link http://weblogs.sqlteam.com/brettk/archive/2005/08/11/7516.aspx Thanks Brett P.S. Please post a link of your blog here for circular references ;-) |