Fish parameters are, as a rule, escaped before being injected into fish commands:
mqudsi@freebsd> echo hello > hello\ world.txt
mqudsi@freebsd> file (echo hello world.txt)
hello world.txt: ASCII text
However, the result of braces expansion is not correctly escaped, _and_ there's no easy way to escape to manually escape it as introducing quotes around the parameter breaks the expansion:
mqudsi@freebsd> echo -n hello\ {1,2,3}.txt\n
hello 1.txt
hello 2.txt
hello 3.txt
As you can see, after the first parameter, echo
is being passed two separate arguments hello
and #.txt
, leading to the extra space in front of the words.
Wrapping the arguments in quotes leads to the following:
mqudsi@freebsd> echo -n "hello\ {1,2,3}.txt\n"
hello\ {1,2,3}.txt\n
While attempting to work around the issue by inserting escaped quotes into the original string (under the presumption that the contents of the string are not being escaped after replace and before injection) leads to the quotes being correctly escaped, preventing the desired result:
mqudsi@freebsd> echo -n \"hello\ {1,2,3}.txt\n\" "hello 1.txt " "hello 2.txt " "hello 3.txt
"
It looks like the parameter expansion is happening after the argument splitting stage.
echo
is being passed two separate arguments hello and #.txt, leading to the extra space in front of the words.
I don't agree with that diagnosis. echo
is being passed 3 arguments (each ending with \n
), which echo
dutifully prints with a space inbetween. I see no bug here.
Here is what I do to debug arguments:
~> printf '«%s»' hei\ {1,2,3}.txt\n
«hei 1.txt
»«hei 2.txt
»«hei 3.txt
»⏎
Here is what I do to debug arguments:
I use string escape
, i.e.
> string escape -- hello\ {1,2,3}.txt\n
hello\ 1.txt\n
hello\ 2.txt\n
hello\ 3.txt\n
which means you actually get what I'd expect. You get the full argument with "1", then with "2" and then with "3". The full argument just happens to include a newline.
@mqudsi: I would assume what's throwing you off here is one of a couple of things:
(command)
) on newline. That means the \n
here has no special meaning after being replaced with a newline character. It's "a character", as far as the rest is concerned. We don't need to _escape_ the character, we just don't run the splitting.Or in file (echo hello world.txt)
, the "hello world.txt" _is not_ escaped to hello\ world.txt
, it's just not split because there's no newline. If you have a file called hello\nworld.txt
, this would have issues similar to bash's problem with spaces.
echo
inserts spaces between its arguments (if "-s" has not been given). That's what's causing the weird indentation - because the spaces happen right after the newline.That means if you want to have the output
hello 1.txt
hello 2.txt
hello 3.txt
use echo -s
or printf '%s\n' hello\ {1,2,3}.txt
.
I believe this is a misunderstanding, rather than a bug. Am I correct?
Sorry, folks! I was trying to come up with a minimal repro for an issue and was confused by something completely different. I got the behavior of parameter expansion wrong, in particular, I confused it with that of parallel
or xargs
with a limit of 1, i.e. I presumed echo {1,2,3}
would expand to 3 commands with 1 argument each and not 1 command with 3 arguments.
Thanks for setting me straight.