Zum Inhalt springen
aviral gupta

// 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.

Lektion 4 von 5 in B1 Node ausführen und Projektgrundlagen

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
  1. Aufwärmen · Aufgabe 1 von 7

    Aufwärmen: Welche dieser console-Methoden schreiben auf stderr statt auf stdout? Wählen Sie alle zutreffenden.

    Wählen Sie alle zutreffenden aus.

  2. 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");
  3. Ü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");
  4. Ü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.

  5. Ü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");
  6. 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);
  7. 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.js

Ausgabe

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
  1. Hinweis 1

    Fragen Sie bei jeder Zeile: Soll sie in orders.csv stehen? Wenn nicht, gehört sie auf stderr.

  2. Hinweis 2

    console.error und console.warn schreiben auf stderr; console.log schreibt auf stdout.

  3. 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.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.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
  1. Hinweis 1

    Number("ten") ist NaN, und Number.isNaN sagt es Ihnen.

  2. Hinweis 2

    Prüfen Sie alle Argumente, bevor Sie etwas ausgeben; dann bleibt stdout bei einem ungültigen leer.

  3. 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.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Hä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: 5

Warum, 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.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Zwei Ströme: stdout für Daten, stderr für Meldungen

Jedes Programm hat zwei Ausgabeströme. console.log, console.info und console.debug schreiben auf stdout; console.error, console.warn und console.trace schreiben auf stderr. Ein Terminal zeigt beide gemischt, aber die Shell kann sie trennen: node main.js > out.txt speichert nur stdout, die stderr-Zeilen erscheinen weiter auf dem Bildschirm; 2> err.txt speichert nur stderr; node main.js | sort gibt nur stdout an das nächste Programm weiter. Geben Sie deshalb das Ergebnis auf stdout aus und alles, was für einen Menschen gedacht ist, auf stderr: Fortschritt, Warnungen, Hinweise zur Bedienung und Fehler. Auch der Bericht über einen nicht abgefangenen Fehler geht auf stderr; out.txt enthält also nur, was vor dem Absturz ausgegeben wurde.

process.stdout.write gibt genau das aus, was Sie übergeben

console.log formatiert seine Argumente, hängt einen Zeilenumbruch an und schreibt das Ergebnis in process.stdout, den Strom hinter stdout. process.stdout.write(text) schreibt den Text und sonst nichts: keinen Zeilenumbruch, keine Leerzeichen zwischen Teilen, keine Formatierung. Damit bauen Sie eine Zeile aus mehreren Stücken; am Zeilenende setzen Sie "\n" selbst. write nimmt einen String, keine Zahl: write(42) wirft einen TypeError. Ein zweites Argument gilt als Kodierung des Textes, deshalb scheitert write("Total:", 5) mit Unknown encoding: 5. process.stderr.write tut dasselbe für stderr. Der Browser hat kein process-Objekt; Code mit einem der beiden läuft nur auf Ihrem Rechner.

Der Exit-Code ist das Urteil

Wenn ein Programm endet, erhält die Shell seinen Exit-Code: 0 heißt Erfolg, alles andere Fehler. Skripte und Werkzeuge lesen den Code, nicht Ihren Text: node check.js && node deploy.js führt den zweiten Befehl nur nach Exit-Code 0 aus. In bash gibt echo $? den letzten Exit-Code aus, in PowerShell steht er in $LASTEXITCODE. Setzen Sie das Urteil mit process.exitCode = 1 und lassen Sie das Programm zu Ende laufen. process.exit(code) beendet den Prozess sofort, mit code, oder mit process.exitCode, wenn Sie keinen übergeben. Es wartet nicht auf offene Arbeit, und unter Linux und macOS gehört dazu auch Ausgabe, die noch unterwegs in eine Pipe ist: node big.js | wc -c kann weniger zählen, als geschrieben wurde.

Quellen

Zuletzt geprüft am 30. September 2026