How Elixir System cmd or shell works?

I want to run backup of postgresql database with Elixir. How can I do it with elixir script ?

defmodule PmLogin.DatabaseBackup do
  require Logger

  def start do
    Task.start_link(&start_backup/0)
  end

  def start_backup do
    Logger.info("Change directory to postgres path")
    System.cmd("cd", ["/"])

    System.cmd("cd", ["C:\\Program Files\\PostgreSQL\\14\\bin"])

    Logger.info("Set postgres password")
    System.cmd("set", ["PGPASSWORD=postgres"])

    Logger.info("Execute database backup")
    System.cmd("pg_dump", ["-h 'localhost' -U 'postgres' -f 'C:\\Users\\web\\Videos\\backup.sql' 'pm_users'"])

    Logger.alert("Backup successfully")
  end
end

ERROR
** (ErlangError) Erlang error: :enoent
(elixir 1.13.0) lib/system.ex:1044: System.cmd(“cd”, [“/”], [])
(pm_login 0.1.0) lib/pm_login/database_backup.ex:10: PmLogin.DatabaseBackup.start_backup/0

System.cmd doesn’t control a shell. It does start executables directly. There’s also no shared state between multiple System.cmd calls. I’d suggest putting things in a shell script and run everything with a single System.cmd call.

1 Like

Ok… but how do I change this code?

Give the cd and env options to System.cmd directly on the call using pg_dump

1 Like

Ok, thank you let’s try

I can see you are on windows.
I recommend you run your external program on a windows cmd shell and when you have the right cmd line you run it through cmd.exe like in my example below.

  def add_banner_to_video(record_path, match_id) do
    Logger.info("FFmpeg add_banner_to_video start...")

    output_path = "#{@records_final}#{match_id}.mp4"

    args =
      [
        # cmd.exe need this option
        "/c",
        "ffmpeg",
        "-i #{record_path}",
        "-i #{@banner}",
        "-filter_complex",
        "overlay=x=(0):y=(main_h-115)",
        "-vcodec libx264 -crf 17 -preset ultrafast",
        "-c:a copy",
        "#{output_path}"
      ]
      |> Enum.join(" ")

    {_, 0} = System.cmd("cmd.exe", [args], stderr_to_stdout: true)

    Logger.info("FFmpeg add_banner_to_video end")

    output_path
  end
2 Likes

I fixed it by running command with System.shell. Thanks all !!!

   # Execute commands in shell to backup postgresql database
      Logger.info("🔧 Backup starting ")
      System.shell("PGPASSWORD=postgres pg_dump -U postgres -d pm_users -f '#{db_name}'")

      # Say that backup is finished
      Logger.info("📦 Backup finished at 👉 #{datetime_to_finished}")

Beware that if someone will be able to control db_name then they can capture whole machine.

1 Like