如何在 'xp_cmdshell' DIR 命令中使用超过 128 个字符的路径

How to use path having more than 128 character in 'xp_cmdshell' DIR command

我正在尝试使用 SQL 超过 128 个字符的服务器路径获取目录中的文件列表。它不起作用。

DECLARE 
@FilePath varchar(256)='D:\...',--Path with a length more than 128 char

@SourceFiles varchar(100)='Test123456789*.txt',
@Query varchar(1000)

If Object_Id('tempdb.dbo.#FirstTable') Is NULL
    CREATE TABLE #FirstTable (Name varchar(256))

SET QUOTED_IDENTIFIER ON
SET @Query ='master.dbo.xp_cmdshell "dir '+ @FilePath + '\' + @SourceFiles +' /b"'

INSERT #FirstTable exec (@Query)
select * from #FirstTable

truncate table #FirstTable

这会产生以下错误:

The identifier that starts with 'dir D:....' is too long. Maximum length is 128.

这个问题的关键是报错信息的写法(重点加了):

The identifier that starts with

标识符是SQL服务器中的对象或项目的名称,不是文字字符串。例如masterdboxp_cmdshell都是标识符。

所以,你有两个选择:

简单修复(但不是最佳实践)

标识符的问题是指向 SET QUOTED_IDENTIFIER ON 行的线索。只需将 ON 更改为 OFF 即可。但是,如果路径 and/or 文件名模式中存在 space(例如 C:\Program Files (x86)\),您将收到错误消息。

最佳实践修复(仍然很简单)

在 shell 命令周围使用单引号而不是双引号。由于您是在 Dynamic SQL 中创建命令,因此在两个实例中它都需要是两个单引号。所以,...xp_cmdshell ''dir ... /b''...

如果路径本身有任何spaces,那么你需要在路径周围加上双引号:...xp_cmdshell ''dir "..." /b''...

因此,完整语法为:

SET @Query ='master.dbo.xp_cmdshell ''dir "'+ @FilePath + '\' + @SourceFiles +'" /b''';

将它放入完整的原始代码中,连同一个长路径名和一个额外的 SELECTPRINT 以查看发生了什么,您将得到:

DECLARE @FilePath varchar(256)='C:\Users\Solomon\AppData\Local\Microsoft\HelpViewer2.0\TableOfContentsFilterCache\VisualStudio11\en-US',--Path with a length more than 128 char
@SourceFiles varchar(100)='this_is_a_long_file_name.*',
@Query varchar(1000);

IF (OBJECT_ID(N'tempdb.dbo.#FirstTable') IS NULL)
BEGIN
    CREATE TABLE #FirstTable (Name VARCHAR(256));
END;

SET QUOTED_IDENTIFIER ON;
SET @Query ='master.dbo.xp_cmdshell ''dir "'+ @FilePath + '\' + @SourceFiles +'" /b''';

SELECT LEN(@FilePath + '\' + @SourceFiles);
PRINT @Query;

INSERT #FirstTable EXEC(@Query);
  SELECT * FROM #FirstTable;

运行 没有错误。 @Query 的值显示在 "Messages" 选项卡中,呈现为:

master.dbo.xp_cmdshell 'dir "C:\Users\Solomon\AppData\Local\Microsoft\HelpViewer2.0\TableOfContentsFilterCache\VisualStudio11\en-US\this_is_a_long_file_name.*" /b'

现在,在我建议的更改之前,出现了一个错误。原始代码的输出(具有相同的测试值)是:

"Results" 选项卡:

129

"Messages" 选项卡:

master.dbo.xp_cmdshell "dir C:\Users\Solomon\AppData\Local\Microsoft\HelpViewer2.0\TableOfContentsFilterCache\VisualStudio11\en-US\this_is_a_long_file_name.* /b"

Msg 103, Level 15, State 4, Line 1
The identifier that starts with 'dir C:\Users\Solomon\AppData\Local\Microsoft\HelpViewer2.0\TableOfContentsFilterCache\VisualStudio11\en-US\this_is_a_long_file_n' is too long. Maximum length is 128.

为了好玩,我创建了一个目录 C:\Temp\Temporary folder with an unecessarily long name just to be an example etc etc\Temporary folder with an unecessarily long name just to be an example etc etc(163 个字符)并在其中放置了一堆 test*.txt 个文件。

以下脚本不存在您描述的问题。

DECLARE @file_path NVARCHAR(256)='C:\Temp\Temporary folder with an unecessarily long name just to be an example etc etc\Temporary folder with an unecessarily long name just to be an example etc etc';
PRINT LEN(@file_path); -- prints 163
DECLARE @src_files NVARCHAR(100)='test*.txt';
DECLARE @dir_cmd NVARCHAR(4000)='DIR "'+@file_path+'\'+@src_files+'" /b';

CREATE TABLE #dir_table(name NVARCHAR(256));
INSERT INTO #dir_table(name) EXEC xp_cmdshell @dir_cmd;

SELECT*FROM #dir_table; -- result is a bunch of test*.txt files
DROP TABLE #dir_table;