How to enter \n with backtick syntax?

Apparently, \n doesn’t work in backticks:


julia> `echo "hello\nworld"`
`echo 'hello\nworld'`

julia> collect(`echo "hello\nworld"`)
2-element Array{String,1}:
 "echo"         
 "hello\\nworld"

Is there a better way to pass "hello\nworld" to echo than:

julia> hello = "hello\nworld"
"hello\nworld"

julia> collect(`echo $hello`)
2-element Array{String,1}:
 "echo"        
 "hello\nworld"

?

I may have missed the point completely, but how’s this?

using Printf
@printf("%s \n %s","echo","hello world")

or maybe

julia> hello=@sprintf("%s \n%s","hello","world")
"hello \nworld"

julia> println(hello)
hello 
world

`echo $"hello\nworld"` — using $ lets you interpolate Julia string syntax.

6 Likes

I am not sure if I understood the problem correctly, this seems to work as I would have expected:

julia> run(`echo -e "hello\nworld"`)
hello
world
Process(`echo -e 'hello\nworld'`, ProcessExited(0))
1 Like

The difference is whether you want to have \n converted into a newline by Julia and sent to the program (my solution: use $"...") or if you want to send \ and n to the program and have the program convert the backslash escape to a newline itself (your solution: use echo -e).

The problem with the latter echo -e solution is that it only works for echo — if you want to pass a newline to most programs, they won’t have any option to interpret backslash escapes themselves and you must form the newline character on the Julia side.

4 Likes

Fair enough. However, I have to admit that I have never ever needed to pass a string to a Linux command that was meant to have a newline inside and not represented by \n. If the situation arose, I would have just did command "`echo -e "a\nb"`" in the terminal (which works as it can be confirmed by replacing command by echo without the -e).

Is this documented? Running External Programs · The Julia Language has a whole section on interpolation with variables but I can’t find anything about interpolating with a string literal…

1 Like

AFAICT it’s just the general interpolation mechanism, which is documented.

@Tamas_Papp that’s the link I mentioned… Do you see something there suggesting that $"text" would work?

I don’t think this is the general interpolation mechanism. For example the following doesn’ t work: """Hello$"\n"world""".

Funny thing is, after checking the general interpolation documentation I thought you were right: it says

The shortest complete expression after the $ is taken as the expression whose value is to be interpolated into the string.

So it’s reasonable to conclude that "\n" is the expression to be interpolated here. But in practice it doesn’t work (outside of ` `). And "xxx $3 xxx" also doesn’t work, while "xxx $(3) xxx" does. So AFAICS the documentation is misleading, and the syntax `echo $"hello\nworld"` is undocumented…

Changing the documentation can be done very easily, PR’s can be done with a mouse click. No need to fork the repo!
I think, this interpolation thing in the context of backticks and Cmd would suit well in the corresponding docs.

1 Like

I entirely agree with you and was surprised as well that

`echo $"hello\nworld"`

works when I’d have expected to have to put parentheses around the string literal:

`echo $("hello\nworld")`

That being said, since that last form also works and is more consistent with how interpolation behaves elsewhere, shouldn’t we rather advertise this?

IMO, the same goes for array literals interpolation, which is explicitly mentioned in the command interpolation documentation:

julia> `rm -rf $["foo","bar","baz","qux"].$["aux","log","pdf"]`
`rm -rf foo.aux foo.log foo.pdf bar.aux bar.log bar.pdf baz.aux baz.log baz.pdf qux.aux qux.log qux.pdf`

and is very surprising since similar constructs produce syntax errors for string interpolation:

julia> """rm -rf $["foo", "bar"]"""
ERROR: syntax: invalid interpolation syntax: "$["
Stacktrace:
 [1] top-level scope at none:1
1 Like

I just always use $(...) when doing interpolation in Julia, for the same reason why I always use ${...} when referencing a variable in the shell: I don’t have to deal with corner cases where omitting the parentheses would break.

4 Likes

Where does one do that mouse click?

After editing the src and committing you are provided with an option to create directly a PR from the commit.

I can edit the source without having my own fork? I did not know that.

Yes, it’s straight forward.

I think that

julia> "xxx $3 xxx"
ERROR: syntax: invalid interpolation syntax: "$3"

is a bug and should work, here 3 is the shortest complete expression.

1 Like

$ interpolates the first Julia expression fragment it encounters — the first “lexical atom” (symbol or literal value) if there are no parens. You only need parentheses if you want to interpolate a compound expression involving multiple atoms.

For example, $1+2 does interpolation equivalent to $(1)+2, since 1 is the first parsed atom. So you need $(1+2) if you want to interpolate 3. Similarly, $sin(1) will interpolate $(sin)(1) since the symbol sin is the first parsed atom; you need $(sin(1)) to interpolate the whole function call.

A string literal "foo", on the other hand, is a single lexical “atom” — once the parser encounters ", there is no valid way to stop parsing until it reaches the closing ". So you don’t need parens to interpolate $"foo".

Clarifications to the documentation on interpolation would be welcome, of course.

2 Likes

But it doesn’t work!

julia> "$1+2"
ERROR: syntax: invalid interpolation syntax: "$1"

Same here: it doesn’t work (except in command syntax with ` `):

julia> """xxx $"foo" xxx"""
ERROR: syntax: invalid interpolation syntax: "$""

so Julia’s behavior is not consistent with this idea (expressed in the documentation) that $ interpolates “the first Julia expression fragment it encounters”… Is it a bug in Julia or a mistake in the documentation?

1 Like

I understand this is what the documentation says. But my expectation was rather based on empirical experience (not only with Julia but also with other languages/tools I have used for a long time). For example: all of the following 3 constructs should work under the stated rule, but actually produce syntax errors (at least in the case of string interpolation, which is by far the kind of interpolation I’m using the most):

julia> """hello $3 world"""
ERROR: syntax: invalid interpolation syntax: "$3"
Stacktrace:
 [1] top-level scope at none:1
julia> """hello $"\n" world"""
ERROR: syntax: invalid interpolation syntax: "$""
Stacktrace:
 [1] top-level scope at none:1
julia> """hello $[1] world"""
ERROR: syntax: invalid interpolation syntax: "$["
Stacktrace:
 [1] top-level scope at none:1

This might very well be a bug, but I’m really fine with it and never noticed it before. Actually, the only thing I really expect from interpolation is a form of referential transparency that lets me have a mental model where:

var = something # a string or vector or number or any expression, really
"hello $var world"

produces the same result as

"hello $(something) world"

And I’m not bothered by the (possibly useless) parentheses, for the reasons mentioned by @giordano above: I got a long time ago into the habit of always putting brackets/parens/etc around interpolated expressions in shell scripts/Makefiles/etc

My only point is this: I understand the viewpoint where interpolation should really work on the following lexical atom. Under this interpretation, there are a few bugs with string interpolation, which would need fixing.
On the other hand, my point-of-view is that putting parentheses around interpolated expressions is a common practice (maybe even recommended for anything other than a plain variable name). Under this view, string interpolation is not really buggy nor surprising. But then the behavior of command interpolation seems a bit surprising when it correctly handles literals of many more types than string interpolation. Hence my proposal of advertising the use of $(...) in the documented examples of command interpolation even though parentheses are not strictly needed in this specific context.

1 Like