Executing system commands "backtick-like" way in Julia?

In Ruby I can put a shell command in backtick quotes and will get the printed output and the exit code as response. How to accomplish the same in Julia with as less prefix and postfix code wrapping the string of the shell command as possible?

Do you need more than run(`somebin some args`)?

2 Likes

See Running External Programs · The Julia Language

2 Likes

I would like to have it as unobtrusive to a surrounding text flow as possible. run( as prefix and ) as postfix does not align with the surrounding text flow as good as backticks which do not noticeably disturb the text flow … so for example using some Unicode characters like for example » as prefix and « as postfix would be much better and maybe could be replaced by backtick-like other Unicode ones. Is this possible in Julia? Or best to overwrite the backtick behavior with own custom function taking the backtick content as paramater?

Sorry for the late reply, but I was blocked by the chat system - written too much messages within one day …

How about:

output = `my shell command` |> run

Or this:

julia> macro r_cmd(str)
           return `$str` |> run
       end
@r_cmd (macro with 1 method)

julia> r`ls`

This doesn’t quite work with arguments (like r`ls -alh` ), but we can re-use Base’s argument parsing to do so:

macro r_cmd(str)
    return :(run(@cmd($(str))))
end

rls '*.svg'
ls: cannot access ‘*.svg’: No such file or directory
ERROR: failed process: Process(ls '*.svg', ProcessExited(2)) [2]

You can put the command on a different line, with whatever indentation you want, using triple backticks, e.g.:

result = readchomp(```
    ls
```)

(I would generally recommend trying too hard to make Julia code look like Ruby or some other language. Get used to differences in surface syntax between languages, try to write idiomatic code that other Julia programmers can easily read, and focus more on what the code does.)

Note also that most shell commands have native Julia equivalents, and it is better (more flexible, more robust, higher performance) in the long run to learn to use native Julia code for typical shell operations like ls or grep or cut.

Good catch!

OP also wanted the results in a string, and to include the return code.

Therefore:

julia> macro r_cmd(str)
           quote
               io = IOBuffer()
               try
                   run(@cmd($(str)), stdin, io)
               catch e
                   return String(take!(io)), e.procs[1].exitcode
               end
               return String(take!(io)), 0
           end
       end
@r_cmd (macro with 1 method)

julia> r`false`
("", 1)

julia> r`true`
("", 0)
2 Likes

What I am after is making as it easy as possible to write a transpiler for conversion from a like English sentences looking text written following guidelines of an oOo way of approaching programming I am busy with… Best I don’t need a transpiller at all because the target programming language allows to make another kind of programming language out of it giving the user the freedom of choice of anything. Badly languages which allowing this provide as good as no “batteries included” so it would mean to rewrite anything from scratch - what is not practicable - this leads to usage of higher level languages best suited to fit into the core idea. The question is how good is Julia suited for this purpose? Ruby is for example much better suited compared to Python. The oOo system requires usage of one-based indexing - a strong argument towards using Julia … Currently the shell programming language is the most flexible allowing any Unicode in “symbol names” being executable files … Ruby is two backticks away from shell programming … but with zero based indexing like shell …

That also doesn’t work with Julia’s regular commands (i.e. run(`rls '*.svg'`)) since it needs a shell to do globbing. In either case you can do sh -c ... or such.

1 Like

This looks promising … now it needs to be able to take implicit the shell which will be running the command …

It seems that macro programming is the way to arrive at a useful result … how does it work? Strange syntax … is the string str passed to r_cmd(str) the string within the backticks? and the cmd the hint which command the macro takes it parameter from? In this case it is a question of coding the macro to provide any desired functionality - or are macroes limited in what they can do?

julia> `bash -c 'ls "*.svg"'` |> run
ls: cannot access '*.svg': No such file or directory
ERROR: failed process: Process(`bash -c 'ls "*.svg"'`, ProcessExited(2)) [2]
julia> r`bash -c 'ls *.svg'`
ls: cannot access '*.svg': No such file or directory
("", 2)
julia> ```
bash -c "ls *.svg"
``` |> run

Macros are basically functions that take an expression and output a modified expression, which is then evaluated after the function returns.

https://docs.julialang.org/en/v1/manual/metaprogramming/

1 Like

The triple backtick code example fails to work ls: cannot access '*.svg': No such file or directory

I can only replicate that error if I do the the following.

julia> ```
bash -c "ls '*.svg'"
``` |> run

Do not add extra single quotes around *.svg.

1 Like