问题
我试图从C#代码中运行7z来提取一些文件。该命令在Windows下工作,或者如果我只是从shell直接运行它,而不是从代码运行它。也许并不完全一样,我没有意识到。
所以我这样做:
//Unpack dump with 7z
StringBuilder argument = new($"\"{Config.zipPath}\" x \"{dumpPath}\" -so | \"{Config.zipPath}\" x -y -si -ttar");
foreach (string file in new[] { "vn", "vn_titles" /* and other strings */ }) {
argument.Append($" db/{file} db/{file}.header");
}
Process.Start(Config.shell, string.Format(Config.arguments, argument)).WaitForExit();
配置文件是加载到静态Config
类中的键=值对的列表。它适用于Windows:
shell=cmd.exe
zipPath=C:/Program Files/7-Zip-Zstandard/7z.exe
arguments=/C "{0}"
但不适用于Linux:
shell=ash
zipPath=7z
arguments=-c '{0}'
ash命令失败,出现错误:x: line 0: syntax error: unterminated quoted string
我试过/检查过的一些东西
- C#代码运行没有错误,至少直到它需要访问不存在的解压缩文件。
Config.shell
是ash
string.Format(Config.arguments, argument)
是-c '"7z" x "dump.tar.zst" -so | "7z" x -y -si -ttar db/vn db/vn.header db/vn_titles db/vn_titles.header db/releases db/releases.header db/releases_titles db/releases_titles.header db/releases_vn db/releases_vn.header db/vn_length_votes db/vn_length_votes.header db/tags db/tags.header db/tags_parents db/tags_parents.header db/tags_vn db/tags_vn.header'
- 基于前面的两点,我假设执行的命令是这两个命令的串联,即
ash -c '"7z" x "dump.tar.zst" -so | "7z" x ... '
,并且手动运行该命令可以按预期工作。所以我真的很难弄清楚问题出在哪里。
非理想解
knittl提供的答案应该是正确的,据我所知。无论是Windows还是Linux,shell都应该使用两个参数来调用--c
(或/C
,用于Windows的cmd
),然后是我想要运行的命令,正确的是argument
字符串。这通常是最简单的方法。但它在Windows下不起作用。cmd
似乎根本不支持\C
参数中的路径名中的空格。不将它们括在引号中将无法将它们识别为单个字符串,而将它们括在引号中将使路径无效,因为引号不是路径的一部分。powershell
没有这个问题,但是-c
的参数限制为256个字符,这也使得我的命令无法使用。
因此,解决方案是通过Environment.OSVersion.Platform
检测我在哪个操作系统上,并将参数作为Unix的字符串数组传递,或者使用Win32 NT的cmd /C
命令的特殊功能,如果命令的第一个字符是"
,它实际上不会解析整个命令,但是如果它也是一个"
的话,只去掉它和最后一个字符,这样我就不用在命令中转义这些字符了,这是我最初的版本能够工作的唯一原因。
1条答案
按热度按时间yr9zkbsy1#
-c '...'
必须是两个参数(-c
和引号内的任何参数)。我不确定Process.Start(string, string)
重载是如何将第二个参数分割成命令行参数的,但从你的问题来看,它似乎没有像一个(或你的shell)所期望的那样分割它们:)你想调用重载
Start(string, IEnumerable<string>)
: