使用Node.js作为Shell。

3
我该如何将node.js设置为bash的替代品?例如,我应该能够运行vi('file')来打开文件,以及cd('location')在目录之间切换。
这是否可行?

5
由于 Node.js 没有实现 POSIX shell 所需的任何内容,因此这几乎肯定会失败,并可能对用户造成可怕的影响。在 Node.js 中编写符合规范的 shell 是可能的,但这是一个过于广泛的问题,不适合在SO上讨论。 - ssube
你想从Node.js执行exe文件吗?或者在Node.js API shelljs的基础上执行类似于shell命令的操作? - Aishwat Singh
@aishwatsingh Shelljs 并不差,但它只是建立在 Node.js API 之上。据我所知,你不能将其用作真正的 shell 替代品。 - Lime
你的意思是想要能够登录并将你的shell设置为Node REPL,同时仍然能够合理地使用你的计算机吗? - TheHans255
@Compynerd255 是的。例如,我应该能够运行vi('file')来打开一个文件,以及cd('location')在不同目录之间进行切换。 - Lime
1
为了让这个问题保持半新状态,提供了一个小的Node POSIX项目。[1] 距离问题被提出已经3年了。如注所述,一个真正的bash替代品将需要Node POSIX支持。还需要其他步骤。 1. https://www.npmjs.com/package/posix - gtzilla
5个回答

11
当然可以!不过使用电脑会变得更加复杂。
首先,你需要知道如何进行设置。虽然你可以在Linux中设置用户shell为usr/bin/node,但这样只会得到一个没有其他程序设置的Node.js REPL。你需要做的是编写一个设置脚本,可以为你完成以下所有设置/便利步骤,最终生成一个REPL。当然,由于UNIX shell设置无法指定参数,你需要编写一个小的C程序,使用这些参数执行你的shell(例如exec("/usr/bin/node", "path/to/setup/script.js");),并将其设置为你的UNIX shell。
主要思想是,除了基本的命令之外,你需要将任何使用的命令require()到你的shell中 - 例如,要执行与文件系统相关的操作,执行以下命令:
var fs = require("fs")

并且从fs对象中进行所有的文件系统调用。这类似于将东西添加到您的PATH中。您可以使用shelljs或类似的方式获取基本的shell命令,并且要获取实际的可执行程序,可以使用Node内置的child_process.spawnSync用于前台任务,或者child_process.spawn用于后台任务。

由于您的要求之一是要像调用函数一样调用每个程序,因此您需要自己编写这些函数,得到类似以下的内容:

function ls(path) {
    child_process.spawnSync('/bin/ls', [path], { stdio: 'inherit' });
}

对于你想要运行的所有内容,你可以通过编程的方式来实现。你可以通过迭代遍历你的PATH中的所有条目,并使用闭包来生成每个条目的执行函数,将它们分配给全局对象,这样你就不需要输入任何前缀。
再次强调,尽管有了这些命名函数,使用你的计算机将变得更加复杂。你需要明确地使用sh/bash/zsh来运行你在互联网上找到的shell命令,而且那些专门调用你的用户shell并期望它与Bash兼容的程序(或者如果你在一个将/bin/sh链接到你的用户shell的系统上)将不再起作用。但我当然能理解在命令行环境中利用JavaScript的吸引力。
补充:为了编写这个设置脚本,repl.start()返回的REPLServer对象具有一个context对象,该对象与REPL会话创建的全局对象相同。在编写设置脚本时,您需要将所有内容分配给context对象:
const context = repl.start('> ').context;
context.ls = function ls(path) { /* . . . */ }
context.cd = function cd(path) { /* . . . */ }

例如,我应该能够运行vi('file')来打开一个文件,cd('location')来在目录之间切换。我相信你的程序不像这样工作。 - Lime
1
它需要自动工作,对于你路径中的所有内容都是正确的吗? - TheHans255
1
创建一个允许像 cd arg1 arg2ls 这样的功能的超集Js语言会很好......我刚意识到我在描述CoffeeScript。 - Ray Foss
@RayFoss 感谢您提供的参考。Coffeescript 看起来真的很棒。 - site80443

1

我认为这将是一个有趣的提议。创建一个测试账户并告诉它使用node作为其shell。参见'man useradd'了解所有选项。

$ useradd -s /usr/bin/node test
$ su - test

1
这并不是一个真正的答案。 - Lime

0

这适用于Mac和Linux。

require('child_process').spawnSync('vi', ['file.txt'], { stdio: 'inherit' })

0
你可以使用自己的命令引导一个repl会话,然后运行脚本。
#!/bin/bash
node  --experimental-repl-await -i -e "$(< scripts/noderc.js)"`

这使得像以下这样的事情成为可能:

> ls()
> run('vi','file.txt')
> await myAsyncFunc()

-1

我想你正在寻找类似于这个https://youtu.be/rcwcigtOwQ0的东西!

如果是这样... 是的,你可以!

如果你愿意,我可以分享我的代码。但我需要先修复一些错误!

告诉我你是否喜欢。

我的.sh函数:

const hey = Object.create(null),
    sh = Object.create(null);;
  
hey.shell = Object.create(null);
hey.shell.run = require('child_process').exec;

sh.help = 'Execute an OS command';
sh.action = (...args) => {
    // repl_ is the replServer
    // the runningExternalProgram property is one way to know if I should 
    //       render the prompt and is not needed. I will create a better
    //        way to do this (action without if/decision)!
    repl_.runningExternalProgram = true;
    hey.shell.run(args.join(' '),
            (...args) => {
                ['error', 'log'].forEach((command, idx) => {
                    if (args[idx]) {
                        console[command](args[idx]);
                    }
                });
                repl_.runningExternalProgram = false;
            });
};

提示:要进入某个目录,只需更改 process.cwd(当前工作目录)。

提示2:为了避免为每个操作系统程序/命令编写 .sh,您可以在全局对象上使用代理。


有没有一种简单的方法来重新映射字符和控制字符? - Lime

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接