js 文件格式化为 json 的 .ssh/config

Js file formatting in json of the .ssh/config

提问人:Paul 提问时间:10/9/2023 最后编辑:Heretic MonkeyPaul 更新时间:10/9/2023 访问量:26

问:

我有以下文件:

# Personal account - default config
Host github.com-user1
   HostName github.com
   User git
   IdentityFile ~/.ssh/id_rsa_user1
# Official account
Host github.com-user2
   HostName github.com
   User git
   IdentityFile ~/.ssh/id_rsa_user2

我希望它成为以下 JSON:

[
  {
    Host: 'github.com-user1',
    HostName: 'github.com',
    User: 'git',
    IdentityFile: '~/.ssh/id_rsa_user1'
  },
  {
    Host: 'github.com-user2',
    HostName: 'github.com',
    User: 'git',
    IdentityFile: '~/.ssh/id_rsa_user2'
  }
]

应该删除多少条以 # 开头的注释,键的名称将是该行的第一个元素,其值在空格之后找到。

我写了下面的代码,它可以工作,但我想优化它。 例如,它不接受reduce中的最后一个元素,我不得不将其插入到reduce之外。

除了输入的键值之外,可能还有其他键值,例如 ForwardAgent、AddKeysToAgent 和 UseKeyChain。

唯一可以肯定的是,每个帐户都必须从主机密钥开始。

你能帮我一把吗?

import { exec as cExec } from "child_process";
import { promisify } from "util";

const exec = promisify(cExec);

  async function ssh() {
    const cmd = 'while IFS= read -r line; do echo "$line"; done < "$HOME/.ssh/config"'
    const { stdout, stderr } = await exec(cmd);
    if (stderr) throw new Error(stderr);

    const a = stdout.replace("\n", "");
    let obj = {};
    const b = stdout.trim().split("\n").reduce((r, a) => {
      if (!a.includes("#")) {
        let [name, value] = a.trim().split(" ");

        if (name === "Host") {
          if (Object.keys(obj).length > 0) r.push(obj);
          obj = {};
          obj[name] = value;
        } else {
          obj[name] = value;
        }

      }

      return r;
    }, []);

    if (Object.keys(obj).length > 0) b.push(obj);
    return b
  }
JavaScript JSON 文件 序列化 格式

评论

1赞 Heretic Monkey 10/9/2023
您显示的最终结果是无效的 JSON;在 JSON 中,键必须用双引号括起来,字符串值也应该用双引号括起来。您只是想将配置文件解析为对象,还是实际上需要存储 JSON?
0赞 Heretic Monkey 10/9/2023
无论哪种情况,您似乎都需要一个库,该库可以将您使用的格式解析为 JavaScript 对象,这些对象可以使用 .格式似乎是 YAML,在这种情况下,YAML 到 JSON 库将符合要求。JSON.stringify

答:

0赞 Tomi 10/9/2023 #1

最好使用现有的库来解析 ssh 配置,比如 ssh-config

ssh 配置格式比您想象的要复杂。例如,您遗漏的一些细节:

  • 关键字可以不区分大小写
  • #只有当行以 it 开头时,才是一个注释
  • 某些关键字可能具有多个带引号或空格分隔的参数,而不仅仅是 1 个值
  • 该关键字还开始了一个新部分,而不仅仅是MatchHost

ssh-config 库可以处理这个问题。

但是,既然你问了“reduce”:抽象地说,如果你正在解析一个没有良好现有库的类似格式,那么实现的结构可以是这样的:

const content = fs.readFileSync(process.env.HOME + "/.ssh/config", "utf8");

const sections = [];
for (const line of content.trim().split("\n")) {
  if (line.trim() === "" || line.includes("#")) {
    continue;
  }
  let [name, value] = line.trim().split(" ");
  if (name === "Host" || sections.length === 0) {
    sections.push({});
  }
  sections[sections.length - 1][name] = value;
}

return sections;

请注意,此代码并不能解决上述问题!这只是一个例子,你仍然应该使用一个库!