Compare commits

...
33 Commits
Author SHA1 Message Date
Sven 2a7be25c65 Python erweitert 2026-09-23 20:44:48 +02:00
Sven 5c541dfcd8 Python und Rust erweitert 2026-09-22 18:56:36 +02:00
Sven Riwoldt c418fe6153 SQL nun wird es schwieriger 2026-09-22 13:39:21 +02:00
Sven af3537b17b Rust weiter, SQL weiter, Massmatics begonnen 2026-09-21 21:03:01 +02:00
Sven 19b153dd54 Schwedisch begonnen, die anderen erweitert 2026-09-20 11:11:11 +02:00
Sven 9610638462 Rust erweitert 2026-09-17 08:12:04 +02:00
Sven 815facc1cf Rust und Racket 2026-09-16 07:50:42 +02:00
Sven bc4dc789a3 Rust begonnen, da kommt wohl noch viel 2026-09-15 17:22:10 +02:00
Sven 1907fefb57 Lisp und Regex 2026-09-14 20:28:21 +02:00
Sven b331e333ca Alles erweitert 2026-09-14 14:00:27 +02:00
Sven 12515fe2eb Lisp und Scheme 2026-09-13 13:50:16 +02:00
Sven 5a732b5490 Python begonnen, Latex/Typst weiter formartiert 2026-09-10 14:17:00 +02:00
Sven ff77e6d7bb Latex Typst erweitert 2026-09-07 20:22:29 +02:00
Sven 01c73526de Formatierung 2026-09-07 15:02:41 +02:00
Sven b0d0884b76 Temp. erweitert 2026-09-07 12:35:07 +02:00
Sven f7478b9b25 Wieder aus Coddy erweitert 2026-09-07 07:54:54 +02:00
Sven df5138972f Grosse griechische Buchstaben, noch nicht fertig 2026-09-06 21:11:08 +02:00
Sven 3a63a33b2a Griechische Buchstaben weiter bearbeitet 2026-09-06 11:29:34 +02:00
Sven 9ce65c617a Codesnippets und Typst 2026-09-06 09:46:18 +02:00
Sven 2a36a62377 Assembler und Regex 2026-09-05 22:07:26 +02:00
Sven 1e5a7d318f SQL erweitert 2026-09-04 19:06:04 +02:00
Sven f2fe91fe30 SQL, Docker 2 aus Coddy erweitert 2026-09-04 08:07:47 +02:00
Sven Riwoldt c48157c54c SQL erweitert um Aufgabe 2026-08-27 14:40:38 +02:00
Sven Riwoldt 3b095316d4 Habe durch Claude noch Änderungen vornehmen lassen 2026-08-25 14:11:17 +02:00
Sven 67121fb3f6 Xdebug lt. claude 2026-08-24 19:58:21 +02:00
Sven 5a4eb08ca8 kleinere Umformulierungen 2026-08-20 15:28:11 +02:00
Sven Riwoldt d696ff35e7 SQL erweitert, neu: ansible, Linux umd passwd und shadows erweitert 2026-08-19 13:50:00 +02:00
Sven Riwoldt 2a8733f8f8 SINA DB Backup 2026-08-17 11:18:33 +02:00
Sven a2df2755cf Docker von Claude begonnen 2026-08-15 17:18:22 +02:00
Sven Riwoldt 17170f2ec4 PHP aufgenommen, Zertifikate begonnen 2026-08-10 13:59:56 +02:00
Sven Riwoldt 8e14f6594f php update begonnen 2026-08-07 13:45:20 +02:00
Sven Riwoldt 53da75bbc5 SQL Formatierungen, Linux erweitert um SNMP 2026-08-07 09:30:08 +02:00
Sven Riwoldt 5b00737df9 SQL Suche von Einzel-Werten in einer Spalte 2026-08-06 12:52:08 +02:00
26 changed files with 38358 additions and 248 deletions
+106
View File
@@ -0,0 +1,106 @@
# Assembler
## Die Maschine
### Was ist eine CPU
Die CPU (Central Processing Unit) ist das Gehirn des Computers. Aber im Gegensatz zu einem menschlichen Gehirn ist sie tatsächlich sehr einfach. Sie tut nur eine Sache: Sie liest Anweisungen aus dem Speicher und führt sie eine nach der anderen sehr schnell aus. Wenn du Assembly-Code schreibst, gibst du der CPU direkte Anweisungen.
Im Gegensatz zu Hochsprachen wie Python oder JavaScript, die Hardwaredetails verbergen, ermöglicht dir Assemblersprache, genau zu steuern, was die CPU Schritt für Schritt tut. 
Stell dir die CPU als einen sehr schnellen Arbeiter vor, der:
- Nicht selbstständig denken oder Entscheidungen treffen kann
- Einfache Befehle wie „add these two numbers“ oder „move this value there“ befolgt
- Jede Sekunde Millionen solcher einfachen Befehle ausführt
Im Inneren der CPU gibt es winzige Speicherboxen, die **Register** genannt werden. Ein Register enthält eine einzelne Zahl. Die CPU kann auf Register extrem schnell zugreifen, viel schneller als auf den Hauptspeicher (RAM).
Die CPU verfügt außerdem über ein spezielles Register namens **Program Counter (PC)**. Der PC enthält die Speicheradresse der nächsten auszuführenden Anweisung. Nach jeder Anweisung wechselt der PC automatisch zur nächsten Adresse.
**Wichtige Fakten über eine CPU:**
| Fakt | Erklärung |
| ------------------------------------------------- | -------------------------------------------------------------- |
| Sie führt jeweils eine Anweisung aus | Kein Multitasking auf Hardwareebene |
| Sie versteht nur Zahlen | Alles (Anweisungen, Daten, Adressen) ist eine Zahl |
| Sie hat keinen eigenen Speicher (außer Registern) | Alles muss im RAM gespeichert werden |
| Sie ist unglaublich schnell | Moderne CPUs führen Milliarden von Anweisungen pro Sekunde aus |
### Speicher
In der vorherigen Lektion hast du gelernt, dass die CPU Anweisungen eine nach der anderen ausführt. Aber wo werden diese Anweisungen gespeichert? Wo bewahrt die CPU die Daten auf, die sie verarbeiten muss?
Die Antwort lautet **Speicher** (auch RAM genannt: Random Access Memory).
Der Speicher ist wie ein riesiges Raster aus nummerierten Speicherplätzen. Jeder Speicherplatz hat eine eindeutige **Adresse** (wie eine Hausnummer) und kann ein Byte an Daten aufnehmen (eine Zahl von 0 bis 255). Wenn du etwas im Speicher speicherst, legst du es in einem bestimmten Speicherplatz mit einer bestimmten Adresse ab. Wenn du es wieder benötigst, rufst du die Daten an dieser Adresse ab.
**Stell dir den Speicher wie ein Postamt mit nummerierten Postfächern vor:**
- Jedes Fach hat eine eindeutige Nummer (die Adresse)
- Jedes Fach kann einen Brief aufnehmen (ein Byte an Daten)
- Du kannst einen Brief in jedes beliebige Fach legen
- Du kannst jedes beliebige Fach öffnen und lesen, was sich darin befindet
Die CPU kann die Daten an der Adresse 1000 anfordern, und der Speicher gibt sie zurück. Die CPU kann auch neue Daten an die Adresse 1000 schreiben und damit die zuvor dort vorhandenen Daten ersetzen.
**Wichtige Fakten über den Speicher:**
| Fakt | Erklärung |
| --------------------------------- | --------------------------------------------------------------------------------------------- |
| Jedes Byte hat eine Adresse | Adressen beginnen bei 0 und reichen bis zu Millionen oder Milliarden |
| Der Speicher ist flüchtig | Wenn du den Computer ausschaltest, verschwindet alles im RAM |
| Lesen zerstört keine Daten | Du kannst die Adresse 1000 eine Million Mal lesen, und sie enthält weiterhin denselben Wert |
| Schreiben überschreibt alte Daten | Wenn du neue Daten an die Adresse 1000 schreibst, sind die alten Daten für immer verschwunden |
## Wie Befehle funktionieren
Du weißt, dass die CPU Anweisungen eine nach der anderen ausführt. Aber woher weiß die CPU, welche Anweisung als Nächstes ausgeführt werden soll? Wo werden die Anweisungen gespeichert? Und wie sieht eine Anweisung eigentlich aus?
**Anweisungen sind Zahlen.**
Dies ist eine grundlegende Wahrheit über Computer. Alles ist eine Zahl. Die Daten, mit denen du arbeitest (wie die Zahl 42), sind eine Zahl. Die Adresse, an der die Daten gespeichert sind (wie 1000), ist eine Zahl. Und auch die Anweisungen selbst (wie `mov`, `add`, `cmp`) sind Zahlen.
Wenn du Assemblercode wie `mov rax, 5` schreibst, wandelt der Assembler diesen für Menschen lesbaren Text in eine Zahl um, die die CPU versteht. Diese Zahl wird **Instruktionscode** genannt.
**Wo werden Anweisungen gespeichert?**
Anweisungen werden wie Daten im Speicher gespeichert. Es gibt keinen speziellen Ort für Anweisungen. Der Speicher enthält beides:
- **Daten** (Zahlen, Zeichen, Arrays)
- **Anweisungen** (das Programm selbst)
Die CPU kennt den Unterschied nicht. Sie liest einfach, was sich an der Speicheradresse befindet, auf die der Program Counter zeigt. Du hast im Abschnitt 0.1 kurz etwas über den PC gelernt. Nun ist es an der Zeit, genau zu verstehen, wie er funktioniert.
Der <mark>Program Counter</mark> (auch Instruction Pointer genannt) ist ein spezielles Register innerhalb der CPU. Seine einzige Aufgabe besteht darin, die <mark>Speicheradresse der nächsten auszuführenden Anweisung</mark> zu speichern.
**Der Fetch-Execute-Zyklus:**
Die CPU wiederholt diese drei Schritte für immer:
| Schritt | Was passiert |
| ---------- | ---------------------------------------------------- |
| 1. FETCH | Die Anweisung an der in PC angegebenen Adresse lesen |
| 2. EXECUTE | Diese Anweisung ausführen |
| 3. ADVANCE | PC zur nächsten Anweisung weiterbewegen |
**Einfaches Beispiel:**
Wenn PC = 1000 ist, führt die CPU Folgendes aus:
- Ruft die Anweisung an der Adresse 1000 ab
- Führt sie aus
- Verschiebt PC zur nächsten Adresse (1000 + Größe der Anweisung)
Dann wird es mit dem neuen PC-Wert wiederholt.
**Wie eine Instruktion aussieht:**
Jede Instruktion besteht aus zwei Teilen:
| Teil | Was sie tut | Beispiel |
| --------- | --------------------------------- | ---------------------- |
| Opcode | Was AUSGEFÜHRT werden soll | `mov`, `add`, `cmp` |
| Operanden | WORAUF sie angewendet werden soll | `rax`, `5`, `[result]` |
Einige Anweisungen haben einen Operanden (wie `inc rax`, um 1 zu addieren). Einige haben zwei (wie `mov rax, 5`). Einige haben drei (wie `add rax, rbx, rcx` in manchen Architekturen).
+51
View File
@@ -0,0 +1,51 @@
# Codesnippets
## PHP
### IPV4 --> CIDR
```php
function subnetMaskToCidr(string $mask): int
{
$long = ip2long($mask);
if ($long === false) {
throw new InvalidArgumentException("Ungültige Subnetzmaske");
}
$cidr = 0;
for ($i = 31; $i >= 0; $i--) {
if (($long & (1 << $i)) !== 0) {
$cidr++;
} else {
break;
}
}
return $cidr;
}
```
oder
```php
function subnetMaskToCidr(string $mask): int
{
$octets = explode('.', $mask);
$cidr = 0;
foreach ($octets as $octet) {
while ($octet > 0) {
$cidr++;
$octet &= $octet - 1;
}
}
return $cidr;
}
```
+30
View File
@@ -0,0 +1,30 @@
# DB-Backup SINA
Das Backup müsste unter
/backup/<servername>/last/database/<servername>single/
liegen.
Vermutlich "backup_sinaconsole.sql.gz"
Kontrollieren, das alle SINA Consolen geschlossen sind
Das nach /tmp kopieren und entpacken
1. Alte Datenbank-Instanz löschen
dropdb sinaconsole
2. Neue Datenbank-Instanz anlegen
createdb -U root -O sina_admins sinaconsole
3. Datenbank-Backup einspielen
psql -U postgres -d sinaconsole <
/tmp/backup_sinaconsole.sql
+114
View File
@@ -0,0 +1,114 @@
# Docker
## Was ist Docker
**Docker** ist ein Tool, um eine Anwendung zusammen mit allem, was sie zum Ausführen benötigt (Code, Bibliotheken, Einstellungen), in einer einzigen Einheit namens **Container** zu verpacken.
Ein Container läuft immer auf die gleiche Weise, egal ob auf Ihrem Laptop, dem Rechner eines Teamkollegen oder einem Server in der Cloud. Dies löst das klassische „Auf meinem Rechner funktioniert es“-Problem.
Sie steuern Docker über das Terminal mit dem `docker`-Befehl.
Um zu prüfen, ob Docker verfügbar ist und um die Version anzuzeigen, führen Sie folgenden Befehl aus:
```bash
docker --version
```
Dies gibt die installierte Docker-Version aus und bestätigt, dass das Tool einsatzbereit ist.
## Images und Container
Docker hat zwei Kernkonzepte, die zusammenarbeiten: **Images** und **Container**.
Ein **Image** ist eine schreibgeschützte Vorlage (ein Snapshot eines Dateisystems plus Anweisungen dazu, was ausgeführt werden soll). <mark>Ein **Container** ist eine laufende Instanz</mark>, die aus einem Image erstellt wurde. Ein Image kann viele Container starten, so wie eine Klasse viele Objekte erstellen kann.
Der einfachste Weg, dies zu sehen, besteht darin, einen Container aus dem `hello-world` Image auszuführen:
```bash
docker run hello-world
```
Docker nimmt das `hello-world` Image, startet einen Container daraus, und der Container gibt eine kurze Willkommensnachricht aus, bevor er beendet wird.
## Images pullen
Bevor Sie einen Container ausführen können, benötigt Docker das Image auf Ihrem Rechner. Der Befehl `docker pull` lädt ein Image aus einer Registry (einer öffentlichen Bibliothek von Images) herunter:
```bash
docker pull alpine
```
Docker ruft das Image ab und meldet jede Ebene, sobald sie eintrifft, und schließt mit einer Statuszeile ab. Wenn Sie keine Version angeben, lädt Docker standardmäßig den Tag **latest** herunter.
Sie können eine spezifische Version mit `image:tag` anfordern:
```bash
docker pull alpine:3.20
```
Das Pulling eines bereits vorhandenen Images bestätigt <mark>lediglich</mark>, dass es <mark>aktuell</mark> ist, anstatt es erneut herunterzuladen.
## Images auflisten
Um zu sehen, welche Images lokal verfügbar sind, verwendet man `docker images`:
```bash
docker images
```
Die Ausgabe ist eine Tabelle mit einer Zeile pro Image:
```bash
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest c8be21c88f2a 1 day ago 7.34MB
ubuntu latest 75afc20638b6 4 days ago 81.8MB
```
- **REPOSITORY** und **TAG** benennen das Image
- **IMAGE ID** ist eine kurze eindeutige Kennung
- **SIZE** gibt an, wie viel Speicherplatz das Image belegt
Um die Liste auf ein Repository einzugrenzen, übergibt man dessen Namen:
`docker images alpine` zeigt nur die `alpine`-Tags an.
## Images taggen
Ein **Tag** ist eine benutzerfreundliche Bezeichnung, die auf ein Image verweist. Der Befehl `docker tag` gibt einem bestehenden Image einen zusätzlichen Namen:
```bash
docker tag alpine:3.21 myalpine:v1
```
Dies kopiert das Image nicht. Es erstellt einen neuen Namen, `myalpine:v1`, der auf dasselbe zugrunde liegende Image verweist wie `alpine:3.21`. Beide erscheinen nun in `docker images`.
Das Format ist `docker tag SOURCE:TAG TARGET:TAG`. Mit Tags geben Sie Ihren eigenen Builds aussagekräftige Versionsnamen wie `v1`, `dev` oder `stable`.
## Einen Befehl ausführen
Man kann einem Container genau sagen, welcher Befehl ausgeführt werden soll, indem man ihn nach dem Imagenamen hinzufügt:
```bash
docker run alpine echo "hello from a container"
```
Docker startet einen Container aus dem `alpine`-Image, führt darin `echo "hello from a container"` aus, gibt die Ausgabe aus und beendet anschließend den Container. Die Struktur lautet:
```bash
docker run IMAGE COMMAND [ARGUMENTS]
```
Dies ist das alltägliche Muster für die Verwendung eines Containers als Wegwerfumgebung: Starten, ausführen eines Befehls und stoppen.
### Echte Ausführung
Befehle innerhalb eines Containers werden tatsächlich ausgeführt und nicht nur als vorgetäuschte Ausgabe wiedergegeben. Du kannst das beweisen, indem du dem Container eine Shell und ein kleines Skript übergibst:
```bash
docker run alpine sh -c "echo abc | tr a-z A-Z"
docker run alpine sh -c "seq 3"
```
Hier führt `sh -c` eine Shell-Befehlszeichenfolge innerhalb des Containers aus. Die Shell leitet `abc` an `tr` weiter, was es in Großbuchstaben umwandelt, sodass die Ausgabe `ABC` ist.
Das bedeutet, dass Sie Pipes, Variablen und die Befehlszeilenwerkzeuge, die Sie bereits kennen, direkt im Container verwenden können.
+442
View File
@@ -0,0 +1,442 @@
# LaTeX -- Typst
## Griechische Buchstaben
### kleine griechische Buchstaben
| LaTeX | Vorschau | Typst |
|:------------- | ------------- | ---------------------- |
| `\alpha` | $\alpha$ | alpha |
| `\beta` | $\beta$ | beta |
| `\gamma` | $\gamma$ | gamma |
| `\delta` | $\delta$ | delta |
| `\epsilon` | $\epsilon$ | epsilon.alt |
| `\zeta` | $\zeta$ | zeta |
| `\eta` | $\eta$ | eta |
| `\theta` | $\theta$ | theta |
| `\iota` | $\iota$ | iota |
| `\kappa` | $\kappa$ | kappa |
| `\lambda` | $\lambda$ | lambda |
| `\mu` | $\mu$ | mu |
| `\nu` | $\nu$ | nu |
| `\xi` | $\xi$ | xi |
| `\omicron` | $\omicron$ | omnicron |
| `\pi` | $\pi$ | pi |
| `\rho` | $\rho$ | rho |
| `\sigma` | $\sigma$ | sigma |
| `\tau` | $\tau$ | tau |
| `\upsilon` | $\upsilon$ | upsilon <—- bis hier |
| `\phi` | $\phi$ | phi.alt |
| `\chi` | $\chi$ | chi |
| `\psi` | $\rho$ | rho |
| `\omega` | $\omega$ | omega |
| `\varepsilon` | $\varepsilon$ | epsilion |
| `\vartheta` | $\vartheta$ | theta.alt |
| `\varpi` | $\varpi$ | pi.alt |
| `\varrho` | $\varrho$ | rho.alt |
| `\varsigma` | $\varsigma$ | sigma.alt |
| `\varphi` | $\varphi$ | phi |
### Grosse griechische Buchstaben
| LaTeX | Vorschau | Typst |
| :--------- | ---------- | ------- |
| `\Gamma` | $\Gamma$ | Gamma |
| `\Delta` | $\Delta$ | Delta |
| `\Theta` | $\Theta$ | Theta |
| `\Lambda` | $\Lambda$ | Lambda |
| `\Xi` | $\Xi$ | Xi |
| `\Pi` | $\Pi$ | Pi |
| `\Sigma` | $\Sigma$ | Sigma |
| `\Upsilon` | $\Upsilon$ | Upsilon |
| `\Phi` | $\Phi$ | Phi |
| `\Psi` | $\Psi$ | Psi |
| `\Omega` | $\Omega$ | Omega |
### Integral
| LaTeX | Vorschau | Typst |
| :--------- | ---------- | ------- |
| `\int_a^b f(x) \mathrm{d} x` | $\int_a^b f(x) \mathrm{d} x$ | integral_a^b f(x) dif x |
| `\int` | $\int$ | integral |
| `\oint` | $\oint$ | integral.cont |
| `\iint` | $\iint$ | integral.double |
| `\oiint` | $\oiint$ | integral.surf |
| `\iiint` | $\iiint$ | integral.triple |
| `\oiiint` | $\oiiint$ | integral.vol |
### Fonts
| LaTeX | Vorschau | Typst |
| :--------------- | ---------------- | ------- |
| `\boldsymbol{A}` | $\boldsymbol{A}$ | bold(A) |
| `\mathbb{A}` | $\mathbb{A}$ | AA |
| `\mathbf{A}` | $\mathbf{A}$ | upright(bold(A)) |
| `\mathcal{A}` | $\mathcal{A}$ | cal(A) |
| `\mathscr{A}` | $\mathscr{A}$ | scr(A) |
| `\mathit{A}` | $\mathit{A}$ | italic(A) |
| `\mathfrak{A}` | $\mathfrak{A}$ | frak(A) |
| `\mathrm{A}` | $\mathrm{A}$ | upright(A) |
| `\mathsf{A}` | $\mathsf{A}$ | sans(A) |
| `\mathtt{A}` | $\mathtt{A}$ | mono(A) |
## Arrows
| LaTeX | Preview | Typst (Textual) | Typst (Shorthand) |
| --------------------- | --------------------- | --------------------- | ----------------- |
| `\leftarrow` | $\leftarrow$ | arrow.l | <- |
| `\gets` | $\gets$ | arrow.l | <- |
| `\rightarrow` | $\rightarrow$ | arrow.r | -> |
| `\to` | $\to$ | arrow.r | -> |
| `\leftrightarrow` | $\leftrightarrow$ | arrow.l.r | <-> |
| `\Leftarrow` | $\Leftarrow$ | arrow.l.double | |
| `\Rightarrow` | $\Rightarrow$ | arrow.r.double | => |
| `\Leftrightarrow` | $\Leftrightarrow$ | arrow.l.r.double | <=> |
| `\mapsto` | $\mapsto$ | arrow.r.bar | -> |
| `\hookleftarrow` | $\hookleftarrow$ | arrow.l.hook | |
| `\leftharpoonup` | $\leftharpoonup$ | harpoon.lt | |
| `\leftharpoondown` | $\leftharpoondown$ | harpoon.lb | |
| `\rightleftharpoons` | $\rightleftharpoons$ | harpoons.rtlb | |
| `\longleftarrow` | $\longleftarrow$ | arrow.l.long | <-- |
| `\longrightarrow` | $\longrightarrow$ | arrow.r.long | --> |
| `\longleftrightarrow` | $\longleftrightarrow$ | arrow.l.r.long | <--> |
| `\Longleftarrow` | $\Longleftarrow$ | arrow.l.double.long | <== |
| `\Longrightarrow` | $\Longrightarrow$ | arrow.r.double.long | ==> |
| `\Longleftrightarrow` | $\Longleftrightarrow$ | arrow.l.r.double.long | <==> |
| `\longmapsto` | $\longmapsto$ | arrow.r.long.bar | |
| `\hookrightarrow` | $\hookrightarrow$ | arrow.r.hook | |
| `\rightharpoonup` | $\rightharpoonup$ | harpoon.rt | |
| `\rightharpoondown` | $\rightharpoondown$ | harpoon.rb | |
| `\iff` | $\iff$ | arrow.l.r.double.long | <==> |
| `\implies` | $\implies$ | arrow.r.double.long | ==> |
| `\uparrow` | $\uparrow$ | arrow.t | |
| `\downarrow` | $\downarrow$ | arrow.b | |
| `\updownarrow` | $\updownarrow$ | arrow.t.b | |
| `\Uparrow` | $\Uparrow$ | arrow.t.double | |
| `\Downarrow` | $\Downarrow$ | arrow.b.double | |
| `\Updownarrow` | $\Updownarrow$ | arrow.t.b.double | |
| `\nearrow` | $\nearrow$ | arrow.tr | |
| `\searrow` | $\searrow$ | arrow.br | |
| `\swarrow` | $\swarrow$ | arrow.bl | |
| `\nwarrow` | $\nwarrow$ | arrow.tl | |
| `\leadsto` | $\leadsto$ | arrow.r.squiggly | ~> |
| `\leftleftarrows` | $\leftleftarrows$ | arrows.ll | |
| `\rightrightarrows` | $\rightleftarrows$ | arrows.rr | |
## Set and Elements
| LaTeX | Preview | Typst |
| ------------- | ------------- | --------- |
| `\in` | $\in$ | in |
| `\subset` | $\subset$ | subset |
| `\subseteq` | $\subseteq$ | subset.eq |
| `\supset` | $\supset$ | supset |
| `\supseteq` | $\supseteq$ | supset.eq |
| `\varnothing` | $\varnothing$ | diameter |
## Non-mathematical Symbols
| LaTeX | Preview | Typst |
| ------------ | ------------ | --------- |
| `\$` | $\$$ | \\$ |
| `\pounds` | $\pounds$ | pound |
| `\yen` | $\yen$ | yen |
| `\copyright` | $\copyright$ | copyright |
| `\S` | $\S$ | section |
| `\P` | $\P$ | pilcrow |
## Verschiedene Symbole
| LaTeX | Preview | Typst (Textual) | Typst (Shorthand) |
| -------- | -------- | --------------- | ----------------- |
| `\Cap` | $\Cap$ | inter.double | |
| `\Cup` | $\Cup$ | union.double | |
| `\Join` | $\Join$ | join | |
| `\aleph` | $\aleph$ | alef | |
| | | | |
# Temp
## Miscellaneous Symbols
| LaTeX | Preview | Typst (Textual) | Typst (Shorthand) |
| -------------------- | ------- | ------------------ | ----------------- |
| `\angle` | ∠ | `angle` | `` |
| `\approx` | ≈ | `approx` | `` |
| `\approxeq` | ≊ | `approx.eq` | `` |
| `\ast` | ∗ | `ast` | `` |
| `\bigcap` | ⋂ | `inter.big` | `` |
| `\bigcirc` | ◯ | `circle.big` | `` |
| `\bigcup` | ⋃ | `union.big` | `` |
| `\bigodot` | ⨀ | `dot.o.big` | `` |
| `\bigoplus` | ⨁ | `xor.big` | `` |
| `\bigotimes` | ⨂ | `times.o.big` | `` |
| `\bigsqcup` | ⨆ | `union.sq.big` | `` |
| `\bigtriangledown` | ▽ | `triangle.b` | `` |
| `\bigtriangleup` | △ | `triangle.t` | `` |
| `\biguplus` | ⨄ | `union.plus.big` | `` |
| `\bigvee` | ⋁ | `or.big` | `` |
| `\bigwedge` | ⋀ | `and.big` | `` |
| `\bullet` | ∙ | `bullet` | `` |
| `\cap` | ∩ | `inter` | `` |
| `\cdot` | ⋅ | `dot.op` | `` |
| `\cdots` | ⋯ | `dots.c` | `` |
| `\checkmark` | ✓ | `checkmark` | `` |
| `\circ` | ∘ | `circle.small` | `` |
| `\colon` | : | `colon` | `` |
| `\cong` | ≅ | `tilde.equiv` | `` |
| `\coprod` | ∐ | `product.co` | `` |
| `\cup` | ∪ | `union` | `` |
| `\curlyvee` | ⋎ | `or.curly` | `` |
| `\curlywedge` | ⋏ | `and.curly` | `` |
| `\dagger` | † | `dagger` | `` |
| `\dashv` | ⊣ | `tack.l` | `` |
| `\ddagger` | ‡ | `dagger.double` | `` |
| `\ddots` | ⋱ | `dots.down` | `` |
| `\diamond` | ⋄ | `diamond` | `` |
| `\div` | ÷ | `div` | `` |
| `\divideontimes` | ⋇ | `times.div` | `` |
| `\dotplus` | ∔ | `plus.dot` | `` |
| `\ell` | ℓ | `ell` | `` |
| `\emptyset` | ∅ | `nothing` | `` |
| `\equiv` | ≡ | `equiv` | `` |
| `\exists` | ∃ | `exists` | `` |
| `\forall` | ∀ | `forall` | `` |
| `\ge` | ≥ | `gt.eq` | `>=` |
| `\geq` | ≥ | `gt.eq` | `>=` |
| `\geqslant` | ⩾ | `gt.eq.slant` | `` |
| `\gg` | ≫ | `gt.double` | `>>` |
| `\hbar` | ℏ | `planck` | `` |
| `\imath` | ** | `dotless.i` | `` |
| `\infty` | ∞ | `infinity` | `oo` |
| `\intercal` | ⊺ | `top` | `` |
| `\jmath` | ** | `dotless.j` | `` |
| `\land` | ∧ | `and` | `` |
| `\langle` | ⟨ | `chevron.l` | `` |
| `\lbrace` | { | `brace.l` | `` |
| `\lbrack` | [ | `bracket.l` | `` |
| `\ldots` | … | `dots.l` | `` |
| `\le` | ≤ | `lt.eq` | `<=` |
| `\leftthreetimes` | ⋋ | `times.three.l` | `` |
| `\leq` | ≤ | `lt.eq` | `<=` |
| `\leqslant` | ⩽ | `lt.eq.slant` | `` |
| `\lhd` | ⊲ | `triangle.l` | `` |
| `\ll` | ≪ | `lt.double` | `<<` |
| `\ltimes` | ⋉ | `times.l` | `` |
| `\measuredangle` | ∡ | `angle.arc` | `` |
| `\mid` | ∣ | `divides` | `` |
| `\models` | ⊨ | `models` | `` |
| `\mp` | ∓ | `minus.plus` | `` |
| `\nRightarrow` | ⇏ | `arrow.double.not` | `` |
| `\nabla` | ∇ | `nabla` | `` |
| `\ncong` | ≆ | `tilde.nequiv` | `` |
| `\ne` | = | `eq.not` | `!=` |
| `\neg` | ¬ | `not` | `` |
| `\neq` | = | `eq.not` | `!=` |
| `\nexists` | ∄ | `exists.not` | `` |
| `\ngeq` | ≱ | `gt.eq.not` | `` |
| `\ni` | ∋ | `in.rev` | `` |
| `\nleftarrow` | ↚ | `arrow.l.not` | `` |
| `\nleq` | ≰ | `lt.eq.not` | `` |
| `\nparallel` | ∦ | `parallel.not` | `` |
| `\nmid` | ∤ | `divides.not` | `` |
| `\notin` | ∈/ | `in.not` | `` |
| `\nrightarrow` | ↛ | `arrow.not` | `` |
| `\nsim` | ≁ | `tilde.not` | `` |
| `\nsubseteq` | ⊈ | `subset.eq.not` | `` |
| `\ntriangleleft` | ⋪ | `lt.tri.not` | `` |
| `\ntriangleright` | ⋫ | `gt.tri.not` | `` |
| `\odot` | ⊙ | `dot.o` | `` |
| `\ominus` | ⊖ | `minus.o` | `` |
| `\oplus` | ⊕ | `xor` | `` |
| `\otimes` | ⊗ | `times.o` | `` |
| `\parallel` | ∥ | `parallel` | `` |
| `\partial` | ∂ | `partial` | `` |
| `\perp` | ⊥ | `perp` | `` |
| `\pm` | ± | `plus.minus` | `` |
| `\prec` | ≺ | `prec` | `` |
| `\preceq` | ⪯ | `prec.eq` | `` |
| `\prime` | ′ | `prime` | `` |
| `\prod` | ∏ | `product` | `` |
| `\propto` | ∝ | `prop` | `` |
| `\rangle` | ⟩ | `chevron.r` | `` |
| `\rbrace` | } | `brace.r` | `` |
| `\rbrack` | ] | `bracket.r` | `` |
| `\rhd` | ⊳ | `triangle` | `` |
| `\rightthreetimes` | ⋌ | `times.three.r` | `` |
| `\rtimes` | ⋊ | `times.r` | `` |
| `\setminus` | ∖ | `without` | `` |
| `\sim` | ∼ | `tilde` | `` |
| `\simeq` | ≃ | `tilde.eq` | `` |
| `\smallsetminus` | ∖ | `without` | `` |
| `\spadesuit` | ♠ | `suit.spade` | `` |
| `\sqcap` | ⊓ | `inter.sq` | `` |
| `\sqcup` | ⊔ | `union.sq` | `` |
| `\sqsubseteq` | ⊑ | `subset.eq.sq` | `` |
| `\sqsupseteq` | ⊒ | `supset.eq.sq` | `` |
| `\star` | ⋆ | `star` | `` |
| `\subsetneq` | ⊊ | `subset.neq` | `` |
| `\succ` | ≻ | `succ` | `` |
| `\succeq` | ⪰ | `succ.eq` | `` |
| `\sum` | ∑ | `sum` | `` |
| `\supsetneq` | ⊋ | `supset.neq` | `` |
| `\times` | × | `times` | `` |
| `\top` | ⊤ | `top` | `` |
| `\triangle` | △ | `triangle.t` | `` |
| `\triangledown` | ▽ | `triangle.b.small` | `` |
| `\triangleleft` | ◃ | `triangle.l.small` | `` |
| `\triangleright` | ▹ | `triangle.r.small` | `` |
| `\twoheadrightarrow` | ↠ | `arrow.r.twohead` | `->>` |
| `\upharpoonright` | ↾ | `harpoon.tr` | `` |
| `\uplus` | ⊎ | `union.plus` | `` |
| `\vdash` | ⊢ | `tack.r` | `` |
| `\vdots` | ⋮ | `dots.v` | `` |
| `\vee` | ∨ | `or` | `` |
| `\wedge` | ∧ | `and` | `` |
| `\wr` | ≀ | `wreath` | |
# Implementing LaTeX macros unsupported by Typst
## Background
There is not always a Typst equivalent for every LaTeX macro. This document provides a guide on how to implement unsupported LaTeX macros in Typst.
## The `\mathscr` macro
`scr` is natively supported in Typst since version 0.14.0! [[1\]](https://qwinsi.github.io/tex2typst-webapp/impl-in-typst.html#fn1)
## The `\LaTeX` and `\TeX` macro
LaTeX: `\LaTeX` and `\TeX`
Implementation in Typst [[2\]](https://qwinsi.github.io/tex2typst-webapp/impl-in-typst.html#fn2)
```
#let TeX = context {
set text(font: "New Computer Modern")
let e = measure("E")
let T = "T"
let E = text(1em, baseline: e.height * 0.31, "E")
let X = "X"
box(T + h(-0.15em) + E + h(-0.125em) + X)
}
#let LaTeX = context {
set text(font: "New Computer Modern")
let a-size = 0.66em
let l = measure("L")
let a = measure(text(a-size, "A"))
let L = "L"
let A = box(scale(x: 105%, text(a-size, baseline: a.height - l.height, "A")))
box(L + h(-a.width * 0.67) + A + h(-a.width * 0.25) + TeX)
}
```
Usage example:
```
You can use #LaTeX in text environments.
You can use $#LaTeX$ in math environments as well.
```
## Using the `op` function to define custom operators
For example, if you want to define a custom operator `\myopr`.
LaTeX: `\newcommand{\myopr}{\operatorname{myopr}}`
Equivalent in Typst:
```
#let myopr = op("myopr");
```
Usage example:
```
$
y = myopr x
$
```
## A vertical bar for evaluation
It's common to use a vertical bar to denote the evaluation of a function at a point. e.g.
➣ LaTeX:
```
f(x) \bigg\rvert_{x = x_0}
```
Where `\bigg\rvert` may be replaced with `\bigg\vert`, `\bigg|` etc.
➣ Walkaround in Typst:
```
f(x) lr(| vec(delim: #none, , , x = x_0))
```
Also it's common to use a vertical bar to denote the deference of function values at two points, especially when calculating definite integrals. e.g. [[3\]](https://qwinsi.github.io/tex2typst-webapp/impl-in-typst.html#fn3)
➣ LaTeX:
```
F(x) \bigg\rvert_{a}^{b}
```
Where `\bigg\rvert` may be replaced with `\bigg\vert` , `\bigg|` etc.
➣ Walkaround in Typst:
```
F(x) lr(| vec(delim: #none, b, , a))
```
## The `\cancelto` macro
`\cancelto{value}{expression}` is a LaTeX command provided by the `cancel` package. It is used to place an arrow through an expression and annotate it with a value to which the expression is be evaluated.
➣ LaTeX:
```
\cancelto{0}{\frac{\partial^2 Q}{\partial r^2}}
```
➣ Implementation in Typst (adapted from [[4\]](https://qwinsi.github.io/tex2typst-webapp/impl-in-typst.html#fn4) ):
```
#let cancelto(to, body) = {
let max(a, b) = if a > b { a } else { b };
context {
let m = measure(body)
let (w, h) = (m.width, m.height * 2)
let arrow = rotate(-55deg, math.stretch(sym.arrow.r, size: max(h*1.8, w*2.0)))
set place(center + horizon)
body
place(dx: -w * 0.5, dy: -h * 0.1, arrow)
place(dx: w * 0.3, dy: -h * 1.1, to)
}
}
```
➣ Usage example:
```
$
cancelto(0, (partial^2 Q)/(partial r^2))
$
```
https://qwinsi.github.io/tex2typst-webapp/cheat-sheet.html
+687 -6
View File
@@ -49,11 +49,11 @@ mkdir -p ~/src
### Für mehrere Benutzer ### Für mehrere Benutzer
| Verzeichnis | Zweck | | Verzeichnis | Zweck |
|-------------|-------| | ----------------- | ----------------------------------------------------------------- |
| `/srv/` | Gemeinsam genutzte Projekte oder Dienste | | `/srv/` | Gemeinsam genutzte Projekte oder Dienste |
| `/usr/local/src/` | Systemweiter Quellcode | | `/usr/local/src/` | Systemweiter Quellcode |
| `/opt/` | Installierte Drittanbieter-Software (nicht für eigenen Quellcode) | | `/opt/` | Installierte Drittanbieter-Software (nicht für eigenen Quellcode) |
--- ---
@@ -137,7 +137,7 @@ find ~/Downloads -name "*.zip" -delete
--- ---
# `xargs` erklärt # xargs erklärt
## Was macht `xargs`? ## Was macht `xargs`?
@@ -307,11 +307,13 @@ find . -name "*.log" -print0 | xargs -0 rm
### `find` ### `find`
- Dateien suchen: - Dateien suchen:
```bash ```bash
find . -name "*.txt" find . -name "*.txt"
``` ```
- Direkt löschen: - Direkt löschen:
```bash ```bash
find . -name "*.txt" -delete find . -name "*.txt" -delete
``` ```
@@ -335,3 +337,682 @@ find . -exec <befehl> {} +
``` ```
Diese Variante ist oft einfacher und ebenso effizient. Diese Variante ist oft einfacher und ebenso effizient.
# SNMP: MIB-Auflösung und OID-Übersetzung mit net-snmp
## OIDs werden trotz eingehängter MIB nicht textuell aufgelöst
### Mögliche Ursachen
**MIB wird nicht geladen**
- MIB liegt nicht in einem durchsuchten Verzeichnis. Prüfen mit `net-snmp-config --default-mibdirs`; übliche Pfade sind `~/.snmp/mibs`, <mark>`/usr/share/snmp/mibs</mark>`.
- MIB nicht per `-m` oder Konfiguration aktiviert. Test: `snmpwalk -m ALL ...` oder in `~/.snmp/snmp.conf` bzw. `/etc/snmp/snmp.conf`: `mibs +MEIN-MIB`.
- net-snmp lädt standardmäßig nur ein Minimalset. `mibs :` deaktiviert alles.
**Dateiname passt nicht zum MIB-Namen**
- net-snmp löst Module über den Dateinamen auf; der interne Modulname (vor `DEFINITIONS ::= BEGIN`) muss stimmen.
**Fehlende IMPORTS / Abhängigkeiten**
- Importierte MIBs (z. B. `SNMPv2-SMI`, `SNMPv2-TC`, herstellereigene Basis-MIBs) fehlen → Parsen schlägt still fehl. Sichtbar machen mit:
```bash
snmptranslate -M+/pfad -m ALL -Dparse-mibs OID
```
**Parse-/Syntaxfehler in der MIB**
- Diagnose:
```bash
snmptranslate -Le -m ALL -M /pfad -On MEIN-MIB::objekt
```
Fehler werden auf stderr ausgegeben.
**Numerische OID gehört zu keinem geladenen Zweig**
- Die abgefragte Enterprise-OID liegt außerhalb dessen, was die MIB definiert (falsche/unvollständige MIB).
### Schneller Prüfweg
1. `snmptranslate -m +MEIN-MIB -IR meinObjekt` → gibt es einen Treffer?
2. `snmptranslate -Le -M /pfad/zu/mibs -m ALL .1.3.6.1.4.1.<enterprise>` → Fehler beim Laden?
3. Fehlende Import-MIBs nachlegen.
Meist ist es eine fehlende Import-Abhängigkeit oder ein falscher Suchpfad/Modulname.
---
## Umgekehrt: von `MIB::objekt` auf die OID schließen
Textuellen Namen statt numerischer OID übergeben (MIB muss geladen sein):
```bash
snmpget -v2c -c public host MEIN-MIB::meinObjekt.0
snmpwalk -v2c -c public host MEIN-MIB::meinObjekt
```
### Vorher ohne Gerät prüfen (Name → OID)
```bash
snmptranslate -On MEIN-MIB::meinObjekt
```
`-On` erzwingt die numerische Ausgabe, also die zugehörige OID.
Umgekehrt (OID → Name):
```
snmptranslate .1.3.6.1.4.1.xxx
```
### Nützliche Varianten
- Objektname allein suchen (ohne `MIB::`-Präfix):
```
snmptranslate -IR -On meinObjekt
```
- Vollständigen symbolischen Pfad anzeigen:
```
snmptranslate -Of MEIN-MIB::meinObjekt
```
- Objektdetails (Typ, Zugriff, Beschreibung):
```
snmptranslate -Td MEIN-MIB::meinObjekt
```
### Hinweise
- Scheitert `snmpget MEIN-MIB::meinObjekt.0` mit „Unknown Object Identifier", ist die MIB nicht geladen → mit `-m +MEIN-MIB` bzw. `-M /pfad` ergänzen.
- Bei skalaren Objekten die `.0`-Instanz nicht vergessen.
# Idoit von 35 auf 38
Test auf Masternode
- kein main-Mode
- ohne ansible
## php8.2 zu 8.4
8.2-Module ermitteln, die Ausgabe listet die entsprechenden 8.4-Paketnamen
```bash
dpkg -l | grep '^ii php8.2' | awk '{print $2}' | sed 's/8.2/8.4/'
```
Update der entsprechenden Pakete
```bash
apt update
apt install -y $(dpkg -l | grep '^ii php8.2' | awk '{print $2}' | sed 's/8.2/8.4/')
```
Umschalten (mod_php/Apache) und CLI
```bash
a2dismod php8.2 && a2enmod php8.4
crm res restart rcapache2
update-alternatives --set php /usr/bin/php8.4
```
# Zertifikate
## Ein CSR (Certificate Signing Request) erstellen (bei vorhandenem )
```bash
openssl req -new -key server.key -out server.csr
```
Hier werden dann einige Daten abgefragt. Daher ist es einfacher mit einem Config-File das man mit übergibt
```bash
openssl req -new -key server.key -out server.csr -config config.req
```
### Muster für ein Config-File
```bash
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = req_cert_ext
prompt = no
default_days = 365
[ req_distinguished_name ]
#
# requested SubjectDN
#
C = DE
O = Bund
OU = Service
CN = cmdb01.adm.ivbb.bund.de
emailAddress = mail@bund.de
[req_cert_ext]
#
subjectAltName = @alt_names
## requested SubjectAlternativeNames (SANs)
[ alt_names ]
DNS.1 = cmdb01.adm.ivbb.bund.de
DNS.2 = mlseazcmd01.adm.ivbb.bund.de
DNS.3 = mlsfazcmd01.adm.ivbb.bund.de
```
## Betrachten des CSR
```bash
openssl req -text -in <csr>
```
#### Notizen zu Zertifikate
##### Private Key erstellen
openssl genrsa -out $HOME/servercrt/dlsea3tim01.server.key 2048
##### Zertifikatsrequest erstellen
openssl req -new -days 1095 -key dlsea3tim01.server.key -out dlsea3tim01.server.csr -config req_config.dlsea3tim01.adm.ivbb.bund.de
##### Zertifikatsrequest ansehen
openssl req -text -in dlsea3tim01.server.csr|less
Bei Apache/mod_ssl ist der Unterschied:
- **`SSLCertificateFile`** → enthält das **öffentliche Zertifikat** des Servers. Darin stecken u. a. der öffentliche Schlüssel, Domainname und die Signatur der CA. Dieses Zertifikat wird beim TLS-Handshake an den Client geschickt.
- **`SSLCertificateKeyFile`** → enthält den dazugehörigen **privaten Schlüssel**. Er bleibt ausschließlich auf dem Server und darf **niemals veröffentlicht** werden.
# SCP
```bash
scp [Optionen] [Quelle] [Ziel]
```
### Optionen
Dies sind optionale Flags, die das Verhalten des SCP-Befehls verändern. Sie können verschiedene Optionen verwenden, um den Übertragungsprozess individuell zu gestalten. Hier sind einige gängige Optionen:
**-r:** Kopiert Verzeichnisse und deren Inhalte rekursiv.
**-p:** Behält die Berechtigungen, Zeitstempel und Modi der Originaldatei bei.
–**P**: Gibt die Portnummer für die SSH-Verbindung an.
–**i**: Gibt die private Schlüsseldatei für die SSH-Authentifizierung an.
**-C:** Verwenden Sie die Komprimierung, um die Datenübertragung zu beschleunigen.
**-l:** Begrenzen Sie die für die Übertragung verwendete Bandbreite (in Kbit/s).
**-v:** Ausführlicher Modus – zeigt Debugging-Meldungen während der Übertragung an.
**-o:** Übergibt eine Option an den SSH-Client. Sie kann verwendet werden, um die strenge Prüfung des Hostschlüssels zu deaktivieren.
# Linux: `/etc/passwd` und `/etc/shadow`
Unter Linux werden Benutzerinformationen hauptsächlich in den Dateien `/etc/passwd` und `/etc/shadow` gespeichert.
- `/etc/passwd` enthält allgemeine Informationen über Benutzerkonten.
- `/etc/shadow` enthält sensible Informationen zur Passwort- und Accountverwaltung.
---
## 1. `/etc/passwd`
Die Datei `/etc/passwd` enthält pro Benutzer eine Zeile.
### Beispiel
```text
max:x:1001:1001:Max Mustermann:/home/max:/bin/bash
```
Die einzelnen Felder werden durch einen Doppelpunkt (`:`) getrennt.
```text
max:x:1001:1001:Max Mustermann:/home/max:/bin/bash
 │  │   │    │         │           │          │
 │  │   │    │         │           │          └─ Login-Shell
 │  │   │    │         │           └─ Home-Verzeichnis
 │  │   │    │         └─ Kommentar / GECOS
 │  │   │    └─ primäre GID
 │  │   └─ UID
 │  └─ Passwort-Platzhalter
 └─ Benutzername
```
### Aufbau
| Feld | Beispiel | Bedeutung |
|---|---|---|
| 1 | `max` | Benutzername |
| 2 | `x` | Passwort-Platzhalter |
| 3 | `1001` | UID – User ID |
| 4 | `1001` | GID – primäre Group ID |
| 5 | `Max Mustermann` | Kommentar / GECOS |
| 6 | `/home/max` | Home-Verzeichnis |
| 7 | `/bin/bash` | Login-Shell |
### Feld 1 – Benutzername
```text
max
```
Der eindeutige Name, unter dem der Benutzer im System bekannt ist.
---
### Feld 2 – Passwort-Platzhalter
```text
x
```
Das `x` bedeutet, dass sich die eigentlichen Passwortinformationen in `/etc/shadow` befinden.
Historisch konnten Passwort-Hashes direkt in `/etc/passwd` gespeichert werden. Das wäre heute problematisch, da `/etc/passwd` normalerweise für alle Benutzer lesbar sein muss.
---
### Feld 3 – UID
```text
1001
```
Die **UID (User ID)** ist die numerische Kennung des Benutzers.
Linux arbeitet intern an vielen Stellen mit der UID und nicht mit dem Benutzernamen.
Beispielsweise besitzt `root` normalerweise die UID:
```text
0
```
---
### Feld 4 – GID
```text
1001
```
Die **GID (Group ID)** gibt die primäre Gruppe des Benutzers an.
Weitere Gruppenzugehörigkeiten werden normalerweise über `/etc/group` bzw. entsprechende Benutzerverwaltungsdienste bestimmt.
---
### Feld 5 – GECOS / Kommentar
```text
Max Mustermann
```
Dieses Feld kann zusätzliche Informationen über den Benutzer enthalten, beispielsweise:
- vollständiger Name
- Raumnummer
- Telefonnummer
- sonstige Informationen
---
### Feld 6 – Home-Verzeichnis
```text
/home/max
```
Das Home-Verzeichnis des Benutzers.
Nach einem normalen Login befindet sich der Benutzer üblicherweise in diesem Verzeichnis.
---
### Feld 7 – Login-Shell
```text
/bin/bash
```
Die Shell, die nach einem Login gestartet werden soll.
Beispiele:
```text
/bin/bash
/bin/sh
/bin/zsh
```
Bei Systemkonten findet man häufig auch:
```text
/usr/sbin/nologin
```
oder:
```text
/bin/false
```
Damit soll normalerweise ein interaktiver Login verhindert werden.
---
# 2. `/etc/shadow`
Die Datei `/etc/shadow` enthält die sensiblen Passwort- und Ablaufinformationen eines Benutzers.
Sie ist deshalb im Gegensatz zu `/etc/passwd` normalerweise nur für `root` bzw. entsprechend privilegierte Prozesse lesbar.
### Beispiel
```text
max:$6$...:20680:0:99999:7:::
```
Eine Zeile besteht aus **9 Feldern**:
```text
max:$6$...:20680:0:99999:7:::
 │      │      │   │    │   │ │ │ │
 │      │      │   │    │   │ │ │ └─ reserviert
 │      │      │   │    │   │ │ └─ Account-Ablauf
 │      │      │   │    │   │ └─ Inaktivität
 │      │      │   │    │   └─ Warnzeit
 │      │      │   │    └─ maximales Passwortalter
 │      │      │   └─ minimales Passwortalter
 │      │      └─ letzte Passwortänderung
 │      └─ Passwort-Hash / Passwortstatus
 └─ Benutzername
```
## Aufbau
| Feld | Bedeutung |
|---|---|
| 1 | Benutzername |
| 2 | Passwort-Hash / Passwortstatus |
| 3 | Letzte Passwortänderung |
| 4 | Minimales Passwortalter |
| 5 | Maximales Passwortalter |
| 6 | Warnzeit vor Passwortablauf |
| 7 | Inaktivitätszeit |
| 8 | Ablaufdatum des Accounts |
| 9 | Reserviert |
---
## 3. Benutzername
Das erste Feld muss zum entsprechenden Benutzerkonto passen.
Beispiel:
```text
max
```
Damit können die Informationen aus `/etc/passwd` und `/etc/shadow` demselben Benutzer zugeordnet werden.
---
## 4. Passwort-Hash / Passwortstatus
Das zweite Feld ist besonders wichtig.
Ein Eintrag könnte beispielsweise folgendermaßen aussehen:
```text
$6$salt$hash
```
Dabei steht `$6$` bei klassischen `crypt`-Passwörtern für **SHA-512**.
Auf modernen Linux-Systemen können auch andere Verfahren eingesetzt werden, beispielsweise **yescrypt**, das häufig an einem Präfix wie `$y$` erkennbar ist.
Das Passwort selbst wird nicht gespeichert. Stattdessen wird ein daraus berechneter Hash gespeichert.
---
## 5. Besondere Werte im Passwortfeld
Das zweite Feld kann auch Werte enthalten, die keinen gültigen Passwort-Hash darstellen.
### Übersicht
| Eintrag | Typische Bedeutung |
|---|---|
| `$6$...` | Passwort-Hash, z. B. SHA-512 |
| `$y$...` | Passwort-Hash, z. B. yescrypt |
| `!$6$...` | Passwort gesperrt, ursprünglicher Hash noch vorhanden |
| `!!` | Kein verwendbares Passwort gesetzt / Passwort-Login gesperrt |
| `*` | Passwort-Authentifizierung nicht möglich |
| leer | Potenziell kein Passwort erforderlich – sicherheitskritisch |
---
# 6. Was bedeutet `!!`?
Beispiel:
```text
max:!!:20680:0:99999:7:::
```
Hier steht im zweiten Feld:
```text
!!
```
`!!` ist **kein gültiger Passwort-Hash**.
Es bedeutet typischerweise:
> Für diesen Benutzer ist kein verwendbares lokales Passwort gesetzt. Eine Authentifizierung über dieses Passwortfeld ist daher nicht möglich.
Das sieht man beispielsweise bei neu angelegten oder bewusst für Passwort-Logins gesperrten Accounts.
Wichtig ist dabei:
**Ein gesperrtes Passwort ist nicht automatisch dasselbe wie ein vollständig gesperrter Benutzeraccount.**
Abhängig von der Systemkonfiguration könnten andere Authentifizierungsverfahren weiterhin funktionieren, beispielsweise:
- SSH Public Keys
- Kerberos
- LDAP / zentrale Authentifizierung
- SSO
- andere PAM-basierte Verfahren
Vereinfacht:
```text
max:!!:20680:0:99999:7:::
    ^^
    │
    └── kein gültiger Passwort-Hash
        → lokale Passwortauthentifizierung nicht möglich
```
---
# 7. Passwortalter und Ablauf
Die restlichen Felder von `/etc/shadow` steuern unter anderem die Gültigkeitsdauer eines Passworts.
Beispiel:
```text
max:$6$...:20680:0:99999:7:::
```
Hier bedeuten die Werte:
```text
20680 : 0 : 99999 : 7
  │      │     │     │
  │      │     │     └─ Warnung vor Ablauf
  │      │     └─ maximales Passwortalter
  │      └─ minimales Passwortalter
  └─ letzte Passwortänderung
```
Die Datumswerte werden grundsätzlich als Anzahl der **Tage seit dem 01.01.1970** angegeben.
---
# 8. Warum gibt es zwei Dateien?
Der Grund für die Trennung ist hauptsächlich die Sicherheit.
`/etc/passwd` muss von vielen Programmen gelesen werden können.
Beispielsweise müssen Programme herausfinden können:
```text
UID 1001 → Benutzer max
```
Daher ist `/etc/passwd` normalerweise für alle Benutzer lesbar.
Passwort-Hashes sollen dagegen geschützt werden.
Deshalb wurden sie in die stärker geschützte Datei `/etc/shadow` ausgelagert.
---
# 9. Zusammenhang von `/etc/passwd` und `/etc/shadow`
Für denselben Benutzer könnten die Einträge beispielsweise so aussehen:
### `/etc/passwd`
```text
max:x:1001:1001:Max Mustermann:/home/max:/bin/bash
```
### `/etc/shadow`
```text
max:!!:20680:0:99999:7:::
```
Beide Einträge gehören über den Benutzernamen `max` zusammen.
Zusammengefasst:
```text
/etc/passwd
     │
     ├── Benutzername
     ├── UID
     ├── GID
     ├── Home-Verzeichnis
     └── Login-Shell
/etc/shadow
     │
     ├── Benutzername
     ├── Passwort-Hash / Passwortstatus
     ├── Passwortalter
     ├── Warnzeit
     └── Account-Ablauf
```
## Merksatz
> **`/etc/passwd` beschreibt den Benutzer, `/etc/shadow` beschreibt vor allem seinen Passwort- und Ablaufstatus.**
###############
Änderungen an Profil-Dateien wie `~/.bashrc` erfordern eine neue Shell-Sitzung oder das explizite Ausführen von `source ~/.bashrc`, damit sie in der aktuellen Sitzung wirksam werden.
+62
View File
@@ -0,0 +1,62 @@
# Lisp
## Variablen
### Globale Variablen
#### defparameter
**`defparameter`**: Definiert eine globale Variable und weist ihr sofort einen Wert zu. Ein erneutes Laden überschreibt den Wert.
```lisp
(defparameter *Variable* Wert)
```
**Beispiel**
```lisp
(defparamter *a* 10)
defparameter *name* "Otto")
(+ *a* *b*)
```
#### defvar
**`defvar`**: Definiert eine globale Variable, setzt den Anfangswert aber nur, wenn sie noch keinen Wert hat. Überschreibt bestehende Werte beim Neuladen *nicht*.
```lisp
(defvar *Variable* Wert )
```
Beispiel
```lisp
(defvar *b* 101)
```
#### setq / setf
**`setq` / `setf`**: Ändert den Wert einer bereits existierenden Variablen oder erzeugt (in manchen Lisp-Dialekten) implizit eine globale Variable, was jedoch unsauber ist. `setf` ist der universelle Zuweisungsoperator.
`setq` - einfache Variablenzuweisung
setf - allgemeine Zuweisung
`setf` kann nicht nur Variablen setzen, sondern praktisch alles, wofür Lisp eine passende **Schreibstelle (place)** kennt:
(setf *mein-wert* 100)
### Lokale Variablen
https://www.heise.de/blog/Lisp-lernen-Teil-1-Primzahlen-berechnen-3077388.html
https://gigamonkeys.com/book/
https://portacle.github.io/#get-mac
https://github.com/rabbibotton/clog
https://docs.google.com/presentation/d/16egmnPGA88RVOl0zhurxw6uLnA86v-lBe_SHZA7CWOg/edit?slide=id.gd400d95397ceaa_18#slide=id.gd400d95397ceaa_18
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+20
View File
@@ -0,0 +1,20 @@
## Mengenoperationen
Hat man zwei oder mehrere Mengen gegeben, so kann man diese mit folgenden Operationen zusammenfassen:
1. Vereinigung: “∪”
2. Schnitt: “∩”
3. Differenz: “∖”
Das kartesische Produkt wird gesondert [hier](https://www.massmatics.de/merkzettel/#!16:Das_kartesische_Produkt_von_Mengen) behandelt. Ebenso das [Komplement einer Menge](https://www.massmatics.de/merkzettel/#!260:Komplement_einer_Menge)
Wie man sich die Mengenoperationen grafisch veranschaulicht wird im Artikel zu den [Venn-Diagrammen](https://www.massmatics.de/merkzettel/#!262:Venn_Diagramme) behandelt.
Zu den vorgestellten Operationen gibt es auch Regeln, wie man mit Klammern und mehreren verschiedenen Verknüpfungen umgeht - [diese findest du hier](https://www.massmatics.de/merkzettel/#!263:Rechenregeln_fuer_Mengen).
## Vereinigung von Mengen
Die Vereinigung von Mengen betrachtet alle Elemente die in der einen oder der anderen Menge enthalten sind.
Sobald ein Element also in einer der beiden Mengen A oder B liegt, ist es automatisch auch in A∪B enthalten.
Als Venn-Diagramm kann man diese Operation so darstellen. Die Vereinigung der beiden Mengen A und B:
<img src="./Grafiken/t_14_0.png" style="zoom:33%;" />
+215
View File
@@ -0,0 +1,215 @@
# Python
# Variablen
### Zahlen
**Variablen** sind Container, die Datenwerte enthalten. Sie werden verwendet, um Informationen innerhalb eines Programms zu speichern, zu bearbeiten und anzuzeigen.
Kurz gesagt ist eine Variable wie eine Speichereinheit, auf die wir zugreifen können, indem wir den Namen der Variable eingeben.
Jede Variable hat einen eindeutigen **Namen** und einen **Wert** , der von unterschiedlichen Typen sein kann. Python kann den Variablentyp automatisch erkennen, wodurch das Programmieren effizienter wird.
Um eine Variable zu initialisieren, verwenden wir das folgende **Format**:
```python
variable_name = value
```
Sehen wir uns die verschiedenen Zahlentypen an:
`int` – eine Ganzzahl, wie etwa `1` oder `-2`.
`float` – reelle Zahl, zum Beispiel `1.32` oder `0.98`.
Zum Beispiel:
Um eine Variable vom Typ `int` mit dem Namen `a` und dem Wert `3` zu initialisieren:
```python
a = 3
```
Um eine Variable vom Typ `float` mit dem Namen `b` und dem Wert `13.2` zu initialisieren:
```python
b = 13.2
```
**Hinweis:** Variablennamen dürfen nicht mit einer Zahl beginnen. Verwende Unterstriche, um Wörter zu trennen (z. B. `player_name`), keine Leerzeichen oder Bindestriche..
## Strings
Ein **Zeichen** ist ein einzelner Buchstabe, eine einzelne Ziffer oder ein einzelnes Symbol (zum Beispiel: 1, 6, %, b, p, ., T usw.). Python hat keinen separaten `char`-Typ: Ein einzelnes Zeichen ist einfach eine Zeichenkette der Länge 1.
Der Typ **str** (Zeichenkette) ist eine Folge aus einem oder mehreren Zeichen.
Um einen Zeichenfolgenwert in einer Variablen zu initialisieren, schließe ihn in einfache oder doppelte Anführungszeichen ein:
```python
s1 = 'This is a string's2 = "This is also a string"
```
Im obigen Beispiel werden zwei Zeichenfolgenvariablen initialisiert, die `s1` und `s2` heißen.
## Boolean
Ein **bool** (Boolean) Typ hat nur 2 mögliche Werte: `True` oder `False`.
Beachten Sie, dass bei diesen Werten die **Groß-/Kleinschreibung beachtet werden muss** (case-sensitive), was bedeutet, dass sie mit einem Großbuchstaben beginnen müssen.
Hier ist ein Beispiel für die Zuweisung eines booleschen Werts zu einer Variable:
```python
variable_true = Truevariable_false = False
```
Oben werden zwei Variablen namens `variable_true` und `variable_false` mit den Werten `True` bzw. `False` initialisiert.
> Booleans sind die Bausteine für das Erstellen von Logik in den Programmen, die wir schreiben. Wir haben ein ganzes Kapitel über Logik und Bedingungen.
## Benennungskonventionen
Namenskonventionen sind eine Reihe von Richtlinien, denen Entwickler folgen, um ihren Code lesbarer und wartbarer zu machen. Verschiedene Programmiersprachen haben oft unterschiedliche Namenskonventionen. In Python werden Variablen in `snake case` geschrieben – Wörter werden durch Unterstriche getrennt.
Beim Schreiben eines Variablennamens sei **beschreibend** und verwende **aussagekräftige** Wörter
### Zum Beispiel 
```python
# Schlechte Namensgebung
isActive = False # nicht im Snake-Case-Format
a = 10
b = "Hello"
x = True
# Gute Namensgebung
age = 10
greeting = "Hello"
is_active = True
```
## Leere Variablen
In Python ist `None` ein spezieller Wert, der „nichts“ oder „kein Wert“ darstellt. Es ist wie eine leere Box – sie existiert, aber in ihr befindet sich nichts. Zum Beispiel:
```python
empty_box = None
```
In einem realen Szenario könntest du `None` verwenden, um anzuzeigen, dass etwas noch nicht initialisiert wurde.
Zum Beispiel:
```python
score = None  # Score wurde noch nicht berechnet
name = None   # Name wurde noch nicht eingegeben 
```
**Hinweis:** `None` ist _nicht_ dasselbe wie `0`, eine leere Zeichenfolge `""` oder `False`. Das sind tatsächliche Werte: null, leerer Text und falsch. `None` bedeutet, dass _überhaupt kein Wert_ vorhanden ist. Das Fehlen eines Werts ist kein Fehler; es bedeutet einfach, dass bisher nichts zugewiesen wurde.
`0` ist ein echter numerischer Wert, zum Beispiel eine Punktzahl von genau null, während `None` bedeutet, dass überhaupt kein Wert vorhanden ist, etwa eine Punktzahl, die noch nicht berechnet wurde. Ein häufiges Missverständnis ist, dass `0` „nichts“ bedeutet, aber in Python steht nur `None` tatsächlich für das Fehlen eines Werts. Ebenso sind `""` (leere Zeichenkette) und `False` weiterhin echte Werte ihrer jeweiligen Typen. Sie sind nicht dasselbe wie `None`.
Die Verwendung von `None` signalisiert, dass die Variable als Platzhalter existiert, aber noch keinen sinnvollen berechneten Wert enthält.
## Arithmetische Operatoren
**Operatoren** werden verwendet, um Operationen mit Werten durchzuführen. 
Zuerst besprechen wir die grundlegendsten **arithmetischen Operatoren**, die dir vielleicht aus dem Mathematikunterricht bekannt sind.
|Operator|Operation|Beispiel|
|---|---|---|
|+|Addition|3 + 2 = 5|
|-|Subtraktion|3 - 2 = 1|
|*|Multiplikation|3 * 2 = 6|
|/|Division|4 / 2 = 2.0|
Sehen wir uns ein Anwendungsbeispiel an.
```python
a = 3
b = 5
c = a + b # c hält 8
```
Wenn ein Ausdruck mehrere Operatoren enthält, folgt Python der in der Mathematik verwendeten Reihenfolge: Multiplikation und Division werden vor Addition und Subtraktion berechnet, und alles innerhalb von Klammern wird zuerst berechnet.
```python
z = 7 + 3 * 2   # z hat den Wert 13, weil 3 * 2 zuerst berechnet wird
z = (7 + 3) * 2 # z hat den Wert 20
```
### Challenge
Schreibe einen Code, der zwei Variablen, `a` und `b`, mit den Werten `5.2` bzw. `2.6` initialisiert.
Initialisiere danach eine weitere Variable `c`, die das Ergebnis von `a / b` enthält.
```python
a = 5.2
b = 2.6
c = a / b
print(f"a = {a}, b = {b}, c = {c}");
```
## Modulo-Operator
Der Modulo-Operator `%` gibt an, was nach der Division einer Zahl durch eine andere übrig bleibt.
```python
result = dividend % divisor
```
- **dividend:** Die zu teilende Zahl.
- **divisor:** Die Zahl, durch die der Dividend geteilt wird.
- **result:** Der Rest der Division.
Zum Beispiel
```python
result = 10 % 3
```
Hier wird 10 durch 3 geteilt. 3 passt dreimal in 10, mit einem Rest von 1. Somit wird `result` 1 sein.
Normalerweise wird Modulo verwendet, um zu prüfen, ob eine Zahl gerade oder ungerade ist:
- Wenn eine Zahl gerade ist, lässt die Division durch 2 einen Rest von 0.
- Wenn eine Zahl ungerade ist, lässt die Division durch 2 einen Rest von 1.
Um dies im Code zu prüfen, verwenden wir den `==` Operator, der prüft, ob zwei Werte zueinander **gleich** sind. Zum Beispiel fragt `result == 0` „ist `result` gleich 0?“
**Sonderfall:** Wenn der Dividend kleiner als der Divisor ist, ist das Ergebnis einfach der Dividend selbst.
Zum Beispiel:
`5 % 8 = 5`
Warum? Da die 8 nicht einmal in die 5 passt, bleibt die gesamte 5 als Rest übrig.
### Challenge
Schreibe einen Code, der drei Variablen, `a`, `b` und `c` mit den Werten `9`, `2` und `11` (beziehungsweise) initialisiert.
Initialisiere danach die folgenden Variablen:
- `d`, die das Ergebnis von `a` Modulo `2` enthalten wird
- `e`, die das Ergebnis von `b` Modulo `3` enthalten wird
- `f`, die das Ergebnis von `c` Modulo `10` enthalten wird
Sieh dir das Ergebnis an und beobachte, wie sich unterschiedliche Dividenden und Divisoren auf das Ergebnis auswirken.
```python
a = 9
b = 2
c = 11
d = a % 2
e = b % 3
f = c % 10
# Ändern Sie die folgende Zeile nicht
print(f"a = {a}")
print(f"b = {b}")
print(f"c = {c}")
print(f"d = {d}")
print(f"e = {e}")
print(f"f = {f}")
```
+21
View File
@@ -0,0 +1,21 @@
```racket
#lang racket
; https://dev.to/goober99/learn-racket-by-example-gui-programming-3epm
(require racket/gui/base)
; 1. Hauptfenster (Frame) erstellen
(define frame (new frame% [label "Hallo Racket"]
[width 300]
[height 200]))
; 2. Einen Button zum Fenster hinzufügen
(define btn (new button% [parent frame]
[label "Klick mich"]
[callback (lambda (b e)
(printf "Button wurde geklickt!\n"))]))
; 3. Fenster sichtbar machen
(send frame show #t)
```
+211
View File
@@ -0,0 +1,211 @@
# Regular Expressions Cheat Sheet
A regular expression specifies a set of strings that matches it. This cheat sheet is based off Python 3's Regular Expressions (http://docs.python.org/3/library/re.html) but is designed for searches within Sublime Text.
https://gist.github.com/IsaacCisneros/d7f3cf4bf6c0573d0570
https://ahkde.github.io/docs/v1/misc/RegEx-QuickRef.htm
https://serverdiscounter.com/blog/2026-01-26-regex-grundlagen
## Special Characters
| | | |
| :------: | :------------------------------------------------------------------------------ | :------------------------------------------------------------------------ |
| `\` | Escapet Sonderzeichen oder kennzeichnet eine spezielle Sequenz | |
| `.` | Entspricht einem beliebigen einzelnen Zeichen mit Ausnahme eines Zeilenumbruchs | |
| `^` | Matches the start of the string. | |
| `$` | Matches the end of the string​ | |
| `*` | Greedily matches 0 or more repetitions of the preceding RE. | |
| `*?` | Matches 0 or more repetitions of the preceding RE. | |
| `+` | Greedily matches 1 or more repetitions of the preceding RE. | |
| `+?` | Matches 1 or more repetitions of the preceding RE. | |
| `?` | Greedily matches 0 or 1 repetitions of the preceding RE. | |
| `??` | Matches 0 or 1 repetitions of the preceding RE. | |
| `A\|B` | Matches A, if A is unmatched then matches B, where A and B are arbitrary REs. | |
| `{m}` | Matches exactly m many repetitions of the previous RE. | |
| `{m,n}` | Greedily matches from m many to n many repetitions of the previous RE. | |
| `{m,n}?` | Matches m many to n many repetitions of the previous RE. | |
| `[...]` | Indicates a set of characters to match. | |
| | `[amk]` | Matches 'a', 'm', or 'k'. |
| | `[a-z]` | Matches 'a' through 'z'. |
| | `[a-f0-7]` | Matches 'a' through 'f' or '0' through '7'. |
| | `[a\-z]` | Matches 'a', '-', or 'z'. |
| | `[a-]` | Matches 'a' or '-'. |
| | `[-a]` | Matches 'a' or '-'. |
| | `[(+*)]` | Matches '(', '+', '*', or ')'. `[]` matches special characters literally. |
​
[\w] Matches the character class for '\w'. See character classes.
[^5] Matches anything other than '5'. '^' forms the complementary set only as the first character in a set.
[]()] Matches ']', '(', and ')'. ']' is taken literally only as the first character in a set.
[()\]] Matches ']', '(', and ')'.
(...) Matches the RE inside the parenthesis and assigns a new group.
(?P<name>...) The RE matched is accessible by the group indicated by name.
(?...) Extension notation which changes a RE's behavior. These do not assign a new group.
(?aiLmsux) Sets the corresponding flag to each letter. Does not work within Sublime Text.
(?:...) A non-capturing version of parenthesis. The matched substring cannot be retrieved later.
(?P=name) Matches the substring matched by the group named name.
(?#...) A comment, the contents are ignored.
(?=...) Lookahead assertion, the preceding RE only matches if this matches.
(?!...) Negative lookahead assestion, the preceding RE only matches if this doesn't match.
(?<=...) Positive lookbehind assertion, the following RE will only match if preceeded with this fixed length RE.
(?<!...) Negative lookbehind assertion, the following RE will only match if not preceeded with this fixed length RE.
(?(id)true|false) If group id exists then uses the true RE, else use the false RE.
> Character classes
> \1 Matches the contents of the group labelled by the same number. Acceptable numbers are 1-99.
> \A Matches at the start of the current string.
> \b Matches the empty string at the beginning or end of a word. \b matches the boundary between \w and \W.
> \B Matches the empty string not at the beginning or end of a word.
> \d Matches any Unicode decimal digit, including 0-9.
> \D Matches any Unicode non-decimal digit.
> \s Matches any Unicode whitespace character, including ' ', \t, \n, \r, \f and \v.
> \S Matches any Unicode non-whitespace character.
> \w Matches any Unicode word character, including a-z, A-Z, and 0-9.
> \W Matches any Unicode non-word character.
> \Z Matches at the end of the string.
\a Matches the ASCII Bell ().
\f Matches the ASCII Formfeed ( ).
\n Matches the ASCII Linefeed.
\r Matches the ASCII Carriage Return (
).
\t Matches the ASCII Horizontal Tab.
\v Matches the ASCII Vertical Tab ( ).
#########################
### Regular Expression Cheat Sheet with Examples
Regular Expressions (regex) are patterns used to match strings in text. Below is a cheat sheet with common regex patterns and examples.
---
### **1. Anchors**
| Pattern | Description | Example | Matches |
| ------- | ------------------- | -------- | -------------- |
| `^` | Start of the string | `^Hello` | `Hello world!` |
| `$` | End of the string | `world$` | `Hello world!` |
---
### **2. Quantifiers**
| Pattern | Description | Example | Matches |
| ------- | ------------------------------- | --------- | ------------------------ |
| `*` | 0 or more | `a*` | `aaa`, `b` |
| `+` | 1 or more | `a+` | `aaa`, but not `b` |
| `?` | 0 or 1 | `colou?r` | `color`, `colour` |
| `{n}` | Exactly `n` occurrences | `a{3}` | `aaa`, but not `aa` |
| `{n,}` | At least `n` occurrences | `a{2,}` | `aa`, `aaa` |
| `{n,m}` | Between `n` and `m` occurrences | `a{2,3}` | `aa`, `aaa`, but not `a` |
---
### **3. Character Classes**
| Pattern | Description | Example | Matches |
| ------- | ---------------------------------------- | ------- | --------------- |
| `.` | Any character except newline | `a.b` | `acb`, `a9b` |
| `\d` | Any digit (0-9) | `\d+` | `123`, `9` |
| `\D` | Any non-digit | `\D+` | `abc`, `@#` |
| `\w` | Any word character (alphanumeric or `_`) | `\w+` | `hello_123` |
| `\W` | Any non-word character | `\W+` | `@!`, ` #` |
| `\s` | Any whitespace | `\s+` | ` `, `\t`, `\n` |
| `\S` | Any non-whitespace | `\S+` | `abc`, `123` |
---
### **4. Logical OR and Grouping**
| Pattern | Description | Example | Matches |
| ------- | ----------- | ----------------------- | ------- |
| `a | b` | Match either `a` or `b` | `cat |
| `(ab | cd)` | Grouping | `(ab |
---
### **5. Escape Characters**
| Pattern | Description | Example | Matches |
| ------- | ----------- | --------- | ------- |
| `\.` | Literal dot | `a\.b` | `a.b` |
| `\[` | Literal `[` | `\[abc\]` | `[abc]` |
---
### **6. Ranges**
| Pattern | Description | Example | Matches |
| -------------- | --------------------------- | -------- | ------------ |
| `[a-z]` | Lowercase letters | `[a-z]+` | `abc`, `xyz` |
| `[A-Z]` | Uppercase letters | `[A-Z]+` | `ABC`, `XYZ` |
| `[0-9]` | Digits | `[0-9]+` | `123`, `456` |
| `[a-zA-Z0-9_]` | Alphanumeric and underscore | `\w+` | `hello123_` |
---
### **7. Special Sequences**
| Pattern | Description | Example | Matches |
| ---------- | ------------------- | ------------- | ----------------- |
| `(?=...)` | Positive lookahead | `foo(?=bar)` | `foo` in `foobar` |
| `(?!...)` | Negative lookahead | `foo(?!bar)` | `foo` in `foobaz` |
| `(?<=...)` | Positive lookbehind | `(?<=foo)bar` | `bar` in `foobar` |
| `(?<!...)` | Negative lookbehind | `(?<!foo)bar` | `bar` in `bazbar` |
---
### **8. Common Patterns**
| Use Case | Regex | Example |
| ----------------------- | ------------------------------------------------ | --------------------- |
| Match email | `[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}` | `user@example.com` |
| Match URL | `https?://[^\s]+` | `https://example.com` |
| Match phone number | `\d{3}-\d{3}-\d{4}` | `123-456-7890` |
| Match date (YYYY-MM-DD) | `\d{4}-\d{2}-\d{2}` | `2024-12-13` |
---
### **9. Flags**
| Flag | Description | Example |
| ---- | ---------------- | ------------------------------ |
| `i` | Case-insensitive | `/hello/i` matches `Hello` |
| `g` | Global match | `/hello/g` matches all `hello` |
| `m` | Multiline | `/^hello/m` matches per line |
---
### **10. Examples in Code**
#### Python Example:
```python
import re
# Match an email
pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
email = "contact@example.com"
print(re.match(pattern, email)) # Output: <re.Match object>
```
#### JavaScript Example:
```javascript
// Match a URL
let pattern = /https?:\/\/[^\s]+/g;
let text = "Visit https://example.com for more info.";
console.log(text.match(pattern)); // Output: [ 'https://example.com' ]
```
[regular-expressions-v2.pdf](regular-expressions-v2.pdf)
[regular-expressions-cheat-sheet-v1.pdf](regular-expressions-cheat-sheet-v1.pdf)
[regex-cheatsheet.pdf](regex-cheatsheet.pdf)
+464
View File
@@ -0,0 +1,464 @@
# Rust
Rust ist eine moderne Systemprogrammiersprache, die mit Fokus auf Performance, Speichersicherheit und Nebenläufigkeit entwickelt wurde. Sie ermöglicht es Entwicklern, zuverlässige und effiziente Software zu erstellen, von Betriebssystemen bis hin zu Webanwendungen.
## Hello World!
Das „Hello World!“ ist ein einfaches Programm, das Hello World! auf dem Bildschirm ausgibt.
In Rust verwenden wir das Makro `println!()`, um eine Ausgabe auf der Konsole auszugeben. Beachte, dass `println!` mit `ln` endet: einem Kleinbuchstaben l (wie in „line“), nicht mit einem Großbuchstaben I. Der auszugebende Text wird innerhalb doppelter Anführungszeichen platziert und in Klammern eingeschlossen.
Sehen wir uns das „Hello World!“-Programm in Rust an:
```rust
fn main() {
println!(„Hello World!“);
}
```
## Kommentare
**Comments** sind Notizen, die man in den Code schreibt. Der compiler ignoriert sie vollständig – sie existieren nur, um Menschen beim Verständnis des Codes zu helfen.
Um einen einzeiligen Kommentar zu schreiben, verwendet man `//`. Alles nach `//` bis zum Ende der Zeile wird ignoriert:
```rust
// Das ist ein Kommentarprintln!("Hello, world!");
```
Ein Kommentar kann auch am Ende einer Zeile nach dem Code geschrieben werden:
```rust
println!("Hello, world!"); // Dies gibt Hello, world! aus!
```
Für Kommentare, die sich über mehrere Zeilen erstrecken, verwendet man `/*`, um zu beginnen, und `*/`, um zu enden:
```rust
/* Dies ist ein mehrzeiliger Kommentar.   Der Compiler ignoriert ihn vollständig. */println!("Welcome!");
```
Kommentare können eine Codezeile auch vorübergehend **deaktivieren**, ohne sie zu löschen:
```rust
// println!("This line will NOT run");println!("This line will run");
```
**Hinweis:** Jeder mehrzeilige Kommentar, der mit `/*` beginnt, muss mit `*/` geschlossen werden, andernfalls behandelt der Compiler alles danach als Kommentar.
Grundlegende Programmstruktur
In Rust beginnt jedes ausführbare Programm mit der Funktion `main`. Diese Funktion ist der Einstiegspunkt des Programms und dort beginnt die Ausführung.
Die `function` `main` wird mit dem Schlüsselwort `fn`definiert, gefolgt von `main` und einem Klammerpaar `()`. Der auszuführende Code wird innerhalb geschweifter Klammern `{}` platziert.
Hier ist eine einfache Aufschlüsselung eines grundlegenden Rust-Programms:
```rust
fn main() { // Hauptfunktion    
println!("Hello, Coddy!"); // Ausgabeanweisung}
}
```
Wichtiger Hinweis: In Rust muss jede Anweisung mit einem Semikolon (`;`) enden. Das Semikolon ist obligatorisch und teilt Rust mit, dass du das Ende einer Anweisung erreicht hast.
Wenn du vergisst, ein Semikolon hinzuzufügen, führt dies zu einem Kompilierungsfehler. Beachte jedoch, dass Codeblöcke, die in geschweiften Klammern {} eingeschlossen sind (wie Funktionsdeklarationen), keine Semikolons benötigen.
## Grundlegende Programmstruktur
In Rust beginnt jedes ausführbare Programm mit der Funktion `main`. Diese Funktion ist der Einstiegspunkt des Programms und dort beginnt die Ausführung.
Die `function` `main` wird mit dem Schlüsselwort `fn`definiert, gefolgt von `main` und einem Klammerpaar `()`. Der auszuführende Code wird innerhalb geschweifter Klammern `{}` platziert.
Hier ist eine einfache Aufschlüsselung eines grundlegenden Rust-Programms:
```rust
fn main() { // Hauptfunktion    
println!("Hello, Coddy!"); // Ausgabeanweisung
}
```
Wichtiger Hinweis: In Rust muss jede Anweisung mit einem Semikolon (`;`) enden. Das Semikolon ist obligatorisch und teilt Rust mit, dass du das Ende einer Anweisung erreicht hast.
Wenn du vergisst, ein Semikolon hinzuzufügen, führt dies zu einem Kompilierungsfehler. Beachte jedoch, dass Codeblöcke, die in geschweiften Klammern `{}` eingeschlossen sind (wie Funktionsdeklarationen), keine Semikolons benötigen.
## Zahlen
**Variablen** sind Container, die Datenwerte enthalten. Sie werden verwendet, um Informationen innerhalb eines Programms zu speichern, zu manipulieren und anzuzeigen.
Kurz gesagt ist eine Variable wie eine Speichereinheit, auf die wir zugreifen können, indem wir den Namen der Variable eingeben. 
Jede Variable hat einen eindeutigen **Namen** und einen **Wert**, der von unterschiedlichem Typ sein kann. Rust verfügt über verschiedene integrierte Datentypen, die den Typ des Wertes definieren, den eine Variable enthalten kann.
Um eine Variable zu initialisieren, verwenden wir das folgende **Format**:
```rust
let variable_name: variable_type = value;
```
In Rust werden Zahlen normalerweise mit zwei Hauptdatentypen dargestellt: `i32` und `f64`.
`i32` wird verwendet, um ganze Zahlen ohne Dezimalpunkt zu speichern. Zum Beispiel:
```rust
let age: i32 = 30;
let temperature: i32 = -5;
let count: i32 = 100;
```
`f64` wird verwendet, um Zahlen mit einem Dezimalpunkt zu speichern. Zum Beispiel:
```rust
let price: f64 = 99.99;
let pi: f64 = 3.14159;
let fraction: f64 = 0.5;
```
Beim Deklarieren von Variablen in Rust müssen Sie den Typ der Variable nach dem Variablennamen angeben, gefolgt von einem Doppelpunkt. Dies wird als **Typdeklaration** bezeichnet. Sobald eine Variable mit einem bestimmten Typ deklariert wurde, kann sie nur Werte dieses Typs enthalten.
### Challenge
Schreiben Sie ein Rust-Programm, das die folgenden Variablen deklariert und initialisiert:
- Deklarieren Sie eine `i32`-Variable namens `quantity`und initialisieren Sie diese mit dem Wert `5`.
- Deklarieren Sie eine `f64`-Variable namens `item_price`und initialisieren Sie diese mit dem Wert `24.99`.
Nachdem Sie diese Variablen deklariert und initialisiert haben, verwenden Sie `println!()`, um die Werte der Variablen im folgenden Format auf der Konsole auszugeben:
```rust
Quantity: [value of quantity]
Price: [value of item_price]
```
#### Lösung:
```rust
fn main() {
// Variablen hier deklarieren und initialisieren
let quantity: i32 = 5;
let item_price: f64 = 24.99;
println!("Quantity: {}", quantity);
println!("Price: {}", item_price);
}
```
## Char
Ein **char** ist ein einzelnes Zeichen (Zum Beispiel: `1, 6, %, b, p, ., T`, etc.)
Der **char**-Typ ist ein spezieller Typ, der aus einem einzelnen Zeichen besteht.
Um einen char-Wert in einer Variablen zu initialisieren, schließen Sie ihn in **einfache Anführungszeichen** ein:
```rust
let c1: char = 'h';
```
Im obigen Beispiel wird eine char-Variable namens `c1`initialisiert.
## String
Ein **char** ist ein einzelnes Zeichen (Zum Beispiel: 1, 6, %, b, p, ., T, etc.)
Der Typ **String** ist ein spezieller Typ, der aus mehreren **char**s besteht.
Um einen String-Wert in einer Variablen zu initialisieren, schließen Sie ihn in **doppelte Anführungszeichen** ein:
```rust
let s1 = "This is a string";
```
Im obigen Beispiel wird eine String-Variable namens `s1` initialisiert.
Anders als bei Zahlen müssen wir bei der Arbeit mit Strings vorsichtiger mit Typen sein.
Wenn Sie explizit einen String-Typ deklarieren möchten, müssen Sie die Zeichenfolge wie folgt konvertieren:
```rust
let s1: String = "This is a string".to_string();
```
######################################################
<mark style="background:#ff4d4f">Rust unterscheidet zwischen String-Literalen und dem Typ String, was eine explizite Konvertierung erfordert.</mark> noch beschreiben
String-Literal --> normaler String a = "hhhh"
######################################################
### Challenge
Speichere den String `I am learning to code with Coddy!` in einer Variable namens `coddy` unter Verwendung eines String-Literals (mit doppelten Anführungszeichen)..
> Stelle sicher, dass du den **exakten** String-Wert mit korrekter Groß- und Kleinschreibung speicherst.
```rust
fn main() {
let coddy = "I am learning to code with Coddy!".to_string();
println!("coddy = \"{}\"", coddy);
}
```
## Boolean
Ein **boolescher** Typ hat nur 2 mögliche Werte: `true` oder `false`.
Um einer Variablen einen booleschen Wert zuzuweisen, verwenden Sie das Schlüsselwort `let` gefolgt vom Variablennamen:
```rust
let variable_true: bool = true;
let variable_false: bool = false;
```
Im obigen Beispiel werden zwei boolesche Variablen namens `variable_true` und `variable_false` jeweils mit den Werten `true` und `false` initialisiert.
> Booleans sind die Bausteine für die Erstellung von Logik in den Programmen, die wir schreiben. Wir haben ein ganzes Kapitel über Logik und Bedingungen.
## Veränderbare Variablen
In Rust sind Variablen standardmäßig unveränderlich. Das bedeutet, dass man einen Wert, sobald er einer Variablen zugewiesen wurde, nicht mehr ändern kann. Man kann eine Variable jedoch veränderlich machen, indem man bei der Deklaration der Variablen das Schlüsselwort `mut` verwendet.
Zum Beispiel:
```rust
let x = 5; // x ist unveränderlich
let mut y = 10; // y ist veränderlich
```
In diesem Beispiel ist `x` unveränderlich, sodass Sie seinen Wert nach der Initialisierung nicht mehr ändern können. Andererseits ist `y` veränderlich, sodass Sie seinen Wert später im Code ändern können.
```rust
y = 20; // Dies ist erlaubt, da y veränderbar ist
x = 15; // Dies wird einen Fehler verursachen, da 
```
### Challenge
Deklariere eine veränderbare Variable namens `add` und weise ihr den Wert 13 zu.
Ändere den Wert von 13 auf 16.
### Lösung
```rust
#[allow(unused_assignments)]
fn main() {
// Variable add initialisieren
let mut add = 13;
// Wert von 13 auf 16 ändern
add = 16;
println!("add = {}", add);
}
```
## Typdeklaration
Sobald eine Variable mit einem bestimmten Typ deklariert wurde, kann sie nur Werte dieses Typs enthalten. Beispielsweise kann eine `i32`-Variable nur Ganzzahlwerte enthalten, und eine `String`-Variable kann nur Text enthalten.
Zum Beispiel:
```rust
let mut age: i32 = 25;  // Kann nur ganze Zahlen speichern
let mut name: &str = "Alice";  // Kann nur Text speichern
```
Diese würden Fehler verursachen:
```rust
age = "Bob";  // Fehler: Text kann nicht in eine i32-Variable geschrieben werden
name = 30;  // Fehler: Eine Zahl kann nicht in eine String-Variable geschrieben werden
```
Diese sind gültig:
```rust
age = 26;  // OK: Zuweisen einer neuen Ganzzahl
name = "Jane";  // OK: Zuweisen einer neuen Textzeichenkette
```
### Challenge
Deklariere die folgenden Variablen mit ihren entsprechenden Typen und Werten:
- Eine `i32`-Variable namens `count` mit dem Wert `10`.
- Eine `f64`-Variable namens `total` mit dem Wert `150.75`.
- Eine `char`-Variable namens `grade` mit dem Wert `'A'`.
- Eine `bool`-Variable namens `is_active` mit dem Wert `false`.
- Eine `String`-Variable namens `user_name` mit dem Wert `"Bob123"`.
Verwende nach der Deklaration dieser Variablen `println!()`, um die Werte der Variablen im folgenden Format auf der Konsole auszugeben:
```rust
Count: [value of count]
Total: [value of total]
Grade: [value of grade]
Active: [value of is_active]
User Name: [value of user_name]
```
### Lösung
```rust
fn main() {
// Variablen hier deklarieren
let count: i32 = 10;
let total: f64 = 150.75;
let grade: char = 'A';
let is_active: bool = false;
let user_name: String = "Bob123".to_string();
println!("Count: {}", count);
println!("Total: {}", total);
println!("Grade: {}", grade);
println!("Active: {}", is_active);
println!("User Name: {}", user_name);
}
```
## Namenskonventionen
In Rust gibt es mehrere Benennungskonventionen, die Sie befolgen sollten, um Ihren Code lesbarer und wartbarer zu machen. Sie sind in der Rust-Community weitgehend akzeptiert.
Hier sind einige gängige Namenskonventionen:
- Variablen sollten mit `snake_case` benannt werden, was bedeutet, dass alle Buchstaben kleingeschrieben und Wörter durch Unterstriche getrennt werden. Zum Beispiel: `my_variable`, `calculate_total`.
- Vermeiden Sie zu kurze oder kryptische Namen. Wählen Sie aussagekräftige Namen, die den Zweck der Variable klar angeben.
- Namen können Buchstaben, Ziffern und Unterstriche enthalten.
- Namen müssen mit einem Buchstaben oder einem Unterstrich `_` beginnen.
- Einfache Zähler verwenden normalerweise einzelne Buchstaben wie `i`, `j`, obwohl es erwähnenswert ist, dass aussagekräftigere Namen besser sein könnten, wenn der Kontext komplexer ist.
## Typinferenz
In Rust ermöglicht die Typinferenz dem Compiler, den Typ einer Variablen basierend auf ihrem Wert und ihrer Verwendung automatisch abzuleiten. Das bedeutet, dass Sie den Typ beim Deklarieren einer Variablen oft nicht explizit angeben müssen, was Ihren Code prägnanter und leichter lesbar macht.
Zum Beispiel:
```rust
let x = 5;// Rust leitet ab, dass x ein i32 ist
let y = 3.14;// Rust leitet ab, dass y ein f64 ist
let message = "Hello, world!";// Rust leitet ab, dass message ein &str (String) ist
let is_true = true;// Rust leitet ab, dass is_true ein bool ist
```
In diesen Beispielen haben wir die Typen von `x`, `y`, `message` und `is_true` nicht angegeben. Der Rust-Compiler hat ihre Typen automatisch basierend auf den ihnen zugewiesenen Werten abgeleitet.
Typinferenz ist nicht nur praktisch, sondern hilft auch dabei, Fehler zu vermeiden. Der Compiler prüft, wie die Variablen verwendet werden, und stellt sicher, dass die abgeleiteten Typen im gesamten Code konsistent sind. Wenn ein Konflikt auftritt, erzeugt der Compiler eine Fehlermeldung.
### Challenge
Schreibe ein Rust-Programm, das Typinferenz demonstriert. Deklariere und initialisiere die folgenden Variablen ohne explizite Typanmerkungen:
- Eine Variable namens `quantity` mit dem Wert `10`.
- Eine Variable namens `price` mit dem Wert `99.99`.
- Eine Variable namens `message` mit dem Wert `"Coddy is awesome!"`.
- Eine Variable namens `is_available` mit dem Wert `true`.
Verwende nach der Deklaration dieser Variablen `println!()`, um ihre Werte auf der Konsole auszugeben. Beobachte, wie Rust die Typen dieser Variablen basierend auf ihren Werten ableitet.
### Lösung
```rust
fn main() {
// Variablen hier deklarieren
let quantity = 10;
let price = 99.99;
let message = "Coddy is awesome!";
let is_available = true;
// Die Werte ausgeben
println!("Quantity: {}", quantity);
println!("Price: {}", price);
println!("Message: {}", message);
println!("Is available: {}", is_available);
}
```
## Typumwandlung
Typumwandlung bezeichnet den Vorgang, einen Wert von einem Datentyp in einen anderen umzuwandeln. In Rust verwenden wir das Schlüsselwort <mark style="background:#40a9ff">`as`</mark> für eine explizite Typumwandlung (auch als Typkonvertierung bezeichnet). 
Die häufigsten Typumwandlungen finden zwischen numerischen Typen statt:
```rust
// Umwandlung von Integer zu Float
let number: i32 = 5;
let decimal: f64 = number as f64;// wird zu 5.0
```
```rust
// Umwandlung von Gleitkommazahl in Ganzzahl
let decimal: f64 = 9.7;
let number: i32 = decimal as i32;// wird zu 9 (Dezimalteil wird abgeschnitten)
```
### Challenge
Schreiben Sie ein Rust-Programm, das Typumwandlung demonstriert. Führen Sie die folgenden Operationen aus:
1. Deklarieren Sie eine `f64`-Variable namens `price` und initialisieren Sie diese mit dem Wert `99.99`.
2. Wandeln Sie die Variable `price` in einen `i32` um und speichern Sie das Ergebnis in einer neuen Variable namens `int_price`.
3. Geben Sie die Werte von `price` und `int_price` auf der Konsole aus.
```rust
fn main() {
// Variablen deklarieren und initialisieren
let price: f64 = 99.99;
let int_price: i32 = price as i32;
// Die Werte ausgeben
println!("Price: {}", price);
println!("Int Price: {}", int_price);
}
```
## Arithmetische Operatoren
**Operatoren** werden verwendet, um Operationen auf Werten auszuführen.
Zuerst werden wir die grundlegendsten **arithmetischen Operatoren** besprechen; sie sind Ihnen vielleicht aus dem Mathematikunterricht bekannt.
| Operator | Operation | Beispiel |
| -------- | -------------- | --------- |
| + | Addition | 3 + 2 = 5 |
| - | Subtraktion | 3 - 2 = 1 |
| * | Multiplikation | 3 * 2 = 6 |
| / | Division | 4 / 2 = 2 |
Sehen wir uns ein Verwendungsbeispiel an,
```rust
let a: i32 = 3;
let b: i32 = 5;
let c: i32 = a + b// c enthält 8
```
Beim Arbeiten mit Dezimalzahlen in Rust verwenden wir den Datentyp f64, der Zahlen mit Nachkommastellen speichern kann. Die gleichen arithmetischen Operatoren (+, -, *, /) funktionieren mit f64 genauso wie mit Ganzzahlen:
```rust
let x: f64 = 3.3;
let y: f64 = 4.1;
let z: f64 = x + y;// z enthält 7.4
```
### Challenge
Schreibe einen Code, der zwei Variablen, `a` und `b`, mit den Werten `5.2` und `2.6` (in dieser Reihenfolge) initialisiert.
Initialisiere danach eine weitere Variable `c`, die das Ergebnis von `a / b` enthalten wird.
```rust
fn main() {
// Schreibe deinen Code unten
let a: f64 = 5.2;
let b: f64 = 2.6;
let c: f64 = a / b;
// Ändere die folgende Zeile nicht
println!("a = {}, b = {}, c = {}", a, b, c);
}
```
https://rust-lernen.de/blog/zeichenketten.html
https://www.reddit.com/r/rust/comments/13wzjoq/media_difference_between_string_str_and_string/?tl=de#lightbox
https://cheats.rs/#pointer-meta
https://rust-lang-de.github.io/rustbook-de/title-page.html
+1020 -223
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
# Scheme
## Definition von Variablen
### Globale Variablen
```scheme
(define variablenname wert)
```
Beispiel:
```scheme
(define a 10)
(define name "Otto")
```
+194
View File
@@ -0,0 +1,194 @@
## Die Vokale
Obwohl es weniger Vokale als Konsonanten im schwedischen Alphabet gibt, sind es die Vokale, die dir die meisten Schwierigkeiten bereiten werden. Zunächst wird jeder Vokal entweder weich oder hart ausgesprochen, was die Aussprache des davor stehenden Konsonanten beeinflusst. Obwohl uns durchaus auffällt, ob ein Vokal weich oder hart ist, wird der Unterschied erst richtig klar, wenn wir uns die Konsonanten ansehen.
Außerdem kann jeder Vokal auf mindestens zwei verschiedene Arten ausgesprochen werden. Steht der Vokal vor zwei Konsonanten, vor einem M oder N am Ende eines Wortes oder befindet sich in der letzten, unbetonten Silbe eines Wortes, so ist der Vokal kurz. Steht der Vokal vor einem Konsonanten oder in einem einsilbigen Wort, das auf einen Vokal endet, ist der Vokal lang. Das hört sich erst einmal verwirrend an, aber hör dir hier die Beispiele an und du wirst den Dreh bestimmt herausbekommen.
### **A**
Der Buchstabe A ist ein harter Vokal. Meistens klingt er wie das „a” in „Vater“.
- Kurz ausgesprochen: _t**a**ck_ („danke”)
- Lang ausgesprochen: _br**a**_ (“good”)
### **E**
Der Buchstabe E ist ein weicher Vokal. Ein kurzes E klingt wie das „e“ in „Bett“, wohingegen das lange E wie das „e“ in „Beet“ klingt.
- Kurz ausgesprochen: _m**e**llan_ („zwischen”)
- Lang ausgesprochen: _r**e**sa_ („Reise”)
### **I**
Der Buchstabe I ist ein weicher Vokal. Das I klingt immer wie in „Liebe“.
- Kurz ausgesprochen: _t**i**ll_ („bis”)
- Lang ausgesprochen: _b**i**l_ („Auto”)
### **O**
Der Buchstabe O ist ein harter Vokal. Das kurze O klingt wie das „o“ in „Stopp“, wohingegen das lange O wie das „u“ in „Mut“ klingt.
- Kurz ausgesprochen: _k**o**mma_ („kommen“)
- Lang ausgesprochen: _**o**säker_ („unsicher”)
### **U**
Der Buchstabe U ist ein harter Vokal. Das schwedische U wird ähnlich wie das U im Deutschen ausgesprochen.
- Kurz ausgesprochen: _buss_ („Bus”)
- Lang ausgesprochen: _du_ („du“)
### **Y**
Der Buchstabe Y ist ein weicher Vokal. Er klingt ähnlich wie das deutsche „i“, mit einem leichten Einschlag von „ü“.
- Kurz ausgesprochen: _fl**y**tta_ („bewegen”)
- Lang ausgesprochen:  _s**y**_ („nähen”)
### **Å**
Der Buchstabe Å ist ein harter Vokal. Obwohl er wie das deutsche „A“ aussieht, wird er eher wie das „o“ wie in „oder“ ausgesprochen.
- Kurz ausgesprochen:  _G**å**rdsby_ (ein Ort in Schweden)
- Lang ausgesprochen: _hej d**å**_ („tschüss”)
### **Ä**
Der Buchstabe Ä ist ein weicher Vokal und wird wie das deutsche „ä“ in „ähnlich“ ausgesprochen.
- Kurz ausgesprochen: _G**ä**llivare_ (ein Ort in Schweden)
- Lang ausgesprochen: _**ä**ta_ („essen”)
### **Ö**
Der Buchstabe Ö ist ein weicher Vokal und wird wie das deutsche „ö“ in „gewöhnlich“ ausgesprochen.
- Kurz ausgesprochen: _k**ö**ttbullar_ („Fleischbällchen bzw. Fleischbrötchen”)
- Lang ausgesprochen: _**ö**l_ („Bier”)
> 💡 [In 10 Schritten schwedisch werden: So geht’s!](https://de.babbel.com/de/magazine/schwedisch-werden)
## Schwedisches Alphabet: die Konsonanten
Die schwedischen Konsonanten sind wirklich unkompliziert. Viele Buchstaben werden ähnlich wie im Deutschen ausgesprochen. Es gibt jedoch auch einige Ausnahmen. Also, sehen wir uns die häufigsten Buchstaben und Buchstabenkombinationen an, über die man beim Lernen der Sprache stolpert.
### **G, GN und NG**
Das G wird hauptsächlich auf zwei verschiedene Arten ausgesprochen. Im ersten Fall klingt es wie der Buchstabe „g“ in „gehen“ und wird vor den harten Vokalen (A, O, U und Å) auf diese Weise ausgesprochen.
- _**g**ata_ — Straße
- _**G**otland_ — eine schwedische Insel
Steht das G vor einem weichen Vokal (E, I, Y, Ä oder Ö), klingt es wie das „j“ in „jeder“.
- _**g**ärna_ — gern
- _**g**ift_ — verheiratet
Der Buchstabe G wird ebenfalls weich ausgesprochen, wenn er nach einem R oder einem L steht.
- _äl**g**_ — Elch
- _Ber**g**a_ — ein Ort in Schweden
Die Buchstabenkombination NG wird genauso wie im Deutschen ausgesprochen, wie das „ng“ in „jung“.
- _u**ng**_ — jung
- _si**ng**el_ — Single
Komplizierter wird es beim GN, das wie das „ng“ in „jung“ mit einem noch schnell angehängten „n“ klingt.
- _re**gn**_ — Regen
- _si**gn**al_ — Signal
### **J**
Der Buchstabe J ist einer der schwierigsten des schwedischen Alphabets. Wie er ausgesprochen wird hängt nämlich davon ab, auf welchen Buchstaben er folgt. Steht er am Anfang eines Wortes oder nach einem Vokal, klingt er wie ein „j“.
- _he**j** då_ — tschüss
- _**j**äst_ — Hefe
Die Buchstabenkombination SJ gibt es nur im Schwedischen. Um sie auszusprechen nimmst du das „h“ wie in „Hut“, schiebst es jedoch in deinem Mund weiter nach hinten und machst einen runden Mund. Dieselbe Aussprache wird für den ersten Laut der Wortendungen _-tion_ und _-sion_ genutzt.
- _**sj**ö_ — See
- _**sj**ukhus_ — Krankenhaus
- _sta**tion**_ — Bahnhof
- _diskus**sion**_ — Diskussion
Die Kombination TJ wird ähnlich dem „sch“ in „Schiff“ ausgesprochen.
- _**tj**ugo_ — zwanzig
- _**tj**ena_ — Hey
Bei den Buchstabenkombinationen LJ, DJ, GJ und HJ wird jeweils der erste Buchstabe ignoriert und dann das „j“ wie in „jetzt“ ausgesprochen.
- _**gj**orde_ — gemacht
- _**Lj**usdal_ — ein Ort in Schweden
- _**Dj**urmo_ — ein Ort in Schweden
- _**Hj**o_ — ein Ort in Schweden
### **K und SK**
Genau wie im Falle des G wird das K im Schwedischen auf zwei verschiedene Arten ausgesprochen, abhängig von dem auf es folgenden Vokal. Vor harten Vokalen (A, O, U und Å) sowie am Ende eines Wortes wird es wie das „k“ in „Kuss“ ausgesprochen.
- _**k**ul_ — lustig
- _**k**ål_ — Kohl
Vor weichen Vokalen (E, I, Y, Ä oder Ö) und dem Buchstaben J wird es wie das „sch“ in „Schiff“ ausgesprochen (genau wie das TJ, siehe oben).
- _**K**ina_ — China
- _**k**öra_ — fahren
- _**kj**ol_ — Rock
Die Buchstabenkombination SK hat ebenso zwei Varianten: Vor harten Vokalen klingt es wie das „sk“ in „Skateboard“.
- _**Sk**ara_ — ein Ort in Schweden
- _**sk**o_ — Schuh
Vor weichen Vokalen oder einem J klingt es wie der oben besprochene SJ-Laut.
- _**sk**ön_ — schön
- _**sk**iva_ — Scheibe
### **RS**
Die Buchstabenkombination RS wird wie das „sch“ in „Schuh“ ausgesprochen.
- _ko**rs**ning_ — Kreuzung
- _va**rs**ågod_ — bitte sehr, gern geschehen
### **Q, W und Z**
Obwohl die Buchstaben Q, W und Z im schwedischen Alphabet vorkommen, sind sie dennoch relativ selten. Normalerweise kommen sie nur in alten Ausdrücken und Lehnwörtern vor. Das W wurde bis vor kurzem als identisch mit dem V angesehen, das Q wurde in den meisten Fällen durch das K und das Z meistens durch das S ersetzt.
### **Verschluckte Buchstaben**
Das Letzte, was wir dir noch über das schwedische Alphabet mitgeben möchten, ist, dass die Buchstaben häufig „verschluckt“ werden. Das macht das Schwedischlernen natürlich umso verwirrender. Es gibt einige Regeln, die du lernen kannst – das „k“ in der Buchstabenkombination „skr“ ist oft stumm, das R hört man kaum, wenn es vor dem D, L, T oder N steht – doch es gibt vieles, das du einfach lernen musst, indem du Menschen mit Schwedisch als Erstsprache zuhörst.
#######################
Schwedische Vokale haben unterschiedliche Laute:
- **A:** wie das lange „a“ in „raten“ oder das kurze „a“ in „Mann“
- **E:** ähnlich dem langen „e“ in „See“ oder dem kurzen „e“ in „Bett“
- **I:** wie das lange „i“ in „Igel“ oder das kurze „i“ in „mit“
- **O:** kann wie das „u“ in „gut“ oder das „o“ in „Post“ klingen
- **U:** ein Laut zwischen „i“ und „ü“, der im Deutschen keine direkte Entsprechung hat
- **Y:** wie das deutsche „ü“ in „Tür“
- **Å:** ähnlich dem langen „o“ in „Boot“
- **Ä:** wie das deutsche „ä“ in „spät“
- **Ö:** ähnlich dem deutschen „ö“ in „schön“
### Häufige Verwechslungen
- **Å und Ä verwechseln:** Das sind keine Varianten von A. Å klingt wie ein langes, offenes „o“, während Ä wie das deutsche „ä“ klingt.
- **Ö falsch aussprechen:** Deutsche Muttersprachige haben hier einen Vorteil, da der Laut dem deutschen „ö“ entspricht. Achte darauf, ihn nicht wie ein kurzes „o“ auszusprechen.
- **Den Unterschied zwischen W und V ignorieren:** Obwohl sie für viele Menschen aus Schweden ähnlich klingen, ist die Unterscheidung für die Rechtschreibung wichtig. W kommt hauptsächlich in Lehnwörtern und Namen vor, während V im Alltag viel häufiger ist.
- **Y- und J-Laute verwechseln:** Das schwedische J klingt wie das deutsche J (wie in „ja“), während Y wie das deutsche „ü“ ausgesprochen wird. Diese Vertauschung kann am Anfang zu lustigen Missverständnissen führen.
- **Vergessen, dass C seine Aussprache ändert:** C klingt wie „s“ vor e, i, y, ä und ö, aber wie „k“ vor a, o, u und å.
### Hilfreiche Erinnerungen
Für Å, Ä und Ö kannst du dir Eselsbrücken bauen: Der Kreis über dem Å sieht aus wie ein kleiner See, passend zum tiefen „o“-Laut. Die zwei Punkte auf dem Ä erinnern an weit geöffnete Augen, was zu seinem offeneren Klang passt.
Der knifflige sj-Laut (/ɧ/) in Wörtern wie _sjö_ (See) – stell dir vor, du zischst leise, während du den hinteren Teil deines Rachens leicht verengst. Es braucht zwar Übung, macht aber schnell Spaß.
+51
View File
@@ -183,3 +183,54 @@ a ist nur Beispiel
### Mehrfaches Ausführen ### Mehrfaches Ausführen
100@a 100@a
# Aus alter Datei
## Bestimmte Phrasen in Kleinbuchstaben umwandeln
```
:%s/\(Zum Beispiel[^.!?]*[.!?]\)/\L\1/g
```
**Erläuterung:**
- `:%s/…/…/g` – Sucht und ersetzt global in der ganzen Datei.
- `\(…\)` – Gruppiert den Treffer, um ihn als `\1` später referenzieren zu können.
- `Zum Beispiel` – Die Zielphrase am Satzanfang.
- `[^.!?]*` – Beliebig viele Zeichen, bis zu einem Satzendezeichen.
- `[.!?]` – Der Satz endet mit Punkt, Ausrufezeichen oder Fragezeichen.
- `\L\1` – Wandelt den Inhalt von `\1` (dem gefundenen Satzteil) in Kleinbuchstaben um
## Jede leere Zeile löschen
```
:g/^$/d
```
- `:g` – Wendet den Befehl auf alle Zeilen an, die einem Muster entsprechen.
- `^$` – Das Muster für eine leere Zeile: Zeilenanfang (^) gefolgt von Zeilenende ($), also nichts dazwischen.
- `d` – Löscht die jeweilige Zeile.
oder aber **alternativ**:
- mit `v` —> nicht passende Zeilen behalten, so also `:v/\S/d`
- `\S` bedeutet nicht-Leerzeichen
oder
- mit `:g/^\s*$/d`
- `:g` → global: wende auf alle Zeilen an, die passen
- `^\s*$` → Zeilen, die nur aus Leerzeichen/Tabs (oder gar nichts) bestehen
- `d` → lösche diese Zeilen
## Zeile in ein Register kopieren
- `”ayy`
## Zeile aus einem Register einfügen
- `<ESC>”ap`
+667
View File
@@ -0,0 +1,667 @@
# Ansible Ad-hoc -- Kurzreferenz
Diese Kurzreferenz fasst die besprochenen Ansible-Ad-hoc-Befehle
zusammen: mehrere Rechner direkt ansprechen, speziellen SSH-User
verwenden, Dateien sichern und kopieren, Rechte setzen, Benutzer mit
Home-Verzeichnis anlegen und per `su` statt `sudo` zu `root` wechseln.
## Rechner direkt ansprechen
Ohne Inventory-Datei können Hosts direkt mit `-i` angegeben werden.
Wichtig ist das abschließende Komma.
```bash
ansible all \
-i "server01,server02,server03," \
-m ping
```
Alternativ mit IP-Adressen:
```bash
ansible all \
-i "10.10.1.20,10.10.1.21,10.10.1.22," \
-m ping
```
## Speziellen SSH-User verwenden
Mit `-u` bzw. `--user` wird festgelegt, mit welchem Benutzer Ansible die
SSH-Verbindung aufbaut.
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-m ping
```
Wenn die SSH-Anmeldung ein Passwort benötigt, zusätzlich `-k` verwenden:
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-k \
-m ping
```
`-k` fragt das SSH-Passwort des Login-Users ab.
## Datei kopieren, Rechte setzen und Backup erstellen
Das `copy`-Modul kann die Datei verteilen, Owner/Gruppe/Rechte setzen
und gleichzeitig die vorhandene Zieldatei sichern.
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-m copy \
-a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes"
```
Falls für den Zielpfad erhöhte Rechte benötigt werden, muss zusätzlich
Become verwendet werden.
### Mit sudo
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-b \
-m copy \
-a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes"
```
Falls `sudo` ein Passwort benötigt:
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-b -K \
-m copy \
-a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes"
```
## Vorher prüfen mit `--check`
Viele Änderungen können zunächst im Check-Modus getestet werden:
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-b \
-m copy \
-a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes" \
--check
```
## Neuen User inklusive Home-Verzeichnis anlegen
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-b \
-m user \
-a "name=newuser state=present create_home=yes shell=/bin/bash"
```
Dabei wird `newuser` angelegt und normalerweise `/home/newuser`
erstellt.
Zum vorherigen Test:
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-b \
-m user \
-a "name=newuser state=present create_home=yes shell=/bin/bash" \
--check
```
## `su` statt `sudo` verwenden
Wenn auf den Zielsystemen nicht `sudo`, sondern `su` für den Wechsel zu
`root` verwendet werden muss:
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-b \
--become-method=su \
--become-user=root \
-K \
-m user \
-a "name=newuser state=present create_home=yes shell=/bin/bash"
```
Bedeutung:
- `-u deployuser` -- SSH-Login als `deployuser`
- `-b` -- Become/Privilege Escalation aktivieren
- `--become-method=su` -- `su` statt `sudo` verwenden
- `--become-user=root` -- zu `root` wechseln
- `-K` -- Become-/`su`-Passwort interaktiv abfragen
## `su` zunächst testen
Bevor Änderungen durchgeführt werden, kann geprüft werden, ob der
Wechsel zu `root` funktioniert:
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-b \
--become-method=su \
--become-user=root \
-K \
-m command \
-a "whoami"
```
Bei erfolgreichem Wechsel sollte jeder Host `root` zurückgeben.
## SSH-Passwort und `su`-Passwort
Wenn sowohl die SSH-Anmeldung als auch `su` ein Passwort benötigen,
müssen `-k` und `-K` verwendet werden:
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-k \
-b \
--become-method=su \
--become-user=root \
-K \
-m command \
-a "whoami"
```
Dabei gilt:
Option Bedeutung
---------------------- ---------------------------------------
`-u deployuser` SSH-Login-User
`-k` SSH-Passwort des Login-Users abfragen
`-b` Become aktivieren
`--become-method=su` `su` als Become-Methode
`--become-user=root` Zielbenutzer für Become
`-K` Become-/`su`-Passwort abfragen
Bei Verwendung von `-k` und `-K` fragt Ansible typischerweise nach:
```text
SSH password:
BECOME password:
```
Ohne `-k` kann Ansible beispielsweise einen vorhandenen SSH-Key oder
SSH-Agent verwenden und fragt deshalb nicht nach dem SSH-Passwort.
## Komplettbeispiel: Datei mit `su` verteilen
SSH-Anmeldung als `deployuser` per Passwort, anschließend `su` zu
`root`, vorhandene Datei sichern und neue Datei mit korrekten Rechten
verteilen:
```bash
ansible all \
-i "server01,server02,server03," \
-u deployuser \
-k \
-b \
--become-method=su \
--become-user=root \
-K \
-m copy \
-a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes"
```
######################################################################
# Ansible Ad-hoc -- Kurzreferenz
Diese Kurzreferenz fasst die besprochenen Ansible-Ad-hoc-Befehle
zusammen: mehrere Rechner direkt ansprechen, speziellen SSH-User
verwenden, Dateien sichern und kopieren, Rechte setzen, Benutzer mit
Home-Verzeichnis anlegen und per `su` statt `sudo` zu `root` wechseln.
## Rechner direkt ansprechen
Ohne Inventory-Datei können Hosts direkt mit `-i` angegeben werden.
Wichtig ist das abschließende Komma.
```bash
ansible all \
  -i "server01,server02,server03," \
  -m ping
```
Alternativ mit IP-Adressen:
```bash
ansible all \
  -i "10.10.1.20,10.10.1.21,10.10.1.22," \
  -m ping
```
## Speziellen SSH-User verwenden
Mit `-u` bzw. `--user` wird festgelegt, mit welchem Benutzer Ansible die
SSH-Verbindung aufbaut.
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -m ping
```
Wenn die SSH-Anmeldung ein Passwort benötigt, zusätzlich `-k` verwenden:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -k \
  -m ping
```
`-k` fragt das SSH-Passwort des Login-Users ab.
## Datei kopieren, Rechte setzen und Backup erstellen
Das `copy`-Modul kann die Datei verteilen, Owner/Gruppe/Rechte setzen
und gleichzeitig die vorhandene Zieldatei sichern.
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -m copy \
  -a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes"
```
Falls für den Zielpfad erhöhte Rechte benötigt werden, muss zusätzlich
Become verwendet werden.
### Mit sudo
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -b \
  -m copy \
  -a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes"
```
Falls `sudo` ein Passwort benötigt:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -b -K \
  -m copy \
  -a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes"
```
## Vorher prüfen mit `--check`
Viele Änderungen können zunächst im Check-Modus getestet werden:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -b \
  -m copy \
  -a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes" \
  --check
```
## Neuen User inklusive Home-Verzeichnis anlegen
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -b \
  -m user \
  -a "name=newuser state=present create_home=yes shell=/bin/bash"
```
Dabei wird `newuser` angelegt und normalerweise `/home/newuser`
erstellt.
Zum vorherigen Test:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -b \
  -m user \
  -a "name=newuser state=present create_home=yes shell=/bin/bash" \
  --check
```
## `su` statt `sudo` verwenden
Wenn auf den Zielsystemen nicht `sudo`, sondern `su` für den Wechsel zu
`root` verwendet werden muss:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -b \
  --become-method=su \
  --become-user=root \
  -K \
  -m user \
  -a "name=newuser state=present create_home=yes shell=/bin/bash"
```
Bedeutung:
-   `-u deployuser` -- SSH-Login als `deployuser`
-   `-b` -- Become/Privilege Escalation aktivieren
-   `--become-method=su` -- `su` statt `sudo` verwenden
-   `--become-user=root` -- zu `root` wechseln
-   `-K` -- Become-/`su`-Passwort interaktiv abfragen
## `su` zunächst testen
Bevor Änderungen durchgeführt werden, kann geprüft werden, ob der
Wechsel zu `root` funktioniert:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -b \
  --become-method=su \
  --become-user=root \
  -K \
  -m command \
  -a "whoami"
```
Bei erfolgreichem Wechsel sollte jeder Host `root` zurückgeben.
## SSH-Passwort und `su`-Passwort
Wenn sowohl die SSH-Anmeldung als auch `su` ein Passwort benötigen,
müssen `-k` und `-K` verwendet werden:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -k \
  -b \
  --become-method=su \
  --become-user=root \
  -K \
  -m command \
  -a "whoami"
```
Dabei gilt:
  Option                 Bedeutung
  ---------------------- ---------------------------------------
  `-u deployuser`        SSH-Login-User
  `-k`                   SSH-Passwort des Login-Users abfragen
  `-b`                   Become aktivieren
  `--become-method=su`   `su` als Become-Methode
  `--become-user=root`   Zielbenutzer für Become
  `-K`                   Become-/`su`-Passwort abfragen
Bei Verwendung von `-k` und `-K` fragt Ansible typischerweise nach:
```text
SSH password:
BECOME password:
```
Ohne `-k` kann Ansible beispielsweise einen vorhandenen SSH-Key oder
SSH-Agent verwenden und fragt deshalb nicht nach dem SSH-Passwort.
## Komplettbeispiel: Datei mit `su` verteilen
SSH-Anmeldung als `deployuser` per Passwort, anschließend `su` zu
`root`, vorhandene Datei sichern und neue Datei mit korrekten Rechten
verteilen:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -k \
  -b \
  --become-method=su \
  --become-user=root \
  -K \
  -m copy \
  -a "src=./config.conf dest=/etc/myapp/config.conf owner=root group=root mode=0644 backup=yes"
```
## Benutzer ohne nutzbares Passwort (`!!` in `/etc/shadow`)
Mit dem Ansible-`user`-Modul kann das Passwort eines Accounts mit `password_lock=yes` gesperrt werden:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -k \
  -b \
  --become-method=su \
  --become-user=root \
  -K \
  -m user \
  -a "name=newuser state=present create_home=yes shell=/bin/bash password_lock=yes"
```
Auf üblichen Linux-Systemen ist das Passwortfeld damit gesperrt. Bei einem neu angelegten Benutzer kann `/etc/shadow` beispielsweise `newuser:!!:...` enthalten. Das genaue Sperrkennzeichen kann je nach Distribution und Ausgangszustand variieren.
### Bedeutung von `-m user` und `name=newuser`
| Ausdruck | Bedeutung |
|---|---|
| `-m user` | Ansible-Modul `user` verwenden |
| `name=newuser` | Benutzer `newuser` verwalten bzw. anlegen |
| `state=present` | Sicherstellen, dass der Benutzer existiert |
| `create_home=yes` | Home-Verzeichnis anlegen |
| `shell=/bin/bash` | Bash als Login-Shell setzen |
| `password_lock=yes` | Passwort des Accounts sperren |
Wichtig: `-m` bezeichnet bei Ansible das **Modul**. Der Name des neuen Benutzers steht hinter `name=`.
Beispiel für `appuser`:
```bash
ansible all \
  -i "server01,server02,server03," \
  -u deployuser \
  -k \
  -b \
  --become-method=su \
  --become-user=root \
  -K \
  -m user \
  -a "name=appuser state=present create_home=yes shell=/bin/bash password_lock=yes"
```
Nicht mit `useradd` verwechseln: Bei `useradd -m appuser` bedeutet `-m`, dass das Home-Verzeichnis erstellt wird. Bei `ansible ... -m user` wählt `-m` dagegen das Ansible-Modul aus.
## Benutzer ohne Ansible anlegen
Direkt auf Linux:
```bash
useradd -m -s /bin/bash newuser
```
Passwortstatus bzw. Shadow-Eintrag prüfen:
```bash
passwd -S newuser
grep '^newuser:' /etc/shadow
```
Passwort explizit sperren:
```bash
passwd -l newuser
```
`passwd -l` sperrt einen vorhandenen Passwort-Hash durch ein vorangestelltes `!`. Der exakte Inhalt in `/etc/shadow` muss daher nicht zwingend exakt `!!` sein.
+285
View File
@@ -0,0 +1,285 @@
# Docker & Docker Compose – Befehls‑Referenz
Eine praktische Übersicht der wichtigsten Befehle für den Alltag – von Container‑Verwaltung über Docker Compose bis zur Netzwerk‑Untersuchung.
> Hinweis: Je nach Installation heißt der Compose‑Befehl `docker compose` (Plugin, neu) oder `docker-compose` (Standalone, alt). Beide Varianten sind unten aufgeführt, wo es relevant ist.
---
## 1. Container – Grundlagen
| Zweck | Befehl |
|-------|--------|
| Laufende Container anzeigen | `docker ps` |
| Alle Container (auch gestoppte) | `docker ps -a` |
| Container starten | `docker start <name\|id>` |
| Container stoppen | `docker stop <name\|id>` |
| Container neu starten | `docker restart <name\|id>` |
| Container pausieren / fortsetzen | `docker pause <name>` / `docker unpause <name>` |
| Container löschen | `docker rm <name\|id>` |
| Laufenden Container zwangsweise löschen | `docker rm -f <name\|id>` |
| Alle gestoppten Container aufräumen | `docker container prune` |
### In einen Container hineingehen
```bash
# Interaktive Shell öffnen (bash oder sh, je nach Image)
docker exec -it <name> bash
docker exec -it <name> sh
# Einzelnen Befehl im Container ausführen
docker exec <name> ls -la /data
# Als bestimmter User (z. B. root)
docker exec -it -u root <name> sh
```
---
## 2. Logs & Diagnose
```bash
# Logs anzeigen
docker logs <name>
# Logs live mitverfolgen (folgen)
docker logs -f <name>
# Nur die letzten 100 Zeilen, mit Zeitstempel
docker logs --tail 100 -t <name>
# Logs seit einem Zeitpunkt
docker logs --since 10m <name>
# Ressourcen-Verbrauch live (CPU, RAM, Netzwerk, I/O)
docker stats
# Prozesse innerhalb eines Containers
docker top <name>
# Vollständige Metadaten (JSON): Mounts, Netzwerk, Env, ...
docker inspect <name>
# Gezielt einen Wert herausfiltern (z. B. IP-Adresse)
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <name>
# Geänderte Dateien im Container-Dateisystem
docker diff <name>
```
---
## 3. Images
| Zweck | Befehl |
|-------|--------|
| Lokale Images anzeigen | `docker images` |
| Image herunterladen | `docker pull <image>:<tag>` |
| Image löschen | `docker rmi <image>` |
| Ungenutzte Images aufräumen | `docker image prune` |
| Image aus Dockerfile bauen | `docker build -t <name>:<tag> .` |
| Image-Historie / Layer ansehen | `docker history <image>` |
---
## 4. Volumes & Daten
```bash
# Volumes auflisten
docker volume ls
# Volume-Details (z. B. Mountpoint auf dem Host)
docker volume inspect <volume>
# Ungenutzte Volumes aufräumen (VORSICHT: Daten weg!)
docker volume prune
# Datei vom Host in den Container kopieren
docker cp ./datei.txt <name>:/pfad/im/container/
# Datei aus dem Container auf den Host holen
docker cp <name>:/pfad/im/container/datei.txt ./
```
---
## 5. Aufräumen (Speicher freigeben)
```bash
# Alles Ungenutzte entfernen (gestoppte Container, dangling Images, Netzwerke)
docker system prune
# Zusätzlich ungenutzte Images UND Volumes (aggressiv!)
docker system prune -a --volumes
# Speicherverbrauch von Docker anzeigen
docker system df
```
---
## 6. Docker Compose – Grundlagen
Alle Befehle im Verzeichnis mit der `docker-compose.yml` ausführen.
| Zweck | Befehl |
|-------|--------|
| Stack starten (im Hintergrund) | `docker compose up -d` |
| Stack starten + Images neu bauen | `docker compose up -d --build` |
| Stack stoppen & Container entfernen | `docker compose down` |
| Stack stoppen (Container bleiben) | `docker compose stop` |
| Gestoppten Stack wieder starten | `docker compose start` |
| Einen einzelnen Dienst neu starten | `docker compose restart <service>` |
| Status aller Dienste | `docker compose ps` |
| Logs aller Dienste (live) | `docker compose logs -f` |
| Logs eines Dienstes | `docker compose logs -f <service>` |
| In einen Dienst hineingehen | `docker compose exec <service> sh` |
| Images der Dienste aktualisieren | `docker compose pull` |
| Config einlesen & validieren | `docker compose config` |
### Down mit Aufräumen
```bash
# Stack runterfahren UND die zugehörigen Volumes löschen (VORSICHT!)
docker compose down -v
# Zusätzlich auch die gebauten/verwendeten Images entfernen
docker compose down --rmi all
```
### Update-Workflow (typisch)
```bash
docker compose pull # neue Images holen
docker compose up -d # Container mit neuen Images neu erstellen
docker image prune -f # alte, ungenutzte Images aufräumen
```
---
## 7. Netzwerk – Untersuchung & Verwaltung
Der zentrale Teil, wenn Container sich nicht erreichen oder Ports nicht durchkommen.
### 7.1 Netzwerke auflisten & inspizieren
```bash
# Alle Docker-Netzwerke anzeigen
docker network ls
# Details eines Netzwerks: welche Container hängen dran, Subnetz, Gateway
docker network inspect <netzwerk>
# Kompakt: nur die Container-Namen + IPs eines Netzwerks
docker network inspect <netzwerk> \
-f '{{range .Containers}}{{.Name}} → {{.IPv4Address}}{{println}}{{end}}'
```
Die Standard-Netzwerktypen:
- **bridge** – Standard für einzelne Container auf einem Host.
- **host** – Container teilt sich den Netzwerk-Stack des Hosts (kein Port-Mapping nötig).
- **none** – kein Netzwerk.
- **benutzerdefinierte bridge** – von Compose automatisch pro Projekt angelegt; hier funktioniert DNS-Auflösung über Service-Namen.
### 7.2 Netzwerke anlegen / verbinden
```bash
# Netzwerk erstellen
docker network create <netzwerk>
# Container mit einem Netzwerk verbinden
docker network connect <netzwerk> <container>
# Container von einem Netzwerk trennen
docker network disconnect <netzwerk> <container>
# Ungenutzte Netzwerke aufräumen
docker network prune
```
### 7.3 Ports & Erreichbarkeit prüfen
```bash
# Welche Ports mappt ein Container?
docker port <name>
# Port-Mappings in der Übersicht (Spalte PORTS)
docker ps
# Auf dem Host: lauscht der Port wirklich?
ss -tulpn | grep <port> # modern
netstat -tulpn | grep <port> # klassisch
```
### 7.4 Verbindung zwischen Containern testen
Wichtig: In einem benutzerdefinierten Compose-Netzwerk erreichen sich Container über ihren **Service-Namen** als Hostname (z. B. `db`, `gitea`, `redis`).
```bash
# DNS-Auflösung + Erreichbarkeit vom Container A zum Service "db"
docker compose exec app ping -c 3 db
# Falls ping fehlt: mit wget/curl gegen den Ziel-Port testen
docker compose exec app wget -qO- http://db:5432 || echo "nicht erreichbar"
docker compose exec app curl -v http://gitea:3000
# DNS-Auflösung explizit prüfen (nslookup / getent)
docker compose exec app nslookup db
docker compose exec app getent hosts db
```
Wenn Diagnose-Tools im Container fehlen, hilft ein Wegwerf-Container im selben Netzwerk:
```bash
docker run --rm -it --network <netzwerk> nicolaka/netshoot
# darin dann: ping, curl, dig, nslookup, traceroute, tcpdump, nmap ...
```
`nicolaka/netshoot` ist das Standard-Toolbox-Image für Container-Netzwerk-Debugging.
### 7.5 Häufige Netzwerk-Probleme
| Symptom | Prüfen |
|---------|--------|
| Container erreicht anderen nicht über Namen | Hängen beide im **selben** Netzwerk? → `docker network inspect` |
| Port von außen nicht erreichbar | Port-Mapping gesetzt (`-p host:container` / `ports:` in Compose)? Firewall? |
| „Connection refused" | Dienst lauscht evtl. nur auf `127.0.0.1` statt `0.0.0.0` im Container |
| DNS-Name wird nicht aufgelöst | Standard-`bridge` hat kein DNS – benutzerdefiniertes Netzwerk / Compose nutzen |
| Zwei Stacks sollen sich sehen | Gemeinsames externes Netzwerk anlegen und beiden zuweisen |
---
## 8. Nützliche Kombi-Befehle
```bash
# Alle laufenden Container stoppen
docker stop $(docker ps -q)
# Alle Container löschen (gestoppt)
docker rm $(docker ps -aq)
# In den zuletzt gestarteten Container springen
docker exec -it $(docker ps -q -n 1) sh
# Nur Namen + Status + Ports, sauber formatiert
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
# Live-Logs eines Compose-Dienstes ab jetzt (ohne Historie)
docker compose logs -f --tail 0 <service>
```
---
## 9. Schnelle Fehlersuche – Reihenfolge
1. **Läuft der Container überhaupt?** → `docker ps -a` (Status `Exited` / `Restarting`?)
2. **Warum crasht er?** → `docker logs --tail 100 <name>`
3. **Stimmen Mounts / Env / Netzwerk?** → `docker inspect <name>`
4. **Hängt er am Netzwerk?** → `docker network inspect <netzwerk>` + Ping-Test (Abschnitt 7.4)
5. **Ist der Port offen?** → `docker port <name>` + `ss -tulpn` auf dem Host
6. **Platz voll?** → `docker system df` → ggf. `docker system prune`
---
*Erstellt als schnelle Referenz – bei Docker Compose v1 überall `docker compose` durch `docker-compose` ersetzen.*
+85
View File
@@ -0,0 +1,85 @@
Klar — hier ist der Inhalt als Markdown zum Kopieren:
```markdown
# Erklärung der PHP-Zeile
```php
$page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
```
Die Zeile liest den URL-Parameter **`page`** aus und stellt sicher, dass die Seitennummer mindestens **1** ist.
## 1. Prüfen, ob `page` vorhanden ist
```php
isset($_GET['page'])
```
Prüft, ob in der URL ein Parameter `page` vorhanden ist.
Zum Beispiel:
```text
http://localhost/pfdb/?page=3
```
Dann enthält:
```php
$_GET['page'] // "3"
```
## 2. Umwandlung in eine Ganzzahl
```php
(int) $_GET['page']
```
wandelt den Wert in eine Ganzzahl (`int`) um.
## 3. Mindestwert 1
```php
max(1, (int) $_GET['page'])
```
stellt sicher, dass das Ergebnis **nicht kleiner als 1** wird.
## 4. Ternärer Operator
Der gesamte Ausdruck verwendet den sogenannten **ternären Operator**:
```php
Bedingung ? Wert_wenn_wahr : Wert_wenn_falsch
```
Ausgeschrieben entspricht die ursprüngliche Zeile ungefähr:
```php
if (isset($_GET['page'])) {
$page = max(1, (int) $_GET['page']);
} else {
$page = 1;
}
```
## Beispiele
| URL-Parameter | `$page` |
| ------------- | -------:|
| keiner | `1` |
| `?page=1` | `1` |
| `?page=5` | `5` |
| `?page=0` | `1` |
| `?page=-4` | `1` |
| `?page=abc` | `1` |
## Zweck
Das ist typisch für eine **Pagination/Seitennavigation**.
`$page` gibt also sehr wahrscheinlich an, welche Seite einer Ergebnisliste angezeigt werden soll.
```
```
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+740
View File
@@ -0,0 +1,740 @@
# Xdebug – Installation, Konfiguration, Nutzung
Stand: Xdebug 3.x (Modus-Konfiguration ab Xdebug 3, Port **9003**)
---
## Die wichtigste Antwort vorweg
**Nein – man trägt nichts in die einzelnen PHP-Dateien ein.**
Xdebug wird **einmal** in der `php.ini` konfiguriert. Danach ist es für *jedes* PHP-Skript
aktiv, das über diesen Webserver bzw. diese CLI läuft. Kein `require`, kein `include`,
keine Zeile im Quellcode.
```
php.ini ändern → Apache neu starten → gilt ab sofort überall
```
Das `ini_set(...)` aus dem Gesprächsverlauf war ausdrücklich der **Notfallweg** für
Systeme, auf denen man keine INI-Datei anfassen darf. Wer Zugriff auf die `php.ini` hat,
braucht es nicht.
Im Code gibt es nur zwei *optionale* Dinge, die man punktuell einsetzen kann:
```php
xdebug_break(); // setzt einen Breakpoint ohne IDE-Klick
xdebug_start_trace('/tmp/xy'); // startet ein Aufrufprotokoll ab hier
```
Beides ist Zusatzkomfort, keine Voraussetzung.
---
## 0. Versionsmatrix
| PHP | Xdebug | Konfigurationsstil |
|---|---|---|
| 7.0 – 7.1 | 2.9.x | `xdebug.remote_*`, Port 9000 |
| 7.2 – 7.4 | 3.1.x | `xdebug.mode`, Port 9003 |
| 8.0 – 8.2 | 3.2.x | `xdebug.mode`, Port 9003 |
| 8.3+ | 3.3+ / 3.5+ | `xdebug.mode`, Port 9003 |
> Xdebug 3.5 setzt mindestens PHP 8.3 voraus. Bei älterem PHP die Version explizit pinnen:
> `pecl install xdebug-3.2.2`
Verzeichnisnamen wie `no-debug-non-zts-20220829` kodieren die PHP-API-Version:
`20220829` = PHP 8.2 · `20230831` = PHP 8.3 · `20240924` = PHP 8.4
---
## 1. Installation unter XAMPP (macOS)
Xdebug wird für macOS **nicht** vorkompiliert ausgeliefert – es muss gebaut werden.
### 1.1 Vorbereitung
```bash
xcode-select --install # Compiler / Command Line Tools
brew install autoconf # phpize benötigt autoconf
```
Auf Apple Silicon zusätzlich:
```bash
softwareupdate --install-rosetta --agree-to-license
```
### 1.2 Architektur-Falle (Apple Silicon)
XAMPP für macOS ist **x86_64** und läuft unter Rosetta 2. Ein nativer Build auf einem
M-Mac erzeugt eine arm64-`.so`, die PHP nicht laden kann:
```
dlopen(...) (mach-o file, but is an incompatible architecture
(have 'arm64', need 'x86_64'))
```
`arch -x86_64` **vor** `pecl` reicht nicht – `pecl` ist ein PHP-Skript, dessen
Kindprozesse (`phpize`, `configure`, `clang`) die Rosetta-Umgebung nicht zuverlässig
erben. Deshalb eine komplette x86_64-Shell öffnen:
```bash
arch -x86_64 /bin/zsh
arch # muss "i386" ausgeben
```
### 1.3 Build via pecl
```bash
# Alte Reste entfernen, sonst wird der falsche Build wiederverwendet
sudo rm -f /Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-*/xdebug.so
rm -rf /tmp/pear
# PEAR-Registry abmelden (sonst: "already installed ... install failed")
sudo /Applications/XAMPP/xamppfiles/bin/pecl uninstall xdebug
# Build (in der Rosetta-Shell!)
sudo CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64" CXXFLAGS="-arch x86_64" \
/Applications/XAMPP/xamppfiles/bin/pecl install xdebug-3.2.2
```
`pecl` gibt am Ende die Zeile `Installing '/Applications/XAMPP/.../xdebug.so'` aus –
**das** ist der Pfad für die `php.ini`.
### 1.4 Ergebnis prüfen
```bash
file /Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20220829/xdebug.so
# muss "x86_64" enthalten
```
### 1.5 Manueller Build (falls pecl scheitert)
Gibt mehr Kontrolle, weil jeder Schritt einzeln sichtbar ist:
```bash
cd /tmp && curl -O https://xdebug.org/files/xdebug-3.2.2.tgz
tar -xzf xdebug-3.2.2.tgz && cd xdebug-3.2.2
/Applications/XAMPP/xamppfiles/bin/phpize
./configure --with-php-config=/Applications/XAMPP/xamppfiles/bin/php-config \
CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64"
make
file modules/xdebug.so # VOR dem Kopieren prüfen
sudo cp modules/xdebug.so \
/Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20220829/
```
### 1.6 Alternative ohne Compile-Schmerz
Wer nicht an XAMPP gebunden ist:
```bash
brew install php # natives arm64-PHP
pecl install xdebug # läuft ohne Rosetta durch
php -S localhost:8000 # eingebauter Server statt Apache
```
---
## 2. Installation unter XAMPP (Windows)
Deutlich einfacher – es gibt fertige DLLs.
### 2.1 Passende DLL ermitteln
XAMPP kompiliert PHP als **Thread Safe** (Apache mit mod_php), also wird eine TS-DLL
benötigt. Statt zu raten, den Xdebug-Wizard nutzen:
**https://xdebug.org/wizard**
1. `phpinfo()`-Ausgabe erzeugen – im Browser (`http://localhost/info.php`) oder per
`C:\xampp\php\php.exe -i > info.txt`
2. **Kompletten** Output kopieren (Strg+A / Strg+C), nicht nur die sichtbare Tabelle
3. Ins Textfeld einfügen → *Analyse my phpinfo() output*
4. Der Wizard nennt exakt die passende Datei, z. B.
`php_xdebug-3.4.x-8.2-vs16-x86_64.dll`
> Alternativ manuell unter https://xdebug.org/download – dann Thread Safety und
> VS/VC-Compilerversion selbst aus `phpinfo()` ablesen.
Nach dem Test: **`info.php` wieder löschen.**
### 2.2 Installieren
DLL kopieren nach `C:\xampp\php\ext\php_xdebug.dll`, dann in `C:\xampp\php\php.ini`
(ganz unten steht bereits ein auskommentierter `[XDebug]`-Block):
```ini
[XDebug]
zend_extension = xdebug
xdebug.mode = develop,debug
xdebug.start_with_request = trigger
xdebug.client_port = 9003
xdebug.client_host = 127.0.0.1
```
### 2.3 Prüfen
Apache über das Control Panel **Stop/Start** (nicht nur „Config"), dann:
```
C:\xampp\php\php.exe -v
```
Die Ausgabe muss `with Xdebug v3.x.x` enthalten.
---
## 3. Installation unter Debian
Der bequemste Fall – Paketverwaltung erledigt alles.
### 3.1 Über apt
```bash
sudo apt install php-xdebug
# oder versionsspezifisch, z. B. bei Sury-Repository:
sudo apt install php8.4-xdebug
```
### 3.2 Über pecl (wenn kein Paket verfügbar)
```bash
sudo apt install php-pear php-dev autoconf
sudo pecl install xdebug
```
### 3.3 Konfiguration – hier gilt `conf.d`
Debian nutzt ein Scan-Verzeichnis. **Nicht** die zentrale `php.ini` anfassen, sondern
eine eigene Datei anlegen:
```
/etc/php/8.4/apache2/conf.d/99-xdebug-local.ini
```
```ini
xdebug.mode = develop,debug
xdebug.start_with_request = trigger
xdebug.client_port = 9003
xdebug.discover_client_host = 1
xdebug.var_display_max_depth = 10
xdebug.var_display_max_data = 1024
xdebug.var_display_max_children = 256
```
**Warum `99-`?** Die Dateien werden alphabetisch geladen, die letzte gewinnt. Xdebug
bringt typischerweise `20-xdebug.ini` mit – `99-` läuft danach und überschreibt.
Außerdem überlebt die eigene Datei ein `apt upgrade`, während Änderungen an der
zentralen `php.ini` einen Konfliktdialog auslösen.
### 3.4 SAPI-Trennung beachten
Debian hat getrennte Bäume:
```
/etc/php/8.4/apache2/conf.d/
/etc/php/8.4/fpm/conf.d/
/etc/php/8.4/cli/conf.d/
```
Eine Änderung in `cli/` wirkt **nicht** auf den Webserver. Meist sind es Symlinks nach
`/etc/php/8.4/mods-available/` – dort anlegen und mit `phpenmod` aktivieren, dann gilt
sie für beide.
```bash
sudo systemctl restart apache2
```
---
## 4. Wo wird was eingetragen?
### 4.1 Die entscheidende Frage zuerst
```bash
php -i | grep -E "Loaded Configuration|Scan this dir"
```
| Ergebnis bei *Scan this dir* | Vorgehen |
|---|---|
| ein Verzeichnispfad | eigene Datei mit hoher Nummer, z. B. `99-xdebug-local.ini` |
| `(none)` | direkt in die `php.ini` (Loaded Configuration File) |
**XAMPP → immer `php.ini`** (Windows, macOS, Linux). XAMPP liefert bewusst eine
einzige, selbst verwaltete Datei ohne `conf.d`.
**Debian / RHEL / Sury / Docker-Images → `conf.d` mit `99-…`**
> CLI und Browser können unterschiedliche INIs laden. Was Apache tatsächlich nutzt,
> zeigt nur `phpinfo()` im Browser.
### 4.2 Referenz-Konfiguration
```ini
zend_extension = xdebug.so ; NICHT "extension="!
; Was Xdebug tut
xdebug.mode = develop,debug ; develop = schöneres var_dump + Stack-Traces
; debug = Breakpoints
; trace = Aufrufprotokoll in Datei
; profile = Performance-Analyse
; Wann Xdebug aktiv wird
xdebug.start_with_request = trigger ; nur bei ?XDEBUG_TRIGGER=1 – hält Overhead klein
; Verbindung zur IDE
xdebug.client_port = 9003
xdebug.client_host = 127.0.0.1
xdebug.discover_client_host = 1 ; praktisch bei Remote / Lima / Docker
; Anzeige-Limits (Defaults sind zu knapp!)
xdebug.var_display_max_depth = 10 ; Default 3
xdebug.var_display_max_children = 256 ; Default 128
xdebug.var_display_max_data = 1024 ; Default 512
```
Die drei Anzeige-Limits sind der Grund, warum `var_dump` oft `...` statt der
eigentlichen Daten zeigt.
### 4.3 Nur wenn keine INI-Datei erreichbar ist
**`.htaccess`** (nur bei mod_php, nicht FPM; erfordert `AllowOverride Options`):
```apache
php_value xdebug.var_display_max_depth 10
php_flag xdebug.collect_return 1
```
**Im Skript** – funktioniert nur für `PHP_INI_ALL`-Direktiven:
```php
ini_set('xdebug.var_display_max_depth', '10');
ini_set('xdebug.var_display_max_data', '1024');
```
Sinnvoll dann **einmal zentral** im Bootstrap, nicht in jeder Datei:
```php
require __DIR__ . '/vendor/autoload.php';
if (($_ENV['APP_ENV'] ?? 'prod') === 'dev') {
ini_set('xdebug.var_display_max_depth', '10');
ini_set('xdebug.var_display_max_data', '1024');
}
```
Zwei Fallstricke:
- Die Werte wirken erst auf `var_dump`-Aufrufe **nach** dem `ini_set()`
- Gilt nur für den einen Request (nicht für separate Ajax-/Cron-Skripte)
`xdebug.mode` ist `PHP_INI_SYSTEM` und lässt sich zur Laufzeit **nicht** setzen.
**Auf der CLI ganz ohne Datei:**
```bash
php -d xdebug.mode=develop,trace -d xdebug.start_with_request=yes script.php
```
---
## 5. Schritt für Schritt: Debuggen unter XAMPP (macOS/Windows)
Ausgangslage: Xdebug ist installiert, `php -v` zeigt „with Xdebug".
### Schritt 1 – Konfiguration eintragen (einmalig)
`php.ini` öffnen. Pfad zur *richtigen* Datei ermitteln:
```bash
# macOS
/Applications/XAMPP/xamppfiles/bin/php -i | grep "Loaded Configuration"
```
```
:: Windows
C:\xampp\php\php.exe -i | findstr "Loaded Configuration"
```
Am Ende der Datei eintragen (jede Direktive auf einer **eigenen Zeile**):
```ini
[XDebug]
zend_extension = /Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20220829/xdebug.so
xdebug.mode = develop,debug
xdebug.start_with_request = trigger
xdebug.client_port = 9003
xdebug.client_host = 127.0.0.1
xdebug.var_display_max_depth = 10
xdebug.var_display_max_data = 1024
xdebug.var_display_max_children = 256
```
Unter Windows genügt `zend_extension = xdebug`, weil die DLL in `ext\` liegt.
### Schritt 2 – Apache neu starten
```bash
sudo /Applications/XAMPP/xamppfiles/xampp restart
```
Windows: XAMPP Control Panel → Apache **Stop**, dann **Start**.
### Schritt 3 – Kontrollieren
Datei `htdocs/info.php` mit `<?php phpinfo();` anlegen, `http://localhost/info.php`
aufrufen. Es muss ein eigener **Xdebug-Abschnitt** erscheinen. Danach Datei löschen.
Ab hier ist Xdebug für **alle** Skripte unter `htdocs/` aktiv – ohne weitere Eintragung.
### Schritt 4 – Erster Test ohne IDE
Beliebige Datei, z. B. `htdocs/test.php`:
```php
<?php
$daten = ['id' => 7, 'name' => 'Müller', 'rollen' => ['admin', 'user']];
var_dump($daten);
```
Aufrufen. Erwartetes Ergebnis: farbige, eingerückte Ausgabe mit Datei- und
Zeilenangabe – **ohne** dass `<pre>` nötig wäre. Das ist der `develop`-Modus.
Ebenso: einen absichtlichen Fehler einbauen (`$x->foo();`) – statt der nackten
PHP-Meldung kommt ein tabellarischer Stack-Trace mit allen Aufrufen und Parametern.
### Schritt 5 – Breakpoint-Debugging vorbereiten
**Grundprinzip verstehen:** PHP verbindet sich **zur IDE**, nicht umgekehrt. Die IDE
lauscht auf Port 9003, PHP klopft an. Der Listener muss also **vor** dem Seitenaufruf
laufen – sonst passiert schlicht nichts.
VS Code: Extension „PHP Debug" (xdebug.php-debug) installieren, dann im Projektordner
`.vscode/launch.json` anlegen:
```json
{
"version": "0.2.0",
"configurations": [
{ "name": "Listen for Xdebug", "type": "php", "request": "launch", "port": 9003 }
]
}
```
`pathMappings` ist **nicht** nötig, weil Code und IDE auf derselben Maschine liegen.
### Schritt 6 – Breakpoint setzen und Session starten
1. In `test.php` links neben die Zeilennummer klicken → roter Punkt erscheint
2. **F5** drücken → unten wird die Statusleiste orange, VS Code lauscht jetzt
3. Im Browser aufrufen: `http://localhost/test.php?XDEBUG_TRIGGER=1`
4. Die Seite bleibt hängen, VS Code springt in den Vordergrund und markiert die Zeile
### Schritt 7 – Was man jetzt sieht
| Bereich in VS Code | Inhalt |
|---|---|
| **Variables** (links oben) | alle Variablen im aktuellen Scope, aufklappbar |
| **Watch** | eigene Ausdrücke: `$daten['name']`, `count($items)`, Methodenaufrufe |
| **Call Stack** | wer diese Funktion aufgerufen hat, mit Parametern – Klick springt dorthin |
| **Breakpoints** | Liste aller gesetzten Haltepunkte |
| **Debug Console** | beliebigen PHP-Code im aktuellen Kontext ausführen |
Steuerung: **F10** Step Over (nächste Zeile) · **F11** Step Into (in Funktion hinein) ·
**Shift+F11** Step Out · **F5** Continue (bis zum nächsten Breakpoint)
### Schritt 8 – Trigger bequemer machen
Der Query-Parameter `?XDEBUG_TRIGGER=1` funktioniert nicht bei POST-Formularen oder
Ajax. Lösung: Browser-Extension **Xdebug Helper** (Chrome/Firefox) – ein Klick auf den
Käfer setzt ein Cookie, danach ist jeder Request auf der Domain getriggert.
CLI-Äquivalent:
```bash
XDEBUG_TRIGGER=1 /Applications/XAMPP/xamppfiles/bin/php script.php
```
### Schritt 9 – Session beenden
**Shift+F5** in VS Code stoppt den Listener. Die Seite im Browser läuft dann normal
weiter. Ohne laufenden Listener werden Breakpoints einfach ignoriert – es entsteht kein
Fehler.
---
## 6. Schritt für Schritt: Debuggen unter Debian
Zwei Fälle: Code liegt lokal auf demselben Rechner, oder auf einem entfernten Server.
### Schritt 1 – Installieren und konfigurieren
```bash
sudo apt install php-xdebug
sudo nano /etc/php/8.4/apache2/conf.d/99-xdebug-local.ini
```
```ini
xdebug.mode = develop,debug
xdebug.start_with_request = trigger
xdebug.client_port = 9003
xdebug.discover_client_host = 1
xdebug.var_display_max_depth = 10
xdebug.var_display_max_data = 1024
xdebug.var_display_max_children = 256
```
```bash
sudo systemctl restart apache2
```
Für CLI-Skripte dieselbe Datei zusätzlich unter `/etc/php/8.4/cli/conf.d/` ablegen –
oder einmal in `mods-available/` und mit `phpenmod xdebug-local` für beide aktivieren.
### Schritt 2 – Kontrollieren
```bash
php -v # CLI: "with Xdebug v3.x.x"
php -i | grep xdebug.mode
```
Für den Webserver: `phpinfo()` im Browser aufrufen – nur das zeigt, was Apache lädt.
Danach die Datei löschen.
### Schritt 3 – Client-Position klären
Der Debug-Client läuft auf **deiner** Maschine, nicht auf dem Server.
| Situation | Vorgehen |
|---|---|
| Code liegt lokal | nichts weiter nötig, Listener einfach starten |
| Code auf entferntem Server | SSH-Reverse-Tunnel |
```bash
ssh -R 9003:localhost:9003 user@server
```
Damit verbindet sich Xdebug auf dem Server nach `localhost:9003` – und landet über den
Tunnel bei dir. Der Tunnel muss offen bleiben, solange du debuggst.
### Schritt 4 – Pfade zuordnen (nur bei Remote)
Die IDE muss wissen, welche lokale Datei welchem Serverpfad entspricht.
VS Code, `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/projekt": "${workspaceFolder}"
}
}
]
}
```
Links steht immer der **Serverpfad**, rechts der lokale. Stimmt das nicht, hält der
Debugger zwar an, öffnet aber keine Datei – der häufigste Frustpunkt bei Remote-Setups.
### Schritt 5 – Ohne VS Code: vdebug in Vim/Neovim
Spricht DBGp direkt, braucht nur Vim mit `+python3` – keine Node-Abhängigkeit.
`.vimrc`:
```vim
let g:vdebug_options = {
\ 'port': 9003,
\ 'break_on_open': 0,
\ 'path_maps': {'/var/www/projekt': '/home/sven/projekt'},
\}
```
Bedienung: **F5** Listener starten · **F10** Breakpoint setzen/entfernen ·
**F2** Step Over · **F3** Step Into · **F4** Step Out · **F6** beenden
Sobald die Session steht, teilt sich das Fenster: Quellcode, Variablen im aktuellen
Scope, Call-Stack und ein Watch-Bereich, in dem sich beliebige Ausdrücke auswerten
lassen.
Alternativen: **nvim-dap** (moderneres UI, braucht Node + `vscode-php-debug`) und
**dbgp-tools** von Derick Rethans (reiner CLI-Client, via Composer).
### Schritt 6 – Request triggern
```bash
# Webseite
http://server/projekt/index.php?XDEBUG_TRIGGER=1
# CLI-Skript auf dem Server
XDEBUG_TRIGGER=1 php artisan irgendwas
```
### Schritt 7 – Wenn keine IDE möglich ist: Trace-Dateien
Auf gesperrten Systemen oft der stärkste Hebel – ein Step-Debugger im Nachhinein.
```ini
xdebug.mode = develop,trace
xdebug.start_with_request = trigger
xdebug.output_dir = /tmp
xdebug.trace_format = 0
xdebug.collect_params = 4 ; volle Argumentwerte
xdebug.collect_return = 1
```
Ein Request mit `?XDEBUG_TRIGGER=1` schreibt `/tmp/trace.*.xt` – eine vollständige,
eingerückte Aufrufliste mit allen Parametern und Rückgabewerten:
```bash
ls -t /tmp/trace.*.xt | head -1 | xargs less
```
Gezielt nur einen Abschnitt protokollieren:
```php
xdebug_start_trace('/tmp/meintrace');
// verdächtiger Abschnitt
xdebug_stop_trace();
```
Für die Frage „wer ruft das mit welchen Werten auf" meist schneller als ein Breakpoint.
---
## 7. Was man wo sieht – Überblick
| Modus | Ausgabeort | Zeigt |
|---|---|---|
| `develop` | Browser / STDOUT | farbiges `var_dump`, Stack-Traces bei Fehlern |
| `trace` | Datei in `xdebug.output_dir` | kompletter Aufrufbaum mit Parametern |
| `debug` | IDE / Vim | Variablen, Call-Stack, Watch, schrittweise Ausführung |
| `profile` | `cachegrind.out.*` in `output_dir` | Laufzeit pro Funktion (qcachegrind) |
Zusätzlich im Code nutzbar (alle Modi):
```php
xdebug_info(); // Konfigurations-Übersicht im Browser
xdebug_break(); // Breakpoint aus dem Code heraus
var_dump(xdebug_get_function_stack()); // Wer hat mich aufgerufen?
error_log(xdebug_print_function_stack()); // Stack ins Logfile
echo xdebug_call_line();
```
### Conditional Breakpoints
Rechtsklick auf den Breakpoint → Bedingung eintragen, z. B. `$id === 4711`. Damit hält
man gezielt bei einem Datensatz in einer Schleife über 10.000 Zeilen an. Einer der
größten praktischen Vorteile gegenüber `var_dump`.
### Profiling
```ini
xdebug.mode = profile
xdebug.output_dir = /tmp
```
Auswertung mit **qcachegrind** (`brew install qcachegrind`, `apt install kcachegrind`).
> Nicht dauerhaft anlassen: bremst massiv und füllt `/tmp`.
---
## 8. Alternative & Ergänzung: Symfony VarDumper
Unabhängig von Xdebug, rein per Composer – nützlich auf Systemen, wo keine Extension
installiert werden darf.
```bash
composer require --dev symfony/var-dumper
```
```php
dump($row); // weiter im Code
dd($row, $other); // dump and die
```
Ausgabe im Browser aufklappbar, auf der CLI eingefärbt, kürzt rekursive Strukturen.
**Dump-Server** – fängt Ausgaben in einem separaten Terminal ab, statt sie in die
Response zu schreiben. Praktisch bei API-Endpunkten, wo HTML im Output stört:
```bash
vendor/bin/var-dump-server
# dazu: VAR_DUMPER_FORMAT=server
```
| PHP | symfony/var-dumper |
|---|---|
| 7.1 | `^4.4` |
| 7.2 – 7.4 | `^5.4` |
| 8.0 – 8.1 | `^6.4` |
| 8.2+ | `^7` |
**Absolutes Minimum**, wenn gar nichts geht (Ajax, Redirects, Cronjobs):
```php
error_log(var_export($row, true));
```
```bash
tail -f /var/log/apache2/error.log
```
### Ohne Xdebug: `<pre>` nicht vergessen
`var_dump()` gibt Plaintext aus, der Browser kollabiert Whitespace. Deshalb:
```php
function dbg(...$vars): void {
echo '<pre style="text-align:left">';
var_dump(...$vars);
echo '</pre>';
}
```
`var_dump()` ist variadisch – mehrere Werte auf einmal sind erlaubt. Praktischer Trick
zur Orientierung: `var_dump(__LINE__, $row);`
---
## 9. Stolperfallen-Kurzliste
| Symptom | Ursache / Lösung |
|---|---|
| Extension wird ignoriert, keine Meldung | `extension=` statt `zend_extension=` |
| `incompatible architecture (have 'arm64', need 'x86_64')` | Build ohne Rosetta-Shell – `arch -x86_64 /bin/zsh`, dann neu bauen |
| `already installed ... install failed` | `pecl uninstall xdebug` oder `pecl install -f` |
| `Failed loading ... (no such file)` beim `pecl`-Aufruf | harmlos: PHP liest die INI, die `.so` wurde gerade gelöscht |
| `pecl` schreibt in falsche PHP-Installation | XAMPP-eigenes `pecl` aus `.../xamppfiles/bin/` verwenden |
| CLI zeigt Xdebug, Browser nicht | Apache lädt eine andere `php.ini` → Pfad aus `phpinfo()` nehmen |
| Direktiven wirken nicht | alles in einer Zeile statt untereinander |
| `<datum>` im Pfad | Platzhalter! echten Namen per `php -i \| grep extension_dir` ermitteln |
| `var_dump` zeigt `...` statt Daten | `var_display_max_depth` / `_data` / `_children` erhöhen |
| Breakpoint wird nie erreicht | Listener nicht gestartet, oder Trigger fehlt |
| Debugger hält an, öffnet aber keine Datei | `pathMappings` / `path_maps` falsch (Serverpfad links) |
| Port-Verbindung schlägt fehl | Xdebug 2 nutzt 9000, Xdebug 3 nutzt 9003 |
| `autoconf: command not found` | `brew install autoconf` |
| `Cannot find php-config` | falsches `phpize`/`php-config` – das aus dem Ziel-PHP nehmen |
---
## 10. Randnotiz: `var_dump` mit Barewords
```php
var_dump("Test", ffff); // ohne $
```
| PHP | Verhalten |
|---|---|
| ≤ 7.1 | `Notice: Use of undefined constant ffff` → gibt `string(4) "ffff"` aus |
| 7.2 – 7.4 | `Deprecated`, sonst wie oben |
| 8.0+ | **fataler** `Error: Undefined constant "ffff"` |