diff --git a/src/uucore/src/lib/features/quoting_style/mod.rs b/src/uucore/src/lib/features/quoting_style/mod.rs index 75551692b5..a4afc78776 100644 --- a/src/uucore/src/lib/features/quoting_style/mod.rs +++ b/src/uucore/src/lib/features/quoting_style/mod.rs @@ -1186,6 +1186,14 @@ mod tests { check_names_both("name#", &[("name#", "shell"), ("name#", "shell-escape")]); } + #[test] + fn test_lone_brace() { + check_names_both("{", &[("'{'", "shell"), ("'{'", "shell-escape")]); + check_names_both("}", &[("'}'", "shell"), ("'}'", "shell-escape")]); + check_names_both("{}", &[("{}", "shell"), ("{}", "shell-escape")]); + check_names_both("{a,b}", &[("{a,b}", "shell"), ("{a,b}", "shell-escape")]); + } + #[test] fn test_special_chars_in_double_quotes() { check_names_both( diff --git a/src/uucore/src/lib/features/quoting_style/shell_quoter.rs b/src/uucore/src/lib/features/quoting_style/shell_quoter.rs index 441f1e5404..51b4106cae 100644 --- a/src/uucore/src/lib/features/quoting_style/shell_quoter.rs +++ b/src/uucore/src/lib/features/quoting_style/shell_quoter.rs @@ -261,7 +261,11 @@ fn finalize_shell_quoter( must_quote: bool, quotes: ShellQuotes, ) -> Vec { - let contains_quote_chars = must_quote || bytes_start_with(reference, SPECIAL_SHELL_CHARS_START); + // A lone brace is quoted, but braces inside a longer name are not. + let contains_quote_chars = must_quote + || bytes_start_with(reference, SPECIAL_SHELL_CHARS_START) + || reference == b"{" + || reference == b"}"; if must_quote | contains_quote_chars { let mut quoted = Vec::::with_capacity(buffer.len() + 2); diff --git a/tests/by-util/test_printf.rs b/tests/by-util/test_printf.rs index f598b6ab28..e4e06b87a7 100644 --- a/tests/by-util/test_printf.rs +++ b/tests/by-util/test_printf.rs @@ -20,6 +20,9 @@ use uutests::new_ucmd; #[case::sub_q_string_non_printable(&["non-printable: %q", "\"$test\""], "non-printable: '\"$test\"'")] #[case::sub_q_string_special_non_printable(&["non-printable: %q", "test~"], "non-printable: test~")] #[case::sub_q_string_empty(&["%q", ""], "''")] +#[case::sub_q_string_lone_open_brace(&["%q", "{"], "'{'")] +#[case::sub_q_string_lone_close_brace(&["%q", "}"], "'}'")] +#[case::sub_q_string_brace_group(&["%q", "{a,b}"], "{a,b}")] #[case::sub_char(&["the letter %c", "A"], "the letter A")] #[case::sub_char_from_string(&["%c%c%c", "five", "%", "oval"], "f%o")] #[case::sub_num_int(&["twenty is %i", "20"], "twenty is 20")]