4个版本
0.1.3 | 2022年1月22日 |
---|---|
0.1.2 | 2021年11月8日 |
0.1.1 | 2021年10月14日 |
0.1.0 | 2021年10月13日 |
在文本处理中排名第255
每月下载量24,798
在130个Crate中使用(直接使用2个)
57KB
1K SLoC
os_display
打印字符串可能很棘手。它们可能包含会破坏消息或整个终端的控制代码。在Unix中,甚至文件名也可能包含这样的字符。
文件名也可能包含无效的Unicode,而这在Path::display
中不会被保留。
最后,它们可能包含一些特殊字符,这些字符在没有引用或转义的情况下在命令中使用是不安全的。
此库允许您向文件名(以及其他字符串)添加引号,以便更安全、更有用地显示它们。目标是使它们能够以这种方式渲染,以便可以在不丢失信息的情况下将它们复制并粘贴回shell。
在Unix(和其他平台)上,使用bash/ksh语法进行引号处理,而在Windows上使用PowerShell语法。
何时使用此库?
此库最适合处理任意文件名或其他“脏”文本的命令行程序。例如,mv
是您用于重命名具有问题名称的文件的工具,因此如果其消息能够很好地处理它们,那就很好。
不需要处理奇怪数据的程序不会得到太多好处。
输出是为了shell设计的,因此将其显示在例如GUI中可能没有意义。
大多数程序无需此库也能正常运行。您可能并不严格需要它,但它可能是一个很好的改进。
用法
导入Quotable
特质
use os_display::Quotable;
此操作为常见的字符串类型(包括 OsStr
)添加了两种方法:.quote()
和 .maybe_quote()
。它们返回一个包装了自定义 Display
实现的 Quoted
。
.quote()
总是在文本周围添加引号
// Found file 'filename'
println!("Found file {}", "filename".quote());
// Found file "foo'bar"
println!("Found file {}", "foo'bar".quote());
// Unix: Found file $'foo\nbar'
// Windows: Found file "foo`nbar"
println!("Found file {}", "foo\nbar".quote());
.maybe_quote()
只有在需要(例如,由于空白或特殊字符)时才添加引号
// filename: Not found
println!("{}: Not found", "filename".maybe_quote());
// 'foo bar': Not found
println!("{}: Not found", "foo bar".maybe_quote());
// '*?$': Not found
println!("{}: Not found", "*?$".maybe_quote());
.quote()
最好用于较长的句子中,而 .maybe_quote()
可以用于已通过其他方式(如冒号)分隔的文本。
限制
- Unicode 可以被引号包围,但只有控制字符会被转义。打印的文本可能仍然看起来很奇怪,一些(有缺陷的)终端会丢弃某些字符。
- 该库不应该用于将文本插入到 shell 脚本中。它旨在提高可读性,而不是绝对的安全性。可以考虑使用
shell-escape
crate(或者最好以其他方式传递值)。 - 输出可能不与每个 shell 兼容。
- PowerShell 在外部命令的参数中对待引号的方式不同。此库默认对内部命令let进行引号处理,这可能不是您想要的。使用
Quoted::external()
方法可以切换此行为。 - 我不是 Unicode 专家。此 crate 的第一个版本存在多个疏忽,可能还有更多。
无效的 Unicode
在 Unix 上
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
// \xFF makes this invalid UTF-8, so to_str() would fail
let bad_string = OsStr::from_bytes(&[b'x', 0xFF, b'y']);
assert_eq!(bad_string.quote().to_string(), r#"$'x\xFFy'"#);
在 Windows 上
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
// 0xD800 is an unpaired surrogate, making this invalid UTF-16
let bad_string = OsString::from_wide(&[b'a' as u16, 0xD800, b'b' as u16]);
assert_eq!(bad_string.quote().to_string(), r#""a`u{D800}b""#);
零宽 Unicode
一些代码点宽度为零。它们可以使字符串变得不可见,或者使选择变得困难。GNU 工具难以处理这种情况
$ wc $'\u200b'
wc: : No such file or directory
在这种情况下,os_display
会添加引号
assert_eq!("\u{200B}".maybe_quote().to_string(), "'\u{200B}'");
当打印时,它仍然误导性地看起来像 ''
,但可以复制并粘贴它以获得正确的结果。
双向 Unicode
精心设计的字符串可以将它的一部分移动到行的末尾
$ wc $'filename\u202E\u2066 [This does not belong!]\u2069\u2066'
wc: 'filename': No such file or directory [This does not belong!]
这被称为 特洛伊源 攻击。它使用双向文本的控制代码。
如果它们没有正确终止,os_display
会转义这些控制代码。
功能标志
默认情况下,您只能使用当前平台引用的样式。这在大多数情况下是合适的。
windows
/unix
可以启用 windows
和 unix
可选功能,以便为 Quoted
添加构造函数。
Quoted::unix("some string")
不论平台如何,都会使用 bash/ksh 语法进行引号处理,而 Quoted::windows("etc")
则使用 PowerShell 语法。
Quoted::unix_raw
和 Quoted::windows_raw
分别接受 &[u8]
(用于不规则的 UTF-8)和 &[u16]
(用于不规则的 UTF-16)。
native
默认启用的 native
功能对于 Quotable
特性和 Quoted::native(&str)
和 Quoted::native_raw(&OsStr)
构造函数是必需的。如果没有启用,则必须显式选择引号样式。
alloc
/std
如果禁用了 alloc
和/或 std
功能,则此 crate 与 no_std
兼容。
要引号化 OsStr
,需要 std
功能。要处理 Quoted::windows_raw
,需要 alloc
功能。
备选构造函数
Quoted
不仅有特定的样式构造函数,还有 Quoted::native()
和 Quoted::native_raw()
。如果您更喜欢无聊的函数,则可以使用这些作为 Quotable
特性的替代。
默认情况下,总是添加引号。要获得类似 .maybe_quote()
的行为,请使用 .force()
方法。
println!("{}", Quoted::native(x).force(false));
测试
Unix 实现已针对 bash、zsh、mksh、ksh93 和 busybox 进行了模糊测试,以确保所有输出都被解释回原始字符串。它还针对 fish、dash、tcsh、posh 和 yash(不支持所有必需的语法)进行了更有限的模糊测试。
PowerShell 实现已针对在 Linux 上运行的 PowerShell Core 7.1.4 进行了模糊测试。
这两个实现都进行了模糊测试,以测试其针对特洛伊木马源攻击的保护。
致谢
此库是根据在 GNU coreutils 中看到的 Gnulib 中的引号方式构建的。但是,行为并不完全相同
- GNU 使用八进制转义序列,如
\377
而不是\xFF
。 - GNU 会中途急切地切换引号样式,如
''$'\n''xyz'
而不是$'\nxyz'
。os_display
除非必要,否则避免这样做。 - GNU 将未分配的代码点转义,而不是将其处理留给终端。
- GNU 不会特别处理零宽度代码点。
此代码的第一版是为 uutils 项目 编写的。用户反馈以及在大型代码库中使用它的机会很有帮助。
依赖项
~370KB