Menu

process.argv trong Node.js: đọc tham số dòng lệnh

process.argv là một mảng chứa dòng lệnh đã khởi chạy chương trình: tệp thực thi node, đường dẫn script, rồi đến từng tham số bạn gõ. Dùng process.argv.slice(2) để chỉ lấy các tham số của bạn.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

process.argv là một mảng chứa dòng lệnh đã khởi chạy chương trình Node.js của bạn. Chỉ số 0 là đường dẫn tới tệp thực thi node, chỉ số 1 là đường dẫn tới script, và các tham số của riêng bạn bắt đầu từ chỉ số 2. Vì vậy process.argv.slice(2) cho bạn đúng những gì người dùng gõ sau tên tệp, và luôn ở dạng chuỗi.

Hai phần tử đầu tiên là đường dẫn đầy đủ, nên chương trình chỉ in phần cuối của chúng (node và index.js), rồi đến [ 'Ada', '42', '--verbose' ]. Sửa hàng tham số thành Grace 7 rồi chạy lại: mảng thay đổi theo.

Những gì có trong process.argv

Shell tách phần dòng lệnh sau node theo dấu cách và chuyển từng phần cho Node.js. Các cờ viết trước tên tệp thuộc về chính Node.js, không thuộc về chương trình của bạn:

node --max-old-space-size=4096 index.js --port=8080
# process.argv.slice(2) is [ '--port=8080' ]
# process.execArgv is      [ '--max-old-space-size=4096' ]

Dấu ngoặc kép gom nhiều từ thành một tham số ("Ada Lovelace" đến nơi dưới dạng một chuỗi duy nhất), và shell mở rộng các mẫu như *.txt thành tên tệp trước khi Node.js kịp nhìn thấy.

Lấy tham số bằng slice(2)

Phần lớn script dùng destructuring để lấy các tham số mình cần và gán cho mỗi tham số một giá trị mặc định:

Kết quả in ra là Hello, Ada: một tham số điền vào name, còn greeting dùng giá trị mặc định. Thêm Hi sau Ada ở hàng tham số thì kết quả là Hi, Ada; xóa trống hàng đó thì bạn nhận được Hello, world.

Số đến dưới dạng chuỗi

Shell không có kiểu dữ liệu. Mọi tham số đều là chuỗi, nên phép tính trên chúng sẽ sai cho đến khi bạn chuyển đổi:

a + b nối hai chuỗi thành 75, còn Number() cho ra 12. Một từ không phải số sẽ thành NaN, vì vậy hãy kiểm tra bằng Number.isNaN và in ra hướng dẫn cách dùng thay vì tiếp tục với một giá trị hỏng.

Tự phân tích cờ --name=value

Với vài cờ, một vòng lặp ngắn là đủ. Vòng lặp này biến --port=8080 thành port: '8080', một --verbose không có giá trị thành true, và giữ mọi thứ còn lại làm tham số vị trí:

Kết quả in ra là {"port":"8080","verbose":true} và [ 'build', 'src' ], trong đó port vẫn là chuỗi. Vòng lặp này không xử lý cờ ngắn như -p hay giá trị nằm ở tham số kế tiếp (--port 8080); với những trường hợp đó, hãy dùng bộ phân tích có sẵn bên dưới.

util.parseArgs, bộ phân tích có sẵn

Node.js 18.3 trở lên có sẵn util.parseArgs, xử lý được cờ dài và cờ ngắn, giá trị ở tham số kế tiếp, boolean và giá trị mặc định:

const { parseArgs } = require('node:util');

// node index.js -p 8080 --verbose src
const { values, positionals } = parseArgs({
    options: {
        port: { type: 'string', short: 'p', default: '3000' },
        verbose: { type: 'boolean', short: 'v' },
    },
    allowPositionals: true,
});

console.log(values);      // [Object: null prototype] { port: '8080', verbose: true }
console.log(positionals); // [ 'src' ]

Mặc định parseArgs đọc process.argv.slice(2). Hàm này ném lỗi khi gặp một tùy chọn bạn chưa khai báo, nhờ đó bắt được lỗi gõ nhầm như --prot; truyền strict: false để chấp nhận các cờ lạ. Kiểu của tùy chọn chỉ có string và boolean, nên số vẫn cần Number(). values là một đối tượng không có prototype, đó là lý do nó được in ra kèm [Object: null prototype]; bạn cứ đọc nó như mọi đối tượng khác.

Lỗi thường gặp

Đọc process.argv[0] như tham số đầu tiên. Đó là đường dẫn tới node. Tham số đầu tiên của bạn là process.argv[2].

Quên rằng mọi thứ đều là chuỗi. '10' > '9' là false, vì chuỗi được so sánh từng ký tự một. Hãy chuyển đổi trước.

Đặt thông tin bí mật vào tham số. Dòng lệnh xuất hiện trong lịch sử shell và trong danh sách tiến trình mà người dùng khác trên cùng máy có thể đọc. Thay vào đó, hãy truyền mật khẩu và API key qua biến môi trường.

Câu hỏi thường gặp

Làm sao để truyền tham số cho một npm script?

Đặt chúng sau --: npm run start -- --port=4000. npm chuyển mọi thứ sau -- cho script của bạn, và chúng xuất hiện trong process.argv.slice(2).

Vì sao process.argv[2] là undefined?

Vì chương trình được chạy mà không có tham số đó. Hãy cho nó một giá trị mặc định (process.argv[2] ?? 'guest'), hoặc in ra một dòng hướng dẫn cách dùng rồi dừng bằng process.exit(1).

Có nên dùng yargs hay commander thay cho process.argv không?

Với một script chỉ có vài cờ, util.parseArgs có sẵn và là đủ. Các package như commander và yargs bổ sung phần trợ giúp, lệnh con và kiểm tra dữ liệu, rất đáng dùng khi công cụ của bạn có nhiều lệnh.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu