← Alle Scripts

// Bash-Scripts

Synonyme im Terminal

Schlägt deutsche Synonyme direkt in der Shell nach — Quelle ist OpenThesaurus. Ohne jq, ohne Browser, ohne Tab-Wechsel.

TerminalSpracheAPI
Version1.3.0
Stand2026-07-11
Getestet aufGetestet auf einem Arch Linux x86_64
LizenzMIT
Brauchtbash 5, curl, coreutils
Umfang128 Zeilen · 3.9 KB
SHA256 0e0c3dd7ff312043e51aca170bde83c5d479bf1554ef2289b8943d2ae2f809bd Nach dem Download prüfen: echo "0e0c3dd7ff312043e51aca170bde83c5d479bf1554ef2289b8943d2ae2f809bd synonyme.sh" | sha256sum -c

Erst lesen, dann laufen lassen. Der vollständige Quelltext steht weiter unten auf dieser Seite. Einen curl … | bash-Einzeiler gibt es hier bewusst nicht.

Nutzung auf eigene Gefahr — keine Haftung für Datenverlust oder Systemschäden. Siehe Nutzungsbedingungen.

Wofür das Script gut ist

Man schreibt einen Text, hängt an einem Wort fest, und die Suche nach einem besseren führt zuverlässig in den Browser — und von dort in irgendeinen Tab, der nichts mehr mit dem Text zu tun hat. Dieses Script beantwortet die Frage dort, wo man ohnehin gerade tippt: im Terminal.

$ synonyme.sh schnell
zügig, rasch, flink, hurtig, geschwind, in Windeseile, im Eiltempo, fix, behände, …

Die Daten kommen von OpenThesaurus, einem freien deutschen Synonymwörterbuch. Das Script liest nur, ändert nichts und braucht keine Anmeldung.

Was es macht

  • Fragt OpenThesaurus nach Synonymen für ein Wort (oder eine Wortgruppe)
  • Gibt sie kommagetrennt aus, auf die Breite deines Terminals umgebrochen
  • --plain gibt einen Treffer pro Zeile — damit lässt sich das Ergebnis weiterverarbeiten

(| fzf, | grep, | head)

  • --limit N kürzt die Liste, --raw liefert die JSON-Antwort unverändert
  • Das Suchwort selbst fliegt aus der Trefferliste, Dubletten ebenfalls

Wie es das umsetzt

Der Ursprung war eine Shell-Funktion in meiner .bashrc, die die XML-Schnittstelle mit sed und cut zerlegt hat. Beim Aufräumen für die Veröffentlichung sind drei Dinge dazugekommen, die man in einer privaten Funktion gern weglässt:

Kodierung. wget "…?q=$*" bricht, sobald das Wort einen Umlaut oder ein Leerzeichen enthält — und deutsche Wörter tun das gern. Mit curl erledigt das die Bibliothek:

curl -fsSG --max-time 10 \
     --data-urlencode "q=${QUERY}" \
     --data "format=application/json" \
     "$API"

Kein jq. Naheliegend wäre, die JSON-Antwort mit jq zu filtern — aber jq ist auf einem frischen Debian nicht installiert, und ein Script, das erst ein Paket verlangt, benutzt man kein zweites Mal. Für Felder namens "term" reicht grep vollkommen:

grep -o '"term":"[^"]*"' | cut -d'"' -f4 | grep -vixF "$QUERY" | awk '!seen[$0]++'

Das awk '!seen[$0]++' ist die kürzeste Art, Dubletten zu entfernen, ohne die Reihenfolge zu zerstören — sort -u würde die Treffer alphabetisch umsortieren und damit die Rangfolge von OpenThesaurus wegwerfen.

Umbruch nur im Terminal. Das Original hat immer auf $(tput cols) umgebrochen. In einer Pipe ist das Unsinn: Da will man Zeilen, keine Optik. Deshalb wird nur umgebrochen, wenn die Ausgabe wirklich in einem Terminal landet:

if [[ -t 1 ]] && command -v tput >/dev/null && COLS=$(tput cols 2>/dev/null); then

Ein Script, das anders aussieht, je nachdem ob es in ein Terminal oder in eine Pipe schreibt, ist kein Bug — es ist gutes Unix-Verhalten. ls macht genau dasselbe.

Warum ich das automatisiert habe

Es war nie ein Automatisierungsprojekt, sondern eine Bequemlichkeit: eine Funktion in der .bashrc, mit syn als Alias. Der Grund, sie jetzt als Script aufzuschreiben, ist ein anderer — eine .bashrc-Funktion kann man niemandem geben. Sie hat kein --help, keine Fehlerbehandlung, und sie bricht beim ersten Wort mit Umlaut. Genau das ist der Unterschied zwischen „läuft bei mir" und „kann jemand anders benutzen", und dieses kleine Script ist das kürzeste Beispiel dafür, das ich habe.

Als Shell-Funktion geht es natürlich weiterhin:

# ~/.bashrc
syn() { /usr/local/bin/synonyme.sh "$@"; }

Datenschutz-Hinweis, weil er hierher gehört: Das Suchwort wird per HTTPS an openthesaurus.de übertragen. Wer das nicht will, sollte das Script nicht benutzen. Die Daten dort stehen unter CC-BY-SA.

Aufruf

synonyme.sh Haus
synonyme.sh --limit 5 schnell
synonyme.sh --plain Datei | fzf   # ein Treffer pro Zeile

