【问题标题】:Microsoft SQL xp_cmdshell doesn't like filenames with spaces. Can I replace the space with something else?Microsoft SQL xp_cmdshell 不喜欢带有空格的文件名。我可以用其他东西代替空间吗?
【发布时间】:2011-04-06 15:37:32
【问题描述】:

我有这个 TSQL 代码,它使用 BCP 从表中转储数据。它看起来很复杂,但它只是为每个表创建一个要执行一次的@command 字符串,然后 BCP 将表记录转储到磁盘。这是快速备份所有表数据的好方法。下面我展示了一个更容易阅读的解决版本。

set @command = 
  'if (''?'' <> ''[dbo].[sysdiagrams]'') 
   BEGIN;
       create table #result (result nvarchar(2048) null );
       declare @temp nvarchar(1000); 
       set @temp = ''' +  @bcpPath + ' ' + @database + '.dbo.'' + 
           substring( ''?'', 8, len(''?'')- 8) +
           '' out "' + @driveLetter + @drivePath +
           '\'' + substring( ''?'', 8, len(''?'')- 8) + 
           ''.out" -c -x -t"|" -Uuser -Ppassword'';
       insert into #result (result)
       exec xp_cmdshell @temp;
       drop table #result;
   END;'
   exec sp_msforeachtable @command

@bcppathC:\Program Files\Microsoft SQL Server\90\Tools\Binn\bcp.exe,其中有一个空格。

没有在路径"" 周围使用双引号,它会给出'C:\Program' is not recognized... 的错误使用双引号,它会给出相同的错误。使用双双引号"" "",表示The filename, directory name, or volume label syntax is incorrect.

@command 在打印时会解决这个问题:

if ('?' <> '[dbo].[sysdiagrams]') 
BEGIN;
    create table #result (result nvarchar(2048) null );
    declare @temp nvarchar(1000); 
    set @temp = '"C:\Program Files\Microsoft SQL Server\90\Tools\Binn\bcp.exe" 
        myDB.dbo.' + 
        substring( '?', 8, len('?')- 8) +
        ' out "E:\DataExports\' + 
        substring( '?', 8, len('?')- 8) + '.out" -c -x -t"|" -Uuser -Ppassword';
    insert into #result (result)
    exec xp_cmdshell @temp;
    drop table #result;
END;

编辑:

奇怪的是,我在“路径”前面放了一个ECHO ? &amp;&amp;,它起作用了(用双引号括起来。)....为什么?

【问题讨论】:

  • 你的路径中不是 ..\binn 目录吗?
  • 即使是,第二条路径也会杀死它。
  • 可能。如果 xp_cmdshell 在没有路径组件的情况下调用 bcp,例如“bcp myDB.dbo...”,会发生什么?我问 b/c 我们使用 bcp 进行批量加载,它不在乎文件路径在我们的本地或客户端安装中是否有空格。
  • 我真的很想知道为什么 Echo ? && 前置修复它...
  • xp_cmdshell 可以采用多对引号,只是不能在第一个标记中。在这里查看我的答案:stackoverflow.com/questions/3759331/…

标签: sql-server-2005 tsql batch-file xp-cmdshell


【解决方案1】:

你必须在引用路径之前放一些东西以避免错误C:\Program' is not recognized... 所以我使用了 CALL 语句,它对我有用......

declare @cmd nvarchar(1000)

set @cmd = 'call "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\bcp.exe" myDB.dbo.'
exec xp_cmdshell @cmd

【讨论】:

  • 无需将 CALL 附加到命令行参数。只需将文件路径放在双引号中就足够了。所以这应该可以工作:'"C:\Program Files\Microsoft SQL Server\90\Tools\Binn\bcp.exe" myDB.dbo.'
【解决方案2】:

尝试为包含空格的路径部分指定短名称,例如,PROGRA~1 而不是 Program Files。因此,您的第一个路径将类似于 C:\PROGRA~1\MI6841~1\90\Tools\Binn\bcp.exe。如果没有空格,应该可以去掉引号。

如果您在包含长目录/文件名的目录中执行dir /x,您可以获得短 8.3 名称。

【讨论】:

  • +1,但取决于当前系统,下一个系统短名称可以不同
  • 当然,但是(有趣的是)一位同事在他的机器上检查了这个,短名称是相同的。我原以为它们必须有所不同,尤其是 Microsoft SQL Server => MI6841~1,因为我们安装的软件大相径庭。
  • 我想它只取决于安装的顺序,因为短名称(也是长名称)是在创建时存储的
  • 嘿,看看这个(来自Wikipedia) - #4 从 Windows 2000 开始,如果至少有 4 个文件或文件夹已经存在,它们的短名称中有相同的前 6 个字符,则剥离的 LFN 是而是截断为基本名称的前 2 个字母(如果基本名称只有 1 个字母,则为 1),后跟 4 个从文件名的未记录哈希派生的十六进制数字,后跟波浪号,后跟单个数字,后跟句点“.”,后跟扩展名的前 3 个字符。你每天都能学到新东西。
  • 我不知道,前段时间我为嵌入式系统上的胖驱动程序添加了长文件名支持(但仅用于阅读)。
【解决方案3】:

作为解决方法,您可以使用subst

subst p: "C:\Program Files\Microsoft SQL Server\"

所以您不再需要间隔路径。

或者您尝试找出失败的原因。

exec xp_cmdshell 'cmd /c echo %cmdcmdline% "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\bcp.exe"'

cmdcmdline 应该向您显示完整的命令,如果引号已经存在,这应该可以工作

exec xp_cmdshell 'cmd /c "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\bcp.exe" <the rest of your command>'

【讨论】:

    【解决方案4】:

    这种奇怪的结构也有效:

    exec xp_cmdshell '""%ProgramFiles%\WinRAR\"rar.exe a -v20M "C:\test\test.rar" "C:\test\data\""'
    

    【讨论】:

      猜你喜欢
      • 2018-10-28
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-13
      • 2012-07-06
      相关资源
      最近更新 更多