mitmario.dev

Argumente lesen

Node.js Sandbox 4 Min Lesezeit 3 BeispieleLektion 1 von 6

Bis hierhin hat dein Code immer dasselbe getan. Er las dieselbe Datei, gab dieselben Zeilen aus und hörte auf. Das ist ein Beispiel, kein Werkzeug.

Ein Werkzeug bekommt gesagt, womit es arbeiten soll. Auf der Kommandozeile schreibst du den Wert einfach hinter den Dateinamen, und Node legt ihn dir hin.

Wo die Werte landen

process.argv ist ein Array aus Zeichenketten. Es enthält alles, was beim Start auf der Kommandozeile stand, und zwar in dieser Reihenfolge:

Auf Position 0 steht der Pfad zum Node-Programm selbst, hier /usr/local/bin/node. Auf Position 1 steht der absolute Pfad zu deiner Datei. Erst ab Position 2 kommt das, was du selbst hingeschrieben hast.

Diese beiden vorderen Einträge sind der Grund, warum du in fremdem Code fast immer dieselbe Zeile siehst.

Was wirklich in process.argv steht
const eigene = process.argv.slice(2);

console.log("Anzahl:", eigene.length);
console.log("Als Liste:", eigene);
console.log("Das erste:", eigene[0]);

Das Beispiel läuft mit node argumente.mjs 42 --einheit=km, und du kannst das über dem Ergebnis nachlesen: Die Befehlszeile steht im Terminal über der Ausgabe. slice(2) schneidet die zwei Einträge weg, die dich nicht interessieren, und übrig bleibt genau das, was der Benutzer wollte, nämlich [ '42', '--einheit=km' ].

Probier einen anderen Aufruf. Starte die Sandbox und tipp im Terminal node argumente.mjs Hallo Welt, dann steht dort Anzahl: 2 und deine beiden Wörter. Lass die Argumente ganz weg, und es sind null. Das ist derselbe Unterschied, den ein Benutzer deines Werkzeugs erlebt, wenn er vergisst, etwas mitzugeben.

Merk dir die Zeile const eigene = process.argv.slice(2). Sie steht in praktisch jedem Kommandozeilenwerkzeug, das je geschrieben wurde.

Alles ist Text, auch die Zahl

Hier stolpern fast alle einmal, und der Fehler ist besonders unangenehm, weil er nicht abstürzt.

Wenn die Zahl gar keine ist
const zahl = process.argv[2];

console.log("Typ:", typeof zahl);
console.log("Mal zwei:", zahl * 2);
console.log("Plus zwei:", zahl + 2);
console.log("Erst umwandeln:", Number(zahl) + 2);

Halt zahl * 2 und zahl + 2 nebeneinander. Dieses Beispiel läuft mit einer 20, das erste ergibt also 40, genau das, was du erwartest. Das zweite ergibt 202.

Der Grund: Bei * gibt es keine sinnvolle Bedeutung für Zeichenketten, also wandelt JavaScript stillschweigend in eine Zahl um. Bei + gibt es eine, nämlich Aneinanderhängen, und die gewinnt. Aus "20" und 2 wird "202".

Das Tückische daran ist, dass die Multiplikation funktioniert. Du testest kurz, es passt, und drei Wochen später zählt dein Programm irgendwo zusammen und liefert Unsinn.

Wandle jedes Argument, das eine Zahl sein soll, ausdrücklich um. Number(text) ist der kurze Weg. Ob dabei etwas Brauchbares herauskam, sagt dir Number.isNaN(wert).

Positionsargumente und benannte Argumente

Es gibt zwei Arten, einem Programm etwas mitzugeben, und sie fühlen sich verschieden an.

Ein Positionsargument steht einfach da: node umrechnen.mjs 42. Was es bedeutet, ergibt sich aus seiner Stelle. Das ist knapp und liest sich gut, solange es ein oder zwei sind. Bei fünf weiß niemand mehr, was an dritter Stelle stand.

Ein benanntes Argument sagt es selbst: node umrechnen.mjs --einheit=km. Länger zu tippen, dafür lesbar, und die Reihenfolge ist egal.

Für die benannte Variante gibt es einen eingebauten Weg, und den solltest du kennen, bevor du dafür ein Paket installierst.

Benannte Argumente mit parseArgs
import { parseArgs } from "node:util";

const { values, positionals } = parseArgs({
  options: {
    einheit: { type: "string", default: "EUR" },
    ausfuehrlich: { type: "boolean", short: "a", default: false },
  },
  allowPositionals: true,
});

console.log("Einheit:", values.einheit);
console.log("Ausfuehrlich:", values.ausfuehrlich);
console.log("Uebrig:", positionals);

Dieses Beispiel läuft mit node lesen.mjs --einheit=km -a 12 34, also mit einer benannten Option, einer Kurzform und zwei Werten hinterher. parseArgs aus node:util bekommt eine Beschreibung deiner Optionen und gibt dir zwei Dinge zurück: values mit den benannten Werten und positionals mit dem Rest, hier also [ '12', '34' ]. Es kennt Kurzformen wie -a, es kennt Standardwerte, und es meldet einen Fehler, wenn jemand eine Option angibt, die es nicht gibt.

Das deckt ab, was die meisten Werkzeuge brauchen. Erst wenn du Unterbefehle, automatisch erzeugte Hilfetexte oder mehrsprachige Fehlermeldungen willst, lohnt sich ein Paket dafür.

Was tun, wenn ein Argument fehlt

Ein Werkzeug, das ohne Pflichtargument aufgerufen wird, hat genau eine vernünftige Reaktion: Es sagt in einer Zeile, wie es benutzt wird, und hört auf.

Was es nicht tun sollte, ist mit undefined weiterrechnen. Dabei kommt entweder NaN heraus, das dann durch dein halbes Programm wandert, oder ein Absturz an einer Stelle, die mit dem eigentlichen Problem nichts zu tun hat.

Die Meldung gehört dabei nicht auf die normale Ausgabe, und aufhören heißt nicht einfach aufhören, sondern mit einer Zahl aufhören, die Misserfolg bedeutet. Beides ist das Thema von Lektion 4.3, und in der Challenge zu dieser Lektion baust du den Fall schon mit ein.

Zum Mitnehmen

In process.argv stehen zuerst zwei Einträge, die nicht von dir sind: der Pfad zu Node und der Pfad zu deiner Datei. Deine eigenen fangen bei Index 2 an.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.