Aufwärmen · Aufgabe 1 von 7
// B1.4 · ca. 35 Min. · Einstieg
stdout, stderr und Exit-Codes
Nach dieser Lektion halten Ihre Programme Ergebnisse und Meldungen auseinander, sodass eine Datei oder das nächste Programm nur Daten bekommt, und sie teilen der Shell mit einem Exit-Code mit, ob sie erfolgreich waren.
Danach können Sie
- Daten auf stdout und Meldungen auf stderr ausgeben und vorhersagen, was >, 2> und | mit beiden tun
- Mit process.stdout.write exakt ausgeben, ohne automatischen Zeilenumbruch
- Erfolg oder Fehler mit einem Exit-Code melden, ihn in der Shell ablesen und process.exitCode statt process.exit() verwenden
Vorhersagen · Aufgabe 2 von 7
Sagen Sie es vorher, bevor Sie weiterlesen. Sie führen node main.js > fruit.txt aus, um die Obstliste zu speichern. Was steht danach in fruit.txt?
console.log("Reading 3 files..."); console.log("apple,3"); console.error("warning: pears.txt is empty"); console.log("plum,7");Üben · Aufgabe 3 von 7
Setzen Sie die Methode ein, damit die Warnung bei node main.js > fruit.txt nicht in fruit.txt landet und trotzdem auf dem Bildschirm erscheint.
console.____("warning: pears.txt is empty");console.("warning: pears.txt is empty");Üben · Aufgabe 4 von 7
main.js gibt Daten mit console.log und eine Meldung mit console.error aus. Ordnen Sie jedem Befehl zu, was passiert.
Üben · Aufgabe 5 von 7
Was gibt dieses Programm aus?
process.stdout.write("Loading"); process.stdout.write("."); process.stdout.write("."); console.log(" done"); console.log("2 files");Denksport · Aufgabe 6 von 7
Knobelaufgabe. Unter Linux führen Sie node big.js | wc -c aus; wc -c zählt die Zeichen, die das Programm geschrieben hat. Was gibt es aus? (Mit > in eine Datei geschrieben, kommen alle 1000000 an.)
process.stdout.write("x".repeat(1000000)); process.exit(0);Anwenden · Aufgabe 7 von 7
Mini-Aufgabe. Schreiben Sie report.js: Geben Sie für jeden Text in ["12", "7", "x", "30"] die verdoppelte Zahl mit console.log aus, oder, wenn es keine Zahl ist, not a number: x mit console.error. War ein Text ungültig, setzen Sie process.exitCode = 1. Führen Sie node report.js > rows.txt aus und prüfen Sie dann den Exit-Code: echo $? in bash oder $LASTEXITCODE in PowerShell. Öffnen Sie rows.txt.
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Selbst programmieren
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Ein Umrechner, der seine Daten sauber hält
Dieses Programm macht aus Celsius-Messwerten eine CSV-Datei mit einer Fahrenheit-Spalte. Die CSV geht auf stdout, teils mit process.stdout.write, sodass jede Zeile aus zwei Stücken entsteht. Alles, was für einen Menschen gedacht ist, geht auf stderr: eine Fortschrittszeile, eine Warnung für den Messwert, der keine Zahl ist, und eine Zusammenfassung. Die Ausgabe unten ist nur stdout, genau das, was node main.js > temps.csv speichert. Ein übersprungener Messwert ist hier nur eine Warnung, deshalb bleibt der Exit-Code 0.
main.js
// Converts Celsius readings to Fahrenheit, as CSV.
// Data goes to stdout, messages go to stderr.
const readings = ["20", "-5", "warm", "37.5"];
console.error("Converting " + readings.length + " readings...");
process.stdout.write("celsius,fahrenheit\n");
let skipped = 0;
for (const text of readings) {
const celsius = Number(text);
if (Number.isNaN(celsius)) {
console.warn("skipped " + text + ": not a number");
skipped++;
continue;
}
process.stdout.write(celsius + ",");
process.stdout.write((celsius * 9) / 5 + 32 + "\n");
}
console.error("Done: " + (readings.length - skipped) + " converted, " + skipped + " skipped.");
Ausführen mit
node main.jsAusgabe
celsius,fahrenheit
20,68
-5,23
37.5,99.5- Im Terminal zeigt node main.js um die CSV herum außerdem drei stderr-Zeilen: Converting 4 readings..., skipped warm: not a number und Done: 3 converted, 1 skipped.
- node main.js > temps.csv schreibt nur die vier CSV-Zeilen in die Datei; die drei Meldungen bleiben auf dem Bildschirm.
- Jede Zeile entsteht aus zwei write-Aufrufen: Der erste lässt die Zeile nach dem Komma offen, der zweite beendet sie mit "\n".
- celsius + "," ist ein String, also nimmt write ihn an; write(celsius) allein würde einen TypeError werfen.
Übungen
Übung 1 von 2
Nur CSV auf stdout
Jemand führt node main.js > orders.csv aus, also darf stdout nur CSV enthalten: zuerst die Kopfzeile id,amount, dann eine Zeile je Bestellung mit Betrag. Im Moment landen auch die Fortschritts- und Warnzeilen in der Datei, und die Kopfzeile fehlt. Geben Sie die Kopfzeile mit console.log aus und schicken Sie die drei Meldungen mit console.error oder console.warn auf stderr, statt sie zu löschen.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
Fragen Sie bei jeder Zeile: Soll sie in orders.csv stehen? Wenn nicht, gehört sie auf stderr.
Hinweis 2
console.error und console.warn schreiben auf stderr; console.log schreibt auf stdout.
Hinweis 3
Fügen Sie vor der Schleife console.log("id,amount"); ein.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// Prints one CSV line per order: id,amount.
// Someone runs node main.js > orders.csv, so stdout must hold only CSV.
const orders = [["A-1", 12.5], ["A-2", null], ["A-3", 7.25]];
console.error("Exporting orders...");
console.log("id,amount");
for (const [id, amount] of orders) {
if (amount === null) {
console.warn("warning: " + id + " has no amount, skipped");
continue;
}
console.log(id + "," + amount.toFixed(2));
}
console.error("Export finished.");
Auf dem eigenen Computer ausführen
Installieren Sie Node.js 24 LTS oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
// Prints one CSV line per order: id,amount.
// Someone runs node main.js > orders.csv, so stdout must hold only CSV.
const orders = [["A-1", 12.5], ["A-2", null], ["A-3", 7.25]];
console.log("Exporting orders...");
for (const [id, amount] of orders) {
if (amount === null) {
console.log("warning: " + id + " has no amount, skipped");
continue;
}
console.log(id + "," + amount.toFixed(2));
}
console.log("Export finished.");
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
test('stdout beginnt mit der Kopfzeile id,amount', async () => {
const first = (await runMain()).split('\n')[0];
assert.equal(first, 'id,amount', `die erste Zeile auf stdout ist ${JSON.stringify(first)}`);
});
test('keine Fortschritts- oder Warnzeile auf stdout', async () => {
const out = await runMain();
assert.doesNotMatch(out, /Export|warning/, `stdout enthält noch eine Meldung: ${JSON.stringify(out)}`);
});
test('stdout ist genau die Kopfzeile und die zwei Bestellungen', async () => {
const got = (await runMain()).trimEnd().split('\n');
assert.deepEqual(got, ['id,amount', 'A-1,12.50', 'A-3,7.25'], `stdout ist ${JSON.stringify(got)}`);
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenÜbung 2 von 2
Ein Exit-Code für die Shell
node main.js 4 2.5 10 soll die Summe ausgeben, 16.5, und ohne Argumente 0. Ist ein Argument keine Zahl, etwa ten, muss das Programm eine Meldung wie not a number: ten auf stderr ausgeben, nichts auf stdout, und mit Exit-Code 1 enden, sodass node main.js 4 ten && echo ok kein ok ausgibt. Verwenden Sie process.exitCode, nicht process.exit(). Prüfen Sie mit node --test.
Diese Übung braucht Node.js auf Ihrem Computer (die Browser-Version kann sie nicht ausführen). Dateien und Befehle stehen unten.
Hinweise
Hinweis 1
Number("ten") ist NaN, und Number.isNaN sagt es Ihnen.
Hinweis 2
Prüfen Sie alle Argumente, bevor Sie etwas ausgeben; dann bleibt stdout bei einem ungültigen leer.
Hinweis 3
Bei einem ungültigen Argument: console.error("not a number: " + arg); dann process.exitCode = 1; und das console.log der Summe auslassen.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// node main.js 4 2.5 10 -> prints 16.5
// If an argument is not a number: a message on stderr, nothing on stdout, exit code 1.
const args = process.argv.slice(2);
const bad = args.filter((arg) => Number.isNaN(Number(arg)));
if (bad.length > 0) {
console.error("not a number: " + bad.join(", "));
process.exitCode = 1;
} else {
let total = 0;
for (const arg of args) {
total += Number(arg);
}
console.log(total);
}
Auf dem eigenen Computer ausführen
Installieren Sie Node.js 24 LTS oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
// node main.js 4 2.5 10 -> prints 16.5
// If an argument is not a number: a message on stderr, nothing on stdout, exit code 1.
const args = process.argv.slice(2);
let total = 0;
for (const arg of args) {
total += Number(arg);
}
console.log(total);
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
test('4 2.5 10 gibt 16.5 aus', async () => {
const got = (await runMain({args: ['4', '2.5', '10']})).trimEnd();
assert.equal(got, '16.5', `das Programm gab ${JSON.stringify(got)} aus`);
});
test('ohne Argumente erscheint 0', async () => {
const got = (await runMain()).trimEnd();
assert.equal(got, '0', `das Programm gab ${JSON.stringify(got)} aus`);
});
test('4 ten endet mit einem Exit-Code ungleich 0', async () => {
await assert.rejects(runMain({args: ['4', 'ten']}), Error, 'node main.js 4 ten endete mit Exit-Code 0');
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenHäufige Fehler
Eine Zahl mit process.stdout.write ausgeben
const count = 42;
process.stdout.write(count);
Was Node.js ausgibt
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received type number (42)Warum, und die Lösung
console.log macht aus jedem Wert Text, process.stdout.write nimmt aber nur einen String (oder Bytes). Wandeln Sie die Zahl selbst um und fügen Sie den Zeilenumbruch an: process.stdout.write(count + "\n") oder process.stdout.write(String(count)).
Mehrere Werte an process.stdout.write übergeben
const total = 5;
process.stdout.write("Total:", total);
Was Node.js ausgibt
TypeError [ERR_UNKNOWN_ENCODING]: Unknown encoding: 5Warum, und die Lösung
Anders als console.log fügt write seine Argumente nicht zusammen: Das zweite ist die Kodierung des Textes, etwa "utf8", also ist 5 eine unbekannte Kodierung. Bauen Sie zuerst einen String: process.stdout.write("Total: " + total + "\n").
Eine Meldung an process.exit() übergeben
console.log("checking...");
process.exit("config file missing");
Was Node.js ausgibt
TypeError [ERR_INVALID_ARG_TYPE]: The "code" argument must be of type number. Received type string ('config file missing')Warum, und die Lösung
process.exit() nimmt einen Exit-Code, eine ganze Zahl, keine Meldung (seit Node.js 20 nur eine Zahl oder einen String aus Ziffern). Geben Sie die Meldung auf stderr aus und setzen Sie dann den Code: console.error("config file missing"); process.exitCode = 1;
JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode
Abschlussquiz
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.