anodizer_core/shell.rs
1//! POSIX shell quoting.
2
3/// Wrap `v` in POSIX single quotes so a shell reads it as exactly one literal
4/// word.
5///
6/// Inside single quotes a POSIX shell performs no expansion at all, so `$`,
7/// backticks, `"`, whitespace and newlines pass through untouched. The one
8/// character that cannot appear is `'` itself; each is emitted as `'\''` —
9/// close the quote, supply an escaped quote, reopen — which is why the result
10/// is always quoted rather than quoted-if-needed.
11///
12/// ```
13/// use anodizer_core::shell::shell_single_quote;
14/// assert_eq!(shell_single_quote("it's"), r"'it'\''s'");
15/// ```
16pub fn shell_single_quote(v: &str) -> String {
17 format!("'{}'", v.replace('\'', r"'\''"))
18}
19
20#[cfg(test)]
21mod tests {
22 use super::*;
23
24 #[test]
25 fn single_quote_escapes_embedded_quote() {
26 assert_eq!(shell_single_quote("foo"), "'foo'");
27 assert_eq!(shell_single_quote("foo's"), r"'foo'\''s'");
28 assert_eq!(shell_single_quote(""), "''");
29 assert_eq!(shell_single_quote(r#"a "b" c"#), r#"'a "b" c'"#);
30 assert_eq!(shell_single_quote("$(rm -rf /)"), "'$(rm -rf /)'");
31 assert_eq!(shell_single_quote("$HOME `id`"), "'$HOME `id`'");
32 assert_eq!(shell_single_quote("a\nb"), "'a\nb'");
33 }
34}