diff --git a/CHANGELOG.md b/CHANGELOG.md
index ca471d1b9..8a28a887e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ This section is for changes merged to the `major` branch that are not also merge
- `read` now requires at least one var name (#4220).
- `set x[1] x[2] a b` is no longer valid syntax (#4236).
- For loop control variables are no longer local to the for block (#1935).
+- A literal `{}` now expands to itself, rather than nothing. This makes working with `find -exec` easier. (#1109, #4632)
## Notable fixes and improvements
- `wait` builtin is added for waiting on processes (#4498).
diff --git a/doc_src/faq.hdr b/doc_src/faq.hdr
index eefbe5eff..45756f77e 100644
--- a/doc_src/faq.hdr
+++ b/doc_src/faq.hdr
@@ -24,7 +24,6 @@
- I'm seeing weird output before each prompt when using screen. What's wrong?
- How do I change the greeting message?
- Why doesn't history substitution ("!$" etc.) work?
-- Why do I get a missing argument error with `find ... {}`?
- How can I use `-` as a shortcut for `cd -`?
- How do I uninstall fish?
- Where can I find extra tools for fish?
@@ -244,21 +243,6 @@ Fish history recall is very simple yet effective:
See documentation for more details about line editing in fish.
-
-\section faq-find-braces Why do I get a missing argument error with `find ... {}`?
-
-Running `find ... -exec ... {}` produces an error:
-
- find: missing argument to '-exec'
-
-The problem is caused by the empty braces, which are subject to brace expansion.
-
-Quote the empty braces to achieve the desired effect:
-
-\fish{cli-dark}
-find ... -exec ... '{{}}'
-\endfish
-
\section faq-cd-minus How can I use `-` as a shortcut for `cd -`?
diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in
index ac4441629..5a398cc00 100644
--- a/doc_src/index.hdr.in
+++ b/doc_src/index.hdr.in
@@ -506,6 +506,14 @@ mv *.{c,h} src/
# Moves all files with the suffix '.c' or '.h' to the subdirectory src.
\endfish
+A literal "{}" will not be used as a brace expansion:
+
+\fish
+echo foo-{}
+# Outputs foo-{}
+
+echo foo-{$undefinedvar}
+# Output is an empty line - see the cartesian product section
\subsection expand-variable Variable expansion
diff --git a/src/expand.cpp b/src/expand.cpp
index d5e8e25b7..a37015c73 100644
--- a/src/expand.cpp
+++ b/src/expand.cpp
@@ -980,6 +980,15 @@ static expand_error_t expand_brackets(const wcstring &instr, expand_flags_t flag
}
}
+ // Expand a literal "{}" to itself because it is useless otherwise,
+ // and this eases e.g. `find -exec {}`. See #1109.
+ if (bracket_begin + 1 == bracket_end) {
+ wcstring newstr = instr;
+ newstr.at(bracket_begin - in) = L'{';
+ newstr.at(bracket_end - in) = L'}';
+ return expand_brackets(newstr, flags, out, errors);
+ }
+
if (syntax_error) {
append_syntax_error(errors, SOURCE_LOCATION_UNKNOWN, _(L"Mismatched brackets"));
return EXPAND_ERROR;
diff --git a/tests/test1.in b/tests/test1.in
index d14c11836..95d3ea8be 100644
--- a/tests/test1.in
+++ b/tests/test1.in
@@ -15,6 +15,10 @@ logmsg Bracket expansion
echo x-{1}
echo x-{1,2}
echo foo-{1,2{3,4}}
+echo foo-{} # literal "{}" expands to itself
+echo foo-{{},{}} # the inner "{}" expand to themselves, the outer pair expands normally.
+echo foo-{""} # still expands to foo-
+echo foo-{$undefinedvar} # still expands to nothing
logmsg Escaped newlines
echo foo\ bar
diff --git a/tests/test1.out b/tests/test1.out
index 292238753..14b22a690 100644
--- a/tests/test1.out
+++ b/tests/test1.out
@@ -11,6 +11,11 @@
x-1
x-1 x-2
foo-1 foo-23 foo-24
+foo-{}
+foo-{} foo-{}
+foo-
+
+foo- foo- foo- foo-
####################
# Escaped newlines