Quelltext

synonyme.sh
#!/usr/bin/env bash
# ============================================================
#  synonyme.sh — deutsche Synonyme im Terminal nachschlagen.
#
#  Fragt OpenThesaurus (openthesaurus.de) und gibt die Treffer
#  als Liste aus. Liest nur, ändert nichts am System.
#
#  Hinweis: Das Suchwort wird an openthesaurus.de übertragen.
#
#  Autor:   Matthias Meister — https://scripts.web.mm-core.de
#  Lizenz:  MIT — Copyright (c) 2026 Matthias Meister
#           Volltext: https://scripts.web.mm-core.de/lizenz/
#  Version: 1.0.0
# ============================================================
set -euo pipefail

VERSION="1.0.0"
API="https://www.openthesaurus.de/synonyme/search"
TIMEOUT=10

LIMIT=0          # 0 = alle
PLAIN=0          # 1 = ein Synonym pro Zeile
RAW=0            # 1 = rohe JSON-Antwort ausgeben

usage() {
    cat <<'EOF'
synonyme.sh — deutsche Synonyme nachschlagen (Quelle: openthesaurus.de).

  Verwendung:
    synonyme.sh WORT [WORT ...]

  Optionen:
    --limit N      Nur die ersten N Treffer
    --plain        Ein Synonym pro Zeile (gut für Pipes und Skripte)
    --raw          Die rohe JSON-Antwort ausgeben
    --version      Version ausgeben
    -h, --help     Diese Hilfe

  Beispiele:
    synonyme.sh Haus
    synonyme.sh --limit 5 schnell
    synonyme.sh --plain Datei | fzf

  Als Shell-Funktion (in ~/.bashrc):
    syn() { /usr/local/bin/synonyme.sh "$@"; }

  Exit-Code:
    0  Treffer gefunden
    1  kein Treffer oder Dienst nicht erreichbar
    2  Aufruffehler

  Datenschutz: Das Suchwort geht per HTTPS an openthesaurus.de.
  Die Daten dort stehen unter CC-BY-SA — bei Weiterverwendung Quelle nennen.
EOF
}

die() { printf 'FEHLER: %s\n' "$1" >&2; exit 1; }

# ---- Argumente ----------------------------------------------
WORDS=()
while [[ $# -gt 0 ]]; do
    case "$1" in
        --limit)    LIMIT="${2:?--limit braucht eine Zahl}"; shift ;;
        --plain)    PLAIN=1 ;;
        --raw)      RAW=1 ;;
        --version)  printf 'synonyme.sh %s\n' "$VERSION"; exit 0 ;;
        -h|--help)  usage; exit 0 ;;
        --)         shift; WORDS+=("$@"); break ;;
        -*)         printf 'Unbekannte Option: %s\n\n' "$1" >&2; usage >&2; exit 2 ;;
        *)          WORDS+=("$1") ;;
    esac
    shift
done

[[ "${#WORDS[@]}" -gt 0 ]] || { usage >&2; exit 2; }
[[ "$LIMIT" =~ ^[0-9]+$ ]] || die "--limit braucht eine Zahl."
command -v curl >/dev/null || die "curl nicht gefunden (apt install curl)."

QUERY="${WORDS[*]}"

# ---- Abfrage -------------------------------------------------
# --data-urlencode übernimmt die Kodierung — wichtig für Umlaute und Leerzeichen.
RESPONSE=$(curl -fsSG --max-time "$TIMEOUT" \
    --data-urlencode "q=${QUERY}" \
    --data "format=application/json" \
    "$API" 2>/dev/null) || die "OpenThesaurus nicht erreichbar."

if [[ "$RAW" -eq 1 ]]; then
    printf '%s\n' "$RESPONSE"
    exit 0
fi

# ---- Auswerten -----------------------------------------------
# Absichtlich ohne jq: das Paket ist auf einem frischen Debian nicht
# installiert, und für "term"-Felder reicht grep vollkommen.
mapfile -t TERMS < <(
    printf '%s' "$RESPONSE" \
        | grep -o '"term":"[^"]*"' \
        | cut -d'"' -f4 \
        | grep -vixF "$QUERY" \
        | awk '!seen[$0]++'
)

if [[ "${#TERMS[@]}" -eq 0 ]]; then
    printf 'Keine Synonyme gefunden für: %s\n' "$QUERY" >&2
    exit 1
fi

if [[ "$LIMIT" -gt 0 && "$LIMIT" -lt "${#TERMS[@]}" ]]; then
    TERMS=("${TERMS[@]:0:$LIMIT}")
fi

if [[ "$PLAIN" -eq 1 ]]; then
    printf '%s\n' "${TERMS[@]}"
    exit 0
fi

# Kommagetrennt, an die Terminalbreite umgebrochen — aber nur, wenn die
# Ausgabe wirklich in einem Terminal landet. In einer Pipe wäre der
# Umbruch nur störend.
LINE=$(printf '%s, ' "${TERMS[@]}")
LINE="${LINE%, }"

if [[ -t 1 ]] && command -v tput >/dev/null && COLS=$(tput cols 2>/dev/null) && [[ "$COLS" -gt 20 ]]; then
    printf '%s\n' "$LINE" | fold -s -w "$COLS"
else
    printf '%s\n' "$LINE"
fi
Anzeige