CLI AI

sed -i geht auf dem Mac nicht? BSD gegen GNU

2026-05-15

Wenn sed: 1: "s/foo/bar/g": invalid command code erscheint, ist nichts kaputt. macOS liefert BSD-Werkzeuge aus, Ihr Skript wurde für GNU geschrieben. Gleiche Namen, andere Flags. Das sind die sechs, die wirklich beißen.

1. sed -i verlangt auf macOS ein Argument

clai
$ clai ersetze foo durch bar direkt in config.txt, soll auf mac und linux laufen→ sed -i.bak 's/foo/bar/g' config.txt   # portabel: schreibt config.txt.bak

GNU behandelt das Backup-Suffix als optional, BSD verlangt es. sed -i '' 's/…' läuft auf macOS und scheitert auf Linux. sed -i.bak läuft auf beiden – Sie haben nur eine Sicherungsdatei zum Aufräumen.

2. Erweiterte Regex: -E nehmen, niemals -r

clai
$ clai ersetze jede Ziffernfolge durch N mit erweiterter Regex→ echo "foo123" | sed -E 's/[0-9]+/N/'fooN

-r gibt es nur bei GNU. -E versteht beides – GNU akzeptiert es seit Jahren. Machen Sie -E zur Gewohnheit, und eine ganze Fehlerklasse verschwindet.

3. date: -d auf Linux, -r auf macOS

clai
$ clai wandle den Unix-Zeitstempel 1735689600 in ein lesbares Datum in UTC um→ date -u -d @1735689600 '+%Y-%m-%d %H:%M:%S UTC'    # GNU2025-01-01 00:00:00 UTC→ date -u -r 1735689600 '+%Y-%m-%d %H:%M:%S UTC'     # BSD / macOS

Hier gibt es keine portable Schreibweise. Verzweigen Sie über uname oder installieren Sie GNU coreutils und rufen gdate auf.

4. stat: -c auf Linux, -f auf macOS

clai
$ clai gib Größe und Namen dieser Datei aus→ stat -c '%s %n' t.txt      # GNU4 t.txt→ stat -f '%z %N' t.txt      # BSD / macOS

Anderes Flag und andere Formatangaben. Wer mit stat etwas Ernsthaftes vorhat, nimmt auf Linux find -printf oder für den portablen Fall wc -c.

5. grep -P existiert auf macOS nicht

clai
$ clai hol nur die Ziffern aus diesem String, portabel→ echo "abc123" | grep -Eo '[0-9]+'123

grep -P (Perl-Regex) ist eine GNU-Build-Option, macOS liefert sie nicht mit. -E deckt die meisten realen Muster ab; wer wirklich Lookahead braucht, braucht perl oder ripgrep, nicht grep.

6. xargs -r gibt es nur bei GNU – und Sie brauchen es

clai
$ clai finde .log-Dateien älter als 30 Tage und lösche sie, ohne rm auf leerer Liste→ find . -name '*.log' -mtime +30 -print0 | xargs -0 -r rm

Ohne -r startet GNU-xargs den Befehl bei leerer Eingabe einmal ganz ohne Argumente – so wird xargs rm im leeren Verzeichnis zum Fehler und xargs docker rm zur Überraschung. BSD-xargs läuft bei leerer Eingabe ohnehin nicht, dort ist -r überflüssig und in alten Versionen unbekannt.

Stolperfallen

  • brew install coreutils bringt Zwillinge mit g-Präfix – gsed, gdate, gstat. Wer gnubin in den PATH legt, macht den Mac zu Linux: repariert das eigene Notebook und versteckt den Bug vor dem Rest des Teams.
  • Auf readlink -f ist kein Verlass. Ältere macOS-Versionen kennen es nicht. Nehmen Sie realpath, wo vorhanden, sonst greadlink -f.
  • base64 -d gegen -D. GNU dekodiert mit -d, macOS will historisch -D.

Verwandte Fragen

Was bedeutet «invalid command code» eigentlich? BSD-sed hat das nächste Wort als Backup-Suffix geschluckt und den Rest Ihres Ausdrucks als unbekannten Befehl gelesen. Ein Opfer des Argument-Parsings, kein Regex-Problem.

Ist macOS BSD oder Linux? Weder noch. Sein Userland stammt von FreeBSD ab – daher gleiche Namen wie unter Linux, aber andere Flags.

Wie schreibe ich ein Skript für beide? POSIX-Flags verwenden, -E bevorzugen, immer sed -i.bak schreiben und auf beiden Systemen testen, bevor es in die CI geht.

Siehe auch

CliAI erkennt Betriebssystem und Shell und erzeugt die Flags, die diese Maschine tatsächlich akzeptiert. In einer Zeile installieren.