Create a Cmd from a String

I am using Julia to combine information from a combination of sources and generate a (rather lengthy) string that is a call to an external program. I can generate a String containing the text that I would type into the shell but I can’t work out how to turn that into a Cmd to call with run. I currently get around that by writing the string to a file named cmd.sh and calling

run(`/bin/bash cmd.sh`)

but I am convinced there has to be a better way.

I tried

run(Cmd([mystring;]))

but that seemed to generate extra quotes.

Can someone suggest how I can do this?

1 Like

If you need to run it in the shell then run(`sh -c $cmd`) is best (where cmd is a String variable)

If you just need to pass multiple arguments, then call just run(cmd), where cmd is built up from interpolating other Cmd objects and arrays of Strings.

1 Like

Unfortunately the first version doesn’t work because the contents of $cmd are enclosed in double quotes. To the shell, it looks like one long file name.

I want to run

myprog --a=optiona --b=="option b" file1 file2

not

"myprog --a=optiona --b==\"option b\" file1 file2"

It seems that I will need to stay with the current approach or try to use your second approach and right now I think writing to a file then executing that as a shell script is easier.

I appreciate that appropriately quoting strings that are parts of commands is important but not having a way to override the quoting is awkward.

The right way to do this is to avoid the shell completely. e.g. suppose you have an array filenames of filenames strings and an array options with the option strings. You would construct the command to run by, for example:

options = ["--a=optiona", "--b=option b"]
filenames = ["file1", "file2"]
`myprog $options $filenames`

Note that in the options variable, there is no need for additional quoting. You write "--b=option b", not "--b=\"option b\"". The reason is that these options are passed directly to myprog, without going through the shell.

Avoiding the whole issue of quoting and escapes is a huge benefit of circumventing the shell, along with the performance advantage of not launching the shell process.

7 Likes

Thank you, @stevengj. I’ll let that be a lesson to myself to always give an example of what I am trying to accomplish.

It is all working well now.

Also note that writing a command literal (inside backticks) will also work.

Here cmd1 and cmd2 are equivalent:

cmd1 = `myprog --a=optiona --b="option b" file1 file2`
options = ["--a=optiona", "--b=option b"]
filenames = ["file1", "file2"]
cmd2 = `myprog $options $filenames`

2 posts were split to a new topic: Read a command as a string

Simply create an array with the command and its arguments, then pass this array to the command object and run the command using run() function.

x = ["ls", "-la"]
cmd = `$x`
run(cmd)

if you want to run a string as a command, then first split the string and collect it and assign the ‘x’ (above) to the splitted array:

str = "ls -la"
x = split(str)
cmd = `$x`
run(cmd)

It works 100%

Is there a simple way to run a command from a string and get the output as a string ? Something like

cmd = "ls *"
out = readstring(`$cmd`)

but that works. I managed to get something working by copying and modifying Base.repl_cmd but it’s quite ugly and complicated. And I don’t want to do any interpolation, just run the string and get the output.

It need some upgrade work, though.

To read the output of an an external program as a string, simply do e.g.:

read(`ls`, String)

If by “command” you mean “shell command”, e.g. "ls *" is a shell command if you want * to be interpreted as a glob metacharacter, then you need to run it with a shell, e.g.:

shellcmd = "ls *"
read(`sh -c $shellcmd`, String)

By default, commands don’t use the shell because shelling out sucks — they just directly launch executables. Note also that there are portable, native Julia equivalents for anything you might want to do via a shell, e.g. globbing via Glob.jl or ls via readdir.

PS. Sorry, didn’t mean to necro-post. This came up in my discourse feed because of @Bittu_Kumar’s post above and I didn’t notice that I was responding to one of the ancient posts!

4 Likes

A post was split to a new topic: Interpolating multiple parameters into a Cmd