I am trying to construct a shell command for running
$ python3 script.py X=“a b c”
Here’s what I tried:
julia> args = ["script.py", "X=\"a b c\""]
2-element Array{String,1}:
"script.py"
"X=\"a b c\""
julia> cmd = `python3 $args`
`python3 script.py 'X="a b c"'`
How can I get rid of the extra ticks?
function escstr(str)
arr = collect(str); # Split string into an array of characters
resultstr = Array{eltype(arr)}(undef,0)
# Foreach character do any substitutions neccesary
for c in arr
if c == '"'
push!(resultstr,'\\','"')
elseif c == '\\'
push!(resultstr,'\\','\\')
else
push!(resultstr,c)
end
end
result = join(resultstr)
return result
end
bashit(str) = run(`bash -c "$str"`)
pstr = escstr( raw""" script.py X="a b c" """)
bashit("python3 $(pstr)")
There’s no extra ticks, that’s just for display. Also definitely don’t use shell to run command.
1 Like
If the argument is typed as X="a b c"
in the shell, then the actual argument passed to the Python script is X=a b c
because the shell interprets the double quotes and removes them but keeps the resulting quoted string as a single argument instead of splitting it on spaces as it would without the quotes. You can do the exact same thing when constructing a Julia command literal:
julia> cmd = `python3 script.jl X="a b c"`
`python3 script.jl 'X=a b c'`
julia> collect(cmd)
3-element Vector{String}:
"python3"
"script.jl"
"X=a b c"
Julia command literals interpret double quotes just like the shell does. By splicing a string value of X="a b c"
into a command, on the other hand, you are indicating that you actually want the double quotes to be part of the argument rather than interpreted by the command literal (the command literal only interprets what is literally there). If instead you interpolate the exact string that you want the Python script to see, i.e. X=a b c
, then it should do what you want:
julia> arg = "X=a b c"
"X=a b c"
julia> cmd = `python3 script.jl $arg`
`python3 script.jl 'X=a b c'`
Or similarly, you can do this:
julia> vars = "a b c"
"a b c"
julia> cmd = `python3 script.jl X=$vars`
`python3 script.jl 'X=a b c'`
Note that the exact string value that you pass as arg
is exactly what the python script sees as the value of that argument. It completely bypasses any shell quoting or unquoting shenanigans. The fact that you think you need to put double quotes in there is causing all the confusion and that’s just so that you can prevent the shell from splitting the value on spaces, which you don’t want, which then causes further confusion because the shell also removes the double quotes which you didn’t actually want in the argument at all, you only had to add them to prevent space splitting.
5 Likes