Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir shell command with wildcard failing when using System.cmd

I have an elixir program that needs to programmatically delete a variable amount of PNG files named as such.

/path/to/dir/<uuid>-frames-001.png
/path/to/dir/<uuid>-frames-002.png
/path/to/dir/<uuid>-frames-003.png

etc.

Naturally, I have come up with the following elixir code to delete these files.

System.cmd("rm", ["/path/to/dir/" <> uuid <> "-frames-*.png"])

I have seen the above code fail in multiple ways. First off, I have run it on server and seen the following stacktrace:

/bin/rm: cannot remove '/path/to/dir/<uuid>-frames-*.png': No such file or directory

I have also run this code on a console session and seen the exact same output.

If I run the following command in a bash session, it works fine!

rm /path/to/dir/<uuid>-frames-*.png

It returns a 0 error code and it deletes the expected files. It seems like elixir is interpreting the * as a literal character, and not performing the expected wildcard delete. Any idea how to accomplish this? Thanks!

P.S.

Obviously, <uuid> is an actual uuid and therefore should not be interpreted literally for the scope of this problem.

like image 301
Kulix Avatar asked Apr 21 '18 03:04

Kulix


2 Answers

Wildcards like * are expanded by the shell, not by rm. Your command will only delete the file literally called /path/to/dir/<uuid>-frames-*.png.

You can make the wildcard expand by passing the command to a shell like sh:

System.cmd("/bin/sh", ["-c", "rm /path/to/dir/#{uuid}-frames-*.png"])

or use os:cmd/1 which by default invokes sh (note the single quotes instead of double):

:os.cmd('rm /path/to/dir/#{uuid}-frames-*.png')
like image 190
Dogbert Avatar answered Nov 02 '22 15:11

Dogbert


The path in the second argument in call to System.cmd/2 “a list of binaries which the executable will receive as its arguments as is.” From the documentation:

This means that:

— environment variables will not be interpolated
wildcard expansion will not happen (unless Path.wildcard/2 is used explicitly)
— arguments do not need to be escaped or quoted for shell safety.

So, to wildcard to work, one should:

System.cmd("rm", Path.wildcard("/path/to/dir/" <> uuid <> "-frames-*.png"))

Note, that since Path.wildcard/2 already returns a list, it should not be wrapped again.

There are many other workarounds, but for this particular case just use File.rm/1.

like image 23
Aleksei Matiushkin Avatar answered Nov 02 '22 14:11

Aleksei Matiushkin