A small package to run string as shell command

Building a string is easy, but building a Cmd is always a headache to me. So I write a small package to run strings as Cmd.

Here is the task that drives me to write the package: There are some sub-folders containing .png files. I want to convert them into videos and place these videos at the root folder. And here is the code

julia> using Shell

julia> for (r,d,f) in walkdir(".")
           if any(x->endswith(x, ".png"), f)
               run("convert $r/*.png $(basename(r)).mp4")
           end
       end

It is more intuitive than dealing Cmd objects (In fact, I still not able to write the correct Cmd for this task…). Hope this will help someone.


edit:
It also supports windows.

julia> using Shell

julia> run("dir")

... (some output)

julia> useshell("powershell")
"powershell"

julia> run("ls")

... (some output)

WARN:
as @yuyichao pointed out below, there are something wrong with the code. And I quote it here

Blockquote

  1. The package is doing type piracy, don’t extend Base.run.
  2. Please put a warning in the README to that people are NOT encouraged to write buggy code as what you show above.

I also run into this kind of problem regularly

  1. The package is doing type piracy, don’t extend Base.run.
  2. Please put a warning in the README to that people are NOT encouraged to write buggy code as what you show above.
1 Like

Thanks for the suggestion

Note that doing this sort of thing has all of the problems that @StefanKarpinski described in his Shelling Out Sucks blog post. It will have unexpected results if basename(r) contains spaces, for example. (Maybe this is what @yuyichao was referring to with “buggy code”.) That’s why it would be better to learn to use Cmd objects.

The main thing that can’t be done directly with Cmd objects in this example is the *.png globbing (implement more special shell-like functionality in backticks · Issue #20401 · JuliaLang/julia · GitHub). However, you can use the Glob.jl package for that:

using Glob
run(`convert $(glob("*.png", r)) $(basename(r)).mp4`)
6 Likes

Didn’t know Glob.jl can be used like this. Thanks for the tip!

I updated the code to address the problems mentioned in the comments. One is type piracy, and the other is the escaping of spaces. It might be buggy for complex jobs, but it is handy to run simple commands at my skill level.

After writting these codes, I start to wonder, maybe the default way (Cmd and Pipelines) is more concise…

Does this fork a new shell for each command?

Basically it saves commands into a tmpfile.sh and run it by sh tmptile.sh