Выполнение основной команды оболочки в Elixir

На самом раннем этапе изучения языка и работы с сериями видеороликов ElixirSips. Я продолжаю сталкиваться с вещами, которые были слегка искажены языковыми изменениями. Пытаясь обернуть голову вокруг этого, и треки Google/Github для отслеживания/трассировки SO не принесут мне ничего полезного. У меня есть этот очень простой модуль, который должен просто запускать команду оболочки:

defmodule QuickieSynth.Sound do
  def command(note) do
    "play -qn synth 2 pluck #{note}"
  end

  def play(note) do
    note |> command |> System.cmd
  end
end

Однако, когда этот файл скомпилирован и запущены тесты, я получаю ошибку аргумента; достаточно справедливо - System.cmd/1, похоже, больше не входит в стандартную библиотеку lib.

System.cmd/3 находится в стандартной библиотеке, и чтение документов, указанных в параметрах, является необязательным. Поэтому я пропускаю пустые args note |> command |> System.cmd([]), а то, что я получаю, это erlang: :enoent: снова после чтения документов немного более тщательно, достаточно справедливо.

Итак, я пытаюсь использовать Erlang :os.cmd/1, поэтому note |> command |> :os.cmd, и я получаю (FunctionClauseError) no function clause matching in :os.validate/1. И я теперь застрял.

Ответы

Ответ 1

System.cmd/3 кажется, принимает аргументы команды в виде списка и не радует, когда вы пытаетесь проникнуть в аргументы в имени команды. Например, System.cmd("ls", ["-al"]) работает, а System.cmd("ls -al", []) - нет. Так что в вашем случае вам, вероятно, понадобится что-то вроде:

System.cmd("play", ["-qn", "synth", "2", "pluck", note])

На самом деле ниже происходит :os.find_executable/1 System.cmd/3 :os.find_executable/1 с его первым аргументом, который прекрасно работает для чего-то вроде ls но возвращает false для ls -al.

Если вы решите пойти по чисто эрланговскому маршруту, то вызов ожидает список символов вместо двоичного, поэтому вам нужно что-то вроде следующего:

"ls -al" |> String.to_char_list |> :os.cmd