shell.rs (2278B)
1 // Copyright (c) 2017 Jimmy Cuadra 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 use regex::Regex; 22 23 /// Escapes a string so it will be interpreted as a single word by the UNIX Bourne shell. 24 /// 25 /// If the input string is empty, this function returns an empty quoted string. 26 pub fn escape(input: &str) -> String { 27 // Stolen from 28 // https://docs.rs/shellwords/1.0.0/src/shellwords/lib.rs.html#24-37. 29 // Added space to the pattern to exclude spaces from being escaped 30 // which can cause problems when combining strings to form a full 31 // command. 32 let escape_pattern: Regex = Regex::new(r"([^A-Za-z0-9_\-.,:/@ \n])").unwrap(); 33 34 if input.is_empty() { 35 return "''".to_owned(); 36 } 37 38 let output = &escape_pattern.replace_all(input, "\\$1"); 39 40 output.replace("'\n'", r"\n") 41 } 42 43 #[cfg(test)] 44 mod tests { 45 use super::escape; 46 47 #[test] 48 fn empty_escape() { 49 assert_eq!(escape(""), "''"); 50 } 51 52 #[test] 53 fn full_escape() { 54 assert_eq!(escape("foo '\"' bar"), "foo \\'\\\"\\' bar"); 55 } 56 57 #[test] 58 fn escape_multibyte() { 59 assert_eq!(escape("あい"), "\\あ\\い"); 60 } 61 62 #[test] 63 fn escape_newline() { 64 assert_eq!(escape(r"'\n'"), "\\\'\\\\n\\\'"); 65 } 66 }