Tiny CLI

本文没有干货,只是列出了回字的四种写法四种语言编写命令行程序的写法,换句话说四个 Hello World。

in C

/**
 * demo.c
 */
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("argc is: %d\n", argc);
    for (int i = 0; i < argc; i++)
    {
        printf("argv[%d] is: %s\n", i, argv[i]);
    }
    return 0;
}
$ gcc -o demo demo.c
$ ./demo foo bar
argc is: 3
argv[0] is: ./demo
argv[1] is: foo
argv[2] is: bar

在 C 语言中,主函数的 argc 表示参数数量(包括程序本身文件名),argv 表示参数数组,第一项是程序本身文件名,后续项是具体参数列表。(代码中的 argc 表示 argument countargv 表示 argument vector,Java 中的 argsarguments 的简写)

in C++

/**
 * demo.cpp
 */
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    cout << "argc is: " << argc << endl;
    for (int i = 0; i < argc; i++)
    {
        cout << "argv[" << i << "] is: " << argv[i] << endl;
    }
    return 0;
}
$ g++ -o demo demo.cpp
$ ./demo foo bar
argc is: 3
argv[0] is: ./demo
argv[1] is: foo
argv[2] is: bar

C++ 和 C 一致。

in Java

/**
 * Demo.java
 */
class Demo {
    public static void main(String[] args) {
        System.out.println("args length is: " + args.length);
        for (int i = 0; i < args.length; i++) {
            System.out.println("args[" + i + "] is: " + args[i]);
        }
    }
}
$ javac Demo.java
$ java Demo foo bar
args length is: 2
args[0] is: foo
args[1] is: bar

Java 和 C/C++ 不同,作为跑在 JVM 上的程序,主函数的 args 直接就是传入的命令行参数列表,不包括程序本身文件名。

in JavaScript (Node.js)

#!/usr/bin/env node

console.log(`argv length is: ${process.argv.length}`);

process.argv.forEach((arg, index) => {
  console.log(`argv[${index}] is: ${arg}`);
});
$ ./demo.js foo bar
argv length is: 4
argv[0] is: /usr/bin/node
argv[1] is: /mnt/d/workspace/nodejs/demo.js
argv[2] is: foo
argv[3] is: bar

JavaScript 作为解释性脚本语言没有主函数,通过 Node.js 提供的 process API 来获取命令行参数,process.argv 的第一项是 Node 的路径,第二项是 JS 文件路径,后续项是具体参数列表。

Bonus Time

上面是三种编译型语言和一种脚本语言,下面来看看 Bash 脚本怎么获取命令行参数:

#!/bin/bash

echo "\$0 is: $0"
echo "\$1 is: $1"
echo "\$2 is: $2"

echo "\$# is: $#"
echo "\$* is: $*"
echo "\$@ is: $@"

echo "\$? is: $?"
echo "\$\$ is: $$"

for arg in $*; do
  echo "\$arg is: $arg"
done
$ ./demo.sh foo bar
$0 is: ./demo.sh
$1 is: foo
$2 is: bar
$# is: 2
$* is: foo bar
$@ is: foo bar
$? is: 0
$$ is: 9344
$arg is: foo
$arg is: bar

解释:

  • $0 脚本的文件名
  • $n n 为数字,表示脚本执行时传入的第 n 个参数
  • $# 参数数量
  • $* 所有参数
  • $@ 所有参数
  • $? 上个命令的退出状态
  • $$ 当前脚本的进程ID

思考

近年来,随着 Node.js 的蓬勃发展,借助 minimistyargs-parseryargscommander.jsinquirermeow 等命令行参数解析库、UI工具库,可以很方便地使用 JavaScript 编写命令行程序。这些命令行程序并不是黑科技,它们和我们编程入门时学的 Hello World 原理上没有质的区别,只是它们的作者投入了热情和心力。

相关链接