Hi,
I have a csv type file. I want to be able to call a function from the command line, and feed it the content of this file - not the file itself.
I tried to call
mix run lib/my_module.ex $(cat tmp.txt)
having in the end of my module file :
IO.puts MyModule.my_func(System.argv)
Content is correctly processed to the func, but System.argv
being a list of strings, it lost its format and is not possible to parse correctly.
If I instead try to
mix run -e "MyModule.my_func(:args)"
I can’t find how to feed it the content of the file, using cat
or something else.
How to make it work ?
NobbZ
January 31, 2019, 4:06pm
2
Assuming bash, the following should do the trick:
mix run lib/my_module.ex "$(cat tmp.txt)"
Then bash will send the full file content in a single arg.
But I think using stdin where a much better idea:
cat tmp.csv | mix run lib/my_module.ex
2 Likes
Or you can use a library for that:
And pass the location of the file as an argument. That should work.
Yes, that would work, but for some reason I won’t have the file itself - only its content is available to me.
Your solution to send the content as a single argument is ok, but I don’t know why, it gives me a weird error :
== Compilation error in file lib/my_module.ex ==
** (Protocol.UndefinedError) protocol String.Chars not implemented for %IO.Stream{device: #PID<0.108.0>, line_or_bytes: :line, raw: true}
(elixir) lib/string/chars.ex:3: String.Chars.impl_for!/1
(elixir) lib/string/chars.ex:22: String.Chars.to_string/1
(elixir) lib/io.ex:553: IO.puts/2
(elixir) lib/kernel/parallel_compiler.ex:208: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
This stdin
idea is interesting ! I will dig it a little.
Wait, the BEAM turns a giant string argument into an IO Stream? Hmmm, how useful if so…
1 Like
Nah, I used {:ok, stream} = StringIO.open(file_content)
to do so ^^
Oh, but you said Your solution to send the content as a single argument is ok, but I don’t know why, it gives me a weird error
, lol. ^.^;
You’re right, it’s not the solution that has an issue, it’s my way to handle the code after that - I already had a working solution when parsing the file myself directly that uses Stream
and I tried to adapt it.
1 Like
JerryBels:
You’re right, it’s not the solution that has an issue, it’s my way to handle the code after that - I already had a working solution when parsing the file myself directly that uses Stream
and I tried to adapt it.
Hmm, if you want to use the existing stream code then you could just wrap the full-content string argument in a StringIO
, although changing it to direct binary calls would be far far more efficient, but keeping it as IO means that you can choose whether to take a string or a potentially very large file.
Well, as you see, trying to feed ot to StringIO.open
gives that error.
== Compilation error in file lib/my_module.ex ==
** (Protocol.UndefinedError) protocol String.Chars not implemented for {:ok, #PID<0.108.0>}
(elixir) lib/string/chars.ex:3: String.Chars.impl_for!/1
(elixir) lib/string/chars.ex:22: String.Chars.to_string/1
(elixir) lib/io.ex:553: IO.puts/2
(elixir) lib/kernel/parallel_compiler.ex:208: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
I’m dumb. Of course there is a strange bug… It’s the
IO.puts MyModule.my_func(System.argv)
that’s responsible of it ! The code works perfectly.
Thanks again !
2 Likes