Compare commits
33
Commits
82a2cadde7
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a7be25c65 | ||
|
|
5c541dfcd8 | ||
|
|
c418fe6153 | ||
|
|
af3537b17b | ||
|
|
19b153dd54 | ||
|
|
9610638462 | ||
|
|
815facc1cf | ||
|
|
bc4dc789a3 | ||
|
|
1907fefb57 | ||
|
|
b331e333ca | ||
|
|
12515fe2eb | ||
|
|
5a732b5490 | ||
|
|
ff77e6d7bb | ||
|
|
01c73526de | ||
|
|
b0d0884b76 | ||
|
|
f7478b9b25 | ||
|
|
df5138972f | ||
|
|
3a63a33b2a | ||
|
|
9ce65c617a | ||
|
|
2a36a62377 | ||
|
|
1e5a7d318f | ||
|
|
f2fe91fe30 | ||
|
|
c48157c54c | ||
|
|
3b095316d4 | ||
|
|
67121fb3f6 | ||
|
|
5a4eb08ca8 | ||
|
|
d696ff35e7 | ||
|
|
2a8733f8f8 | ||
|
|
a2df2755cf | ||
|
|
17170f2ec4 | ||
|
|
8e14f6594f | ||
|
|
53da75bbc5 | ||
|
|
5b00737df9 |
+106
@@ -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).
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||||
@@ -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 |
@@ -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%;" />
|
||||||
|
|
||||||
@@ -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}")
|
||||||
|
```
|
||||||
@@ -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)
|
||||||
|
```
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Scheme
|
||||||
|
|
||||||
|
## Definition von Variablen
|
||||||
|
|
||||||
|
### Globale Variablen
|
||||||
|
|
||||||
|
```scheme
|
||||||
|
(define variablenname wert)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```scheme
|
||||||
|
(define a 10)
|
||||||
|
|
||||||
|
(define name "Otto")
|
||||||
|
```
|
||||||
+194
@@ -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ß.
|
||||||
@@ -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
@@ -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.
|
||||||
@@ -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.*
|
||||||
@@ -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
@@ -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"` |
|
||||||
Reference in New Issue
Block a user