在 IEx Ports 的标准错误中强制回车 returns?

Force carriage returns in IEx Ports' stderr?

如果我在 IEx 中为将任何内容打印到 stderr 的脚本打开一个端口,输出的 none 将使用回车符 returns 打印。我怎样才能解决这个问题?我是 运行 无法控制其输出的外部软件,所以我不能只手动添加 returns。

例子

/tmp/run.sh

#!/usr/bin/env bash
>&2 echo -e "line 1\nline 2\nline 3\nline 4"

在 IEx 中 shell

iex(1)> Port.open({:spawn_executable, "/tmp/run.sh"}, [])
line 1             
      line 2                                                                                                   
            line 3                                                                                             
                  line 4

您可以 运行 在换行符前插入回车 return 的包装器下的脚本。这是一个使用 bashperl 的包装器:

#!/usr/bin/env bash
"$@" 2>&1 | perl -pe 's/\n/\r\n/' 1>&2

这是另一个使用 bashunix2dos 的方法:

#!/usr/bin/env bash
"$@" 2>&1 | unix2dos 1>&2

基本上,任何可以读取原始程序的stderr,用回车符return和换行符组合替换换行符,然后将结果写入stderr的东西都可以。

将这些解决方案之一放入名为 /tmp/lf.sh 的文件中。下面我们 运行 它来自 iex 与您的原始 /tmp/run.sh,首先是原始脚本,然后是包装器:

iex(1)> Port.open({:spawn_executable, "/tmp/run.sh"}, [])
#Port<0.5>
iex(2)> line 1
              line 2
                    line 3
                          line 4

nil
iex(3)> Port.open({:spawn_executable, "/tmp/lf.sh"}, [args: ["/tmp/run.sh"]])
#Port<0.6>
iex(4)> line 1
line 2
line 3
line 4

nil
iex(5)>

我有另一个快速但肮脏的解决方案(仅限 Elixir)

Port.open({:spawn_executable, "/tmp/run.sh"}, [:use_stdio, :stderr_to_stdout, :binary, :hide]); receive do
  {_port, {:data, line}} -> String.split(line,"\n", trim: true) |> Enum.each(fn(x)-> IO.puts(x) end)
end

问题是你想用这些数据做什么。

有关 link 的更多信息 https://bugs.erlang.org/browse/ERL-802 引用:

elixir --no-halt -e ':user_drv.start();Port.open({:spawn, "bash -c '\''>&2 echo \"stderr\nline2\"'\''"}, [:binary])' 2> err.log