快速上手

常规

首先 opslang 作为一门语言,通常语言所有的特性功能也是有的,比如定义变量,逻辑运算等等,比如下面这个例子(可以先忽略 goalrun 等关键词)

# t.ops
goal all {
    run {
        my Int $foo = 1;
        my Int $bar = 2;
        say("foo + bar = ", $foo + $bar);
    }
}

执行结果:

$ opsrun t.ops
foo + bar = 3

调用 shell 命令

然后 opslang 强大之处则是与 shell 交互,比如一般的执行 shell 命令, 同时,shell 命令里还可以直接使用 opslang 里面的变量

goal all {
    run {
        my Str $name = "opslang";

        $ echo -n "hello world, my name is $.name",
        say("shell out: ", cmd-out);
    }
}

执行结果:

$ opsrun t.ops
shell out: hello world, my name is opslang

流式匹配 shell 输出内容

是的,这个看起来比较普通,一般语言也可以做到,那么我来试下高级一些的用法。 比如:

goal all {
    run {
        my Str $name;
        my Int $age;

        $ echo "hello, my name is opslang, I'm 1 years old",
        stream {
            out contains rx/name is (\w+)/ =>
                $name = $1;

            out contains rx/(\d+) years old/ =>
                $age = $1;

            found-prompt => break;
        },
        say("name: $name, age: $age");
    }
}

执行结果:

$ opsrun t.ops
name: opslang, age: 1

与 shell 交互

嗯,这个看起来也还好,我们再来看看,比如:

goal all {
    run {
        my Str $var = "foo";

        sh/read foo/,    # shell 会等待一个输入
        send-text($var),
        send-key("\n"),
        $ echo -n $foo,
        say("variable foo: ", cmd-out);
    }
}

执行结果:

$ opsrun t.ops
variable foo: foo

哦,看起来有点意思,不过好像没有啥实际作用,我们继续, 比如,修改当前用户密码

goal all {
    run {
        my Str $old-password = "aoleipah1";
        my Str $new-password = "To5Geefohx";

        $ passwd,
        stream {
            out contains "(current) UNIX password" =>
                send-text($old-password),
                send-key("\n");

            out contains "New password:" =>
                send-text($new-password),
                send-key("\n");

            out contains "Retype new password:" =>
                send-text($new-password),
                send-key("\n");

            out contains "updated successfully." =>
                say("updated successfully.");

            found-prompt => break;
        };
    }
}

执行结果:

$ opsrun t.ops
updated successfully.

远程执行

看到这里,我想你应该对 opslang 有一些感觉了,是的,opslang 完全可以做到像人类操作终端一样,我们继续更高级的玩法。 比如:

goal all {
    run {
        my Str $remote-server-ip = "1.2.3.4";
        my Str $local-hostname = hostname;
        my Str $remote-hostname;

        sh/ssh -o StrictHostKeyChecking=no -o "ConnectTimeout=20" root@$.remote-server-ip/,
        setup-sh,

        $ echo "hello, I'm opslang, I come from $.local-hostname" > i-am-here.log,
        $remote-hostname = hostname,

        exit-sh,

        say("I'm back from $remote-hostname, I'm in ", hostname, " now.")
    }
}

执行结果:

$ opsrun t.ops
I'm back from remote, I'm in localhost now.

同时,我们也可以在远程机器上看到 /root/i-am-here.log 的文件内容为:

hello, I'm opslang, I come from localhost

是不是有点像孙猴子在五指山上写的到此一游呢,嗯,对的,有了 opslang 确实有这种魔力,我们也可以变很多戏法了。

opslang 非常适合用来自动化很多繁琐的任务,让我们从繁琐的任务中解放出来,更多的享受编程的乐趣。

更多有趣的功能,比如模拟多终端,异步执行等,以及更详细的语法介绍,请查看 opslang 用户手册

调试

哦,还有一个彩蛋,如果运行时有非预期的情况出现,需要调试怎么办呢?不用担心,opslang 会自动实时记录完整的 shell 交互历史,包括输入和输出。

如果是本地运行,默认会在当前目录有一个 ops.script.log 文件,直接 cat ops.script.log 即可看到非常友好的输出,甚至还有语法高亮,可以随时查看,再也不用担心输出太多被刷屏了。