跨平台,安全使用命令行字符串分隔符

Cross-platform, safe to use command line string separator

对于 PyInstaller 中的新功能,我们需要一个命令行选项来接收其中包含任何分隔符的字符串。这是讨论:https://github.com/pyinstaller/pyinstaller/pull/1990.

示例:

pyinstaller --add-data="file.txt?dir"

?是这里的分隔符,这个应该是另外一个字符。 不能保证,字符串被引号!

我们已经考虑过 ; : > < | * 等等,但我们无法弄清楚哪些字符可以保存使用,没有副作用和平台无关(希望路径中不允许)。 > 例如将重定向标准输出,; 是 POSIX 等的命令分隔符。

知道我们可以使用什么字符吗?

你可以使用@和\进行转义:)

对我们来说最好的解决方案是使用平台相关的分隔符:

  • Windows: ;

  • Unix::

记录起来有点棘手,但这是一个干净安全的解决方案。

真正的问题及其解决方案

你的问题在某种程度上是XY problem的一个实例。至少一条红鲱鱼。

如下所示,不存在理想的路径分隔符,因此 如果您真的坚持支持任意疯狂的路径,则必须在单独的命令行选项中传递该信息 .然后,由用户决定在调用您的程序时在路径中转义他们的怪异字符。

不存在理想的路径定界符

Unix 路径可以包含除 ASCII NUL ([=11=]) 之外的任何字符。路径组件(文件名)不允许包含斜线(/)。其他都行,according to POSIX.

因此,您选择的约束太紧了。即使在 Unix 上也没有解决您的问题的理想方法,完全忽略了可移植性问题。

好的路径分隔符

你必须在路径上设置一些“常识”约束,例如. This combination is quite natural, intuitive and easy to read, by the way, because these characters are path separators 对于这些系统。

让我们看看是否可以只保留一个路径中可能永远不会出现的字符。那么约束集是否可以满足?

如果你列出非字母数字的可打印 ASCII 字符并删除那些对 Unix shell 有特殊意义的字符以及那些即使是理智的人也在路径中使用的字符(_、- 等),你可以选择一个合理的路径分隔符:

LC_ALL=C
awk 'BEGIN{ for (i=1;i<ARGC;i++) printf "%c\n", ARGV[i]; }' {1..127} |
    grep '^[[:print:]]$' |
    grep '^[^][*?~$`"'\''&|#\<>(){}!;/[:alnum:] ._-]$'

ASCII 为 0..127,但 0 被排除在外,因为它会导致面向文本的实用程序出现问题。 Bash 特价商品也被过滤掉了。

结果集只包含七个字符,但是:%+,:=@^

Aaah,百分号 (%) 和插入符号 (^) 不幸的是在 cmd.exe 和冒号 (:) 在 Windows 路径中有特殊含义.只剩下四个:+,=@

要么你选择其中之一,要么你认为它们不方便,你修改了特殊列表以针对不同的系统选择不同的字符(例如,你建议的冒号和分号折衷方案),这放宽了可移植性限制少量。或者也许波浪号 (~) 在 shell 中并不那么特殊,因为它仅在 shell 字开头扩展到主目录路径。或者您可能不需要分隔符,而是分隔符字符串——您可以猜到很少有文件的名称中包含 @@@