init at home

This commit is contained in:
2026-03-27 12:41:00 +01:00
commit 352c352056
58 changed files with 13083 additions and 0 deletions
+780
View File
@@ -0,0 +1,780 @@
---
# 🐳 Einführung in Docker
## 1. Was ist Docker?
Docker ist eine Plattform, mit der du **Container** erstellen, starten und verwalten kannst.
Ein Container ist eine Art "leichtgewichtige virtuelle Maschine":
- Enthält **nur das Nötigste** (Programm, Abhängigkeiten, Bibliotheken).
- Läuft isoliert, aber nutzt den Kernel des Host-Systems (kein eigener Kernel wie bei einer VM).
- Ist **schneller** und **ressourcenschonender** als klassische VMs.
👉 Bildlich: Statt für jedes Programm einen eigenen PC (VM) aufzubauen, packst du nur das Programm in eine "Transportbox" (Container), die überall läuft, solange Docker installiert ist.
---
## 2. Vorteile und typische Anwendungsfälle
### Vorteile
- **Portabilität**: „Läuft auf meinem Rechner“ = „läuft auch auf Servern“.
- **Isolierung**: Verschiedene Programme/Versionen stören sich nicht.
- **Leichtgewicht**: Start in Sekunden statt Minuten wie bei VMs.
- **Reproduzierbarkeit**: Gleiche Umgebung für Entwicklung, Test und Produktion.
- **Einfache Verteilung**: Images können über Docker Hub oder private Registries geteilt werden.
### Typische Anwendungsfälle
- 🚀 **Entwicklung**: Z. B. [[Python]] 3.10 testen, obwohl auf dem System Python 3.12 läuft.
- 🗄️ **Datenbanken**: [[MySQL]], PostgreSQL, Redis, MongoDB zum Testen ohne Installation.
- 🌐 **Web-Apps**: Schnell mal eine fertige Anwendung ausprobieren (WordPress, Nextcloud, GitLab etc.).
- 🧪 **Testing**: Mehrere Umgebungen simulieren (verschiedene OS, Bibliotheksversionen).
- 📦 **Deployment**: Gleiche App auf mehreren Servern identisch bereitstellen.
---
## 3. Hauptfunktionalitäten von Docker
- **Docker Engine**: Herzstück, das Container ausführt.
- **Docker Images**: Baupläne (Templates) für Container (z. B. Python 3.12 + Flask).
- **Docker Containers**: Laufende Instanzen von Images.
- **Docker Hub/Registry**: Cloud-Marktplatz für fertige Images.
- **Docker Compose**: Orchestrierung mehrerer Container (z. B. App + DB + Cache).
---
## 4. Installation unter Linux (Beispiel: Ubuntu/Debian)
```bash
# 1. Alte Versionen entfernen
sudo apt-get remove docker docker-engine docker.io containerd runc
# 2. Repository vorbereiten
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
# Docker GPG-Key hinzufügen
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Repository einrichten
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 3. Docker installieren
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 4. Testen
sudo docker run hello-world
```
👉 Danach kannst du optional dich in die `docker`-Gruppe aufnehmen (sonst musst du immer `sudo` schreiben):
```bash
sudo usermod -aG docker $USER
# Abmelden/neu anmelden, damit es wirkt
```
---
## 5. Erste Schritte in der Praxis
### Beispiel 1: Linux — Container starten
```bash
# Einen Ubuntu-Container starten (interaktiv)
docker run -it ubuntu bash
# Danach bist du im Container:
root@<id>:/# cat /etc/os-release
```
Wenn du rausgehst (`exit`), bleibt der Container gespeichert.
---
### Beispiel 2: Linux — Nginx-Webserver starten
```bash
# Nginx starten, Port 8080 weiterleiten
docker run -d -p 8080:80 nginx
# Nun im Browser: http://localhost:8080
```
---
### Beispiel 3: Python im Container
Nehmen wir an, du willst ein Python-Skript in einer isolierten Umgebung ausführen.
**hello.py**
```python
print("Hello from Dockerized Python!")
```
**Dockerfile**
```dockerfile
FROM python:3.11-slim
# Skript ins Image kopieren
COPY hello.py /app/hello.py
# Arbeitsverzeichnis setzen
WORKDIR /app
# Default-Befehl
CMD ["python", "hello.py"]
```
**Bauen und starten**
```bash
# Image bauen
docker build -t mypythonapp .
# Container starten
docker run --rm mypythonapp
```
Ausgabe:
```
Hello from Dockerized Python!
```
---
### Beispiel 4: Python mit externer Bibliothek
```python
# requirements.txt
flask==3.0.0
```
**app.py**
```python
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, Docker!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
```
**Dockerfile**
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]
```
**Starten**
```bash
docker build -t flaskapp .
docker run -d -p 5000:5000 flaskapp
```
👉 Browser öffnen: `http://localhost:5000`
---
## 6. Nützliche Docker-Befehle (Cheatsheet)
- `docker ps` laufende Container
- `docker ps -a` alle Container (inkl. gestoppter)
- `docker images` vorhandene Images
- `docker stop <id>` Container stoppen
- `docker rm <id>` Container löschen
- `docker rmi <image>` Image löschen
- `docker exec -it <id> bash` in Container einsteigen
---
✅ Damit hast du einen vollständigen Überblick über Docker:
- **Grundidee**
- **Vorteile/Anwendungsfälle**
- **Installation**
- **Praxis mit Linux und Python**
---
# Anwendungsbeispiel
# 🐳 Docker Anwendungsbeispiel - Detaillierte Erklärung für Einsteiger
## 📚 Was ist Docker überhaupt?
**Docker** ist wie ein **"Umzugskarton für Software"**:
- Stell Dir vor, Du willst Deine App an einen Freund verschicken
- Statt nur den Code zu senden, packst Du **alles** ein: Code, Python, alle Bibliotheken, Konfiguration
- Dein Freund öffnet den "Karton" (Container) und alles läuft sofort - egal welches Betriebssystem er hat
---
## 📁 Projektstruktur mit Erklärungen
```
python-docker-project/
├── app/ # 📂 Unser Python-Code
│ ├── __init__.py # (macht 'app' zu einem Python-Paket)
│ ├── main.py # Hauptprogramm
│ ├── data_processor.py # Modul für Datenverarbeitung
│ └── database.py # Modul für Datenbankzugriff
├── input/ # 📁 Hier liegen die Input-Dateien (vom Host)
│ └── sample_data.csv # Beispieldatei
├── output/ # 📁 Hier kommen verarbeitete Dateien rein
├── requirements.txt # 📝 Liste aller Python-Pakete die wir brauchen
├── Dockerfile # 🐳 "Bauanleitung" für unseren Container
├── docker-compose.yml # 🎼 "Dirigent" für mehrere Container
└── .env # 🔐 Geheime Einstellungen (Passwörter etc.)
```
---
## 🐍 Python-Code (wie gewohnt)
### **requirements.txt** - "Einkaufsliste" für Python-Pakete
```txt
# 🛒 Diese Pakete braucht unser Programm
pandas==2.1.4 # Für Excel/CSV-Verarbeitung
psycopg2-binary==2.9.9 # Um mit PostgreSQL zu sprechen
python-dotenv==1.0.0 # Um .env-Dateien zu lesen
sqlalchemy==2.0.23 # Einfache Datenbankanbindung
```
**💡 Warum brauche ich das?**
- Ohne Docker müsstest Du auf jedem PC manuell `pip install pandas` etc. machen
- Mit Docker installiert sich das automatisch im Container
### **app/main.py** - Unser Hauptprogramm
```python
#!/usr/bin/env python3
"""
🎯 Das macht unser Programm:
1. Schaut in /app/input nach CSV-Dateien
2. Verarbeitet sie (quadriert Werte, etc.)
3. Speichert Ergebnis in PostgreSQL-Datenbank
4. Exportiert auch als CSV in /app/output
"""
import os
import time
from pathlib import Path
from dotenv import load_dotenv
from .data_processor import DataProcessor
from .database import DatabaseManager
def main():
print("🚀 Starte Data Processing Pipeline...")
# 📁 Diese Pfade sind INSIDE dem Container!
input_dir = Path("/app/input") # Gemountet von Host ./input/
output_dir = Path("/app/output") # Gemountet von Host ./output/
output_dir.mkdir(exist_ok=True)
# 🗄️ Verbindung zur Datenbank (anderer Container!)
db_manager = DatabaseManager()
processor = DataProcessor(db_manager)
# 📊 Alle CSV-Dateien finden und verarbeiten
csv_files = list(input_dir.glob("*.csv"))
if not csv_files:
print("❌ Keine CSV-Dateien im Input-Verzeichnis gefunden!")
return
for csv_file in csv_files:
print(f"📄 Verarbeite: {csv_file.name}")
# 1️⃣ Daten aus CSV laden und verarbeiten
result_data = processor.process_file(csv_file)
# 2️⃣ In PostgreSQL-Container speichern
processor.save_to_database(result_data, csv_file.stem)
# 3️⃣ Als neue CSV-Datei exportieren
output_file = output_dir / f"processed_{csv_file.name}"
result_data.to_csv(output_file, index=False)
print(f"💾 Gespeichert als: {output_file}")
print("✅ Pipeline abgeschlossen!")
if __name__ == "__main__":
main()
```
### **app/database.py** - Spricht mit der Datenbank
```python
import os
import pandas as pd
from sqlalchemy import create_engine, text
class DatabaseManager:
def __init__(self):
# 🔌 Diese Werte kommen aus der docker-compose.yml!
self.host = os.getenv('DB_HOST', 'postgres') # Name des DB-Containers!
self.port = os.getenv('DB_PORT', '5432')
self.database = os.getenv('DB_NAME', 'dataprocessing')
self.user = os.getenv('DB_USER', 'postgres')
self.password = os.getenv('DB_PASSWORD', 'password')
# 🌐 Connection String - wie eine Adresse zur Datenbank
self.connection_string = (
f"postgresql://{self.user}:{self.password}@"
f"{self.host}:{self.port}/{self.database}"
)
self.engine = None
self._connect()
def _connect(self):
"""Verbindung zur Datenbank herstellen"""
try:
self.engine = create_engine(self.connection_string)
# 🏓 Kurzer Test: "Hallo Datenbank!"
with self.engine.connect() as conn:
conn.execute(text("SELECT 1"))
print("✅ Datenbankverbindung erfolgreich")
except Exception as e:
print(f"❌ Datenbankverbindung fehlgeschlagen: {e}")
raise
def save_dataframe(self, df: pd.DataFrame, table_name: str):
"""Speichert DataFrame als Tabelle in PostgreSQL"""
df.to_sql(
name=table_name,
con=self.engine,
if_exists='replace', # Überschreibt existierende Tabelle
index=False
)
```
*(Die anderen Python-Dateien bleiben gleich)*
---
## 🐳 Dockerfile - "Bauanleitung" für unseren Container
```dockerfile
# 🏗️ SCHRITT 1: Basis-Image wählen
# Das ist wie ein "Rohbau" - Linux + Python sind schon installiert
FROM python:3.11-slim
# 🛠️ SCHRITT 2: System-Tools installieren
# Wir brauchen gcc und libpq-dev für PostgreSQL-Verbindung
RUN apt-get update && apt-get install -y \
gcc \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 💡 WARUM: psycopg2 (PostgreSQL-Driver) braucht diese Tools zum Kompilieren
# 📂 SCHRITT 3: Arbeitsverzeichnis setzen
WORKDIR /app
# Das ist wie "cd /app" - alle folgenden Befehle laufen hier
# 📦 SCHRITT 4: Python-Pakete installieren
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 💡 WARUM separat? Docker cached diesen Layer - muss nur neu gebaut werden wenn requirements.txt ändert
# 📋 SCHRITT 5: Unseren Code ins Container kopieren
COPY app/ ./app/
# Kopiert alles aus Host-Ordner "app/" nach Container "/app/app/"
# 📁 SCHRITT 6: Verzeichnisse erstellen
RUN mkdir -p /app/input /app/output
# Diese werden später durch Volume-Mounts "überschrieben"
# ⚙️ SCHRITT 7: Umgebungsvariablen setzen
ENV PYTHONPATH=/app # Python findet unsere Module
ENV PYTHONUNBUFFERED=1 # Print-Ausgaben erscheinen sofort
# 🚀 SCHRITT 8: Was soll beim Container-Start passieren?
CMD ["python", "-m", "app.main"]
# Startet unser Hauptprogramm
```
**🤔 Was passiert beim `docker build`?**
1. Docker lädt `python:3.11-slim` herunter (falls nicht da)
2. Installiert gcc und PostgreSQL-Tools
3. Kopiert `requirements.txt` und installiert Python-Pakete
4. Kopiert unseren Code rein
5. Setzt Umgebungsvariablen
6. **Ergebnis:** Ein fertiger Container mit allem was wir brauchen!
---
## 🎼 docker-compose.yml - "Dirigent" für mehrere Container
```yaml
# 🎯 docker-compose orchestriert MEHRERE Container gleichzeitig
version: '3.8'
services:
# 🗄️ CONTAINER 1: PostgreSQL-Datenbank
postgres:
image: postgres:15 # Fertiges PostgreSQL-Image von Docker Hub
environment: # Umgebungsvariablen für PostgreSQL
POSTGRES_DB: dataprocessing # Name der Datenbank die erstellt wird
POSTGRES_USER: postgres # Benutzername
POSTGRES_PASSWORD: password # 🔐 Passwort (in Produktion geheimer!)
volumes:
- postgres_data:/var/lib/postgresql/data # 💾 Daten persistent speichern
- ./db_init:/docker-entrypoint-initdb.d # 📂 Optional: SQL-Skripts beim Start
ports:
- "5432:5432" # Port freigeben (Host:Container)
networks:
- app_network # 🌐 Internes Netzwerk für Container-Kommunikation
# 🐍 CONTAINER 2: Unsere Python-Anwendung
python_app:
build: . # 🏗️ Baue Container aus Dockerfile in diesem Verzeichnis
environment: # Diese Variablen kann unser Python-Code lesen
DB_HOST: postgres # ❗ WICHTIG: Name des DB-Containers (nicht localhost!)
DB_PORT: 5432
DB_NAME: dataprocessing
DB_USER: postgres
DB_PASSWORD: password
volumes: # 📂 Verbinde Host-Verzeichnisse mit Container
- ./input:/app/input:ro # Host ./input → Container /app/input (read-only)
- ./output:/app/output # Host ./output → Container /app/output (read-write)
depends_on: # ⏱️ Warte bis postgres-Container läuft
- postgres
networks:
- app_network # 🌐 Gleiches Netzwerk = können miteinander sprechen
restart: unless-stopped # 🔄 Automatisch neu starten bei Absturz
# 🌐 CONTAINER 3: pgAdmin (Web-Interface für PostgreSQL)
pgadmin:
image: dpage/pgadmin4:8
environment:
PGADMIN_DEFAULT_EMAIL: admin@example.com
PGADMIN_DEFAULT_PASSWORD: admin
ports:
- "8080:80" # 🌐 Zugriff via http://localhost:8080
depends_on:
- postgres
networks:
- app_network
# 💾 VOLUMES: Persistente Datenspeicherung
volumes:
postgres_data: # Docker verwaltet diesen Speicher automatisch
# 💡 Auch wenn Container gelöscht wird, bleiben Daten erhalten
# 🌐 NETWORKS: Virtuelle Netzwerke für Container-Kommunikation
networks:
app_network:
driver: bridge # Standard-Netzwerk-Typ
# 💡 Alle Container in diesem Netzwerk können sich über Namen erreichen
```
**🤔 Warum docker-compose?**
- **Ohne compose:** `docker run postgres`, dann `docker run python_app` - sehr umständlich!
- **Mit compose:** Ein Befehl (`docker-compose up`) startet ALLES automatisch
- **Networks:** Container können sich über Namen finden (`postgres` statt IP-Adresse)
- **Volumes:** Daten gehen nicht verloren beim Container-Neustart
---
## 🔧 .env - Geheime Konfiguration
```env
# 🔐 Sensible Daten sollten NICHT in docker-compose.yml stehen
# Diese Datei wird von docker-compose automatisch gelesen
# Datenbankverbindung
DB_HOST=postgres
DB_PORT=5432
DB_NAME=dataprocessing
DB_USER=postgres
DB_PASSWORD=password # ❗ In Produktion: sicheres Passwort!
# Python-Einstellungen
PYTHONPATH=/app
PYTHONUNBUFFERED=1
```
**💡 Wichtig:** Die `.env`-Datei niemals in Git committen! (→ `.gitignore`)
---
## 📊 Beispiel-Daten
### **input/sample_data.csv**
```csv
id,name,value,category
1,Item A,10,electronics
2,Item B,25,clothing
3,Item C,15,electronics
4,Item D,30,books
5,Item E,8,clothing
```
**💡 Das ist eine normale CSV-Datei auf Deinem Host-PC**
- Liegt in `./input/sample_data.csv`
- Wird in den Container als `/app/input/sample_data.csv` "gemountet"
- Unser Python-Code kann sie lesen, als wäre sie im Container
---
## 🚀 Schritt-für-Schritt Anleitung
### **1. Projekt erstellen**
```bash
# Verzeichnis erstellen
mkdir python-docker-project
cd python-docker-project
# Struktur erstellen
mkdir -p app input output
touch requirements.txt Dockerfile docker-compose.yml .env
touch app/__init__.py app/main.py app/data_processor.py app/database.py
```
### **2. Code schreiben**
- Alle Dateien wie oben gezeigt erstellen und befüllen
### **3. Container bauen und starten**
```bash
# Alle Container bauen und starten
docker-compose up --build
# 🔍 Was passiert:
# 1. Docker baut unseren Python-Container (aus Dockerfile)
# 2. Lädt PostgreSQL-Image herunter
# 3. Lädt pgAdmin-Image herunter
# 4. Erstellt Netzwerk "app_network"
# 5. Startet postgres-Container
# 6. Startet python_app-Container (wartet auf postgres)
# 7. Startet pgAdmin-Container
```
### **4. Überprüfen ob alles läuft**
```bash
# Laufende Container anzeigen
docker-compose ps
# Logs ansehen
docker-compose logs python_app
docker-compose logs postgres
# In pgAdmin einloggen: http://localhost:8080
# Email: admin@example.com, Passwort: admin
```
### **5. Neue Daten verarbeiten**
```bash
# Neue CSV-Datei ins input-Verzeichnis kopieren
cp neue_daten.csv input/
# Python-App neu starten um neue Dateien zu verarbeiten
docker-compose restart python_app
# Ergebnis ansehen
ls -la output/
```
### **6. System stoppen**
```bash
# Alle Container stoppen
docker-compose down
# Container stoppen UND Daten löschen (Vorsicht!)
docker-compose down -v
```
---
## 🔍 Docker-Befehle erklärt
### **Grundlegende Container-Befehle**
```bash
# 📋 Alle laufenden Container anzeigen
docker ps
# 📋 Alle Container anzeigen (auch gestoppte)
docker ps -a
# 🔍 Container-Logs ansehen
docker logs <container-name>
# 🔑 In laufenden Container "einsteigen"
docker exec -it <container-name> bash
# 🗑️ Container stoppen
docker stop <container-name>
# 🗑️ Container löschen
docker rm <container-name>
```
### **Image-Befehle**
```bash
# 📋 Alle Images anzeigen
docker images
# 🏗️ Image aus Dockerfile bauen
docker build -t mein-python-app .
# 🗑️ Image löschen
docker rmi <image-name>
# 🧹 Unbenutzte Images löschen
docker image prune
```
### **docker-compose-Befehle**
```bash
# 🚀 Alle Services starten
docker-compose up
# 🚀 Im Hintergrund starten
docker-compose up -d
# 🏗️ Images neu bauen und starten
docker-compose up --build
# 🔄 Einzelnen Service neu starten
docker-compose restart python_app
# 📋 Status aller Services
docker-compose ps
# 🔍 Logs aller Services
docker-compose logs
# 🔍 Logs eines bestimmten Service
docker-compose logs python_app
# 📈 Live-Logs verfolgen
docker-compose logs -f python_app
# 🔑 In Container einsteigen
docker-compose exec python_app bash
docker-compose exec postgres psql -U postgres -d dataprocessing
# ⏹️ Alle Services stoppen
docker-compose down
# 🗑️ Services stoppen und Volumes löschen
docker-compose down -v
```
---
## 🌟 Die wichtigsten Docker-Konzepte
### **1. Images vs Container**
- **Image** = "Bauplan" (wie ein Kuchenrezept)
- **Container** = "Laufende Instanz" (wie ein gebackener Kuchen)
- Ein Image kann viele Container erstellen
### **2. Volumes**
```yaml
volumes:
- ./input:/app/input # Host-Verzeichnis → Container-Verzeichnis
```
- **Warum?** Container-Dateisystem ist temporär
- **Volume** = persistenter Speicher der überlebt
### **3. Networks**
- Container in gleichem Netzwerk können sich über Namen erreichen
- `python_app` kann `postgres` kontaktieren (nicht IP-Adresse!)
### **4. Environment Variables**
```yaml
environment:
DB_HOST: postgres # Diese Variable kann Python-Code lesen
```
### **5. Ports**
```yaml
ports:
- "8080:80" # Host-Port : Container-Port
```
- Container-Port 80 wird auf Host-Port 8080 freigegeben
- Zugriff: `http://localhost:8080`
---
## ❓ Häufige Anfänger-Probleme
### **Problem 1: "Connection refused" zur Datenbank**
```
❌ FALSCH: DB_HOST=localhost
✅ RICHTIG: DB_HOST=postgres
```
- In Docker ist `localhost` der Container selbst
- Verwende den Service-Namen aus `docker-compose.yml`
### **Problem 2: "File not found"**
```
❌ FALSCH: input_dir = Path("./input")
✅ RICHTIG: input_dir = Path("/app/input")
```
- Pfade sind INSIDE dem Container, nicht auf dem Host
### **Problem 3: "Module not found"**
```
❌ FALSCH: Umgebungsvariable vergessen
✅ RICHTIG: ENV PYTHONPATH=/app in Dockerfile
```
### **Problem 4: Änderungen nicht sichtbar**
```bash
# Nach Code-Änderungen Container neu bauen:
docker-compose up --build
```
### **Problem 5: Port bereits belegt**
```
❌ Error: Port 5432 already in use
✅ Lösung: Anderen Port verwenden: "5433:5432"
```
---
## 🎯 Zusammenfassung - Was macht was?
| Datei/Komponente | Was es macht | Warum wichtig |
|------------------|--------------|---------------|
| **Dockerfile** | "Bauanleitung" für Python-Container | Definiert was IN den Container kommt |
| **docker-compose.yml** | Orchestriert mehrere Container | Ein Befehl startet alles |
| **requirements.txt** | Liste der Python-Pakete | Automatische Installation |
| **.env** | Geheime Konfiguration | Passwörter nicht in Code |
| **volumes** | Datenaustausch Host ↔ Container | Input/Output-Dateien |
| **networks** | Container-Kommunikation | python_app kann postgres erreichen |
| **ports** | Zugriff von außen | Web-Interface erreichbar |
**🚀 Mit einem Befehl hast Du:**
- ✅ Python-Umgebung mit allen Paketen
- ✅ PostgreSQL-Datenbank
- ✅ Web-Interface für DB
- ✅ Automatische File-Verarbeitung
- ✅ Persistente Datenspeicherung
**Das ist die Macht von Docker! 🐳**
@@ -0,0 +1,740 @@
```markdown
---
title: JavaScript Tutorial (für Python-Erfahrene)
tags: [javascript, tutorial, beginner, programming]
created: 2026-03-27
---
# JavaScript Tutorial (für Python-Erfahrene)
Ziel: Du lernst JavaScript von Grund auf, aber mit Fokus auf das, was du als Python-Erfahrener schnell einordnen kannst. Viele Beispiele sind so gestaltet, dass du sie 1:1 nachbauen und variieren kannst.
---
## Inhaltsverzeichnis
1. [[#0 Wie führe ich JavaScript am besten aus]]
2. [[#1 Grundsyntax & Variablen]]
3. [[#2 Datentypen, Equality, Truthy/Falsy]]
4. [[#3 Strings & Template Literals]]
5. [[#4 Arrays (Listen) & Methoden]]
6. [[#5 Objekte (Dictionaries) & JSON]]
7. [[#6 Kontrollfluss (if, switch, Schleifen)]]
8. [[#7 Funktionen (inkl. Arrow Functions)]]
9. [[#8 Scope, Hoisting, Closures]]
10. [[#9 Module (import/export)]]
11. [[#10 Klassen & Prototypen]]
12. [[#11 Fehlerbehandlung (try/catch)]]
13. [[#12 Asynchronität: Event Loop, Promises, async/await]]
14. [[#13 DOM: Webseiten manipulieren]]
15. [[#14 Events (Click, Input, Delegation)]]
16. [[#15 Fetch API (HTTP), APIs, JSON]]
17. [[#16 Praktische Mini-Projekte]]
18. [[#17 Tooling: npm, Vite, Linting (kurz)]]
19. [[#18 Cheatsheet: Python vs. JavaScript]]
---
## 0) Wie führe ich JavaScript am besten aus?
### Option A — Browser-Konsole (schnell zum Experimentieren)
1. Öffne eine Website (z. B. `about:blank`)
2. DevTools öffnen:
- Chrome/Edge: `F12` oder `Ctrl+Shift+I`
- macOS: `Cmd+Opt+I`
3. Tab **Console** → JavaScript eintippen.
Beispiel:
```js
console.log("Hello JS!");
```
**Pro:** sofortiges Feedback
**Contra:** nicht so gut für größere Projekte
---
### Option B — HTML + `<script>` direkt im HTML (einfach)
Erstelle `index.html`:
```html
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<title>JS Tutorial</title>
</head>
<body>
<h1>Hallo JavaScript</h1>
<script>
console.log("JS läuft!");
</script>
</body>
</html>
```
Öffne die Datei im Browser (Doppelklick) und dann DevTools → Console.
---
### Option C — HTML + externes `.js` File (empfohlen)
Das ist die gängigste Lern- und Projektstruktur.
`index.html`:
```html
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<title>JS Tutorial</title>
<script defer src="./main.js"></script>
</head>
<body>
<h1>Hallo JavaScript</h1>
<button id="btn">Klick mich</button>
</body>
</html>
```
`main.js`:
```js
console.log("main.js geladen");
document.querySelector("#btn").addEventListener("click", () => {
console.log("Button geklickt");
});
```
**Wichtig:** `defer` sorgt dafür, dass das HTML zuerst geparst wird, bevor dein JS läuft (sehr praktisch für DOM-Skripte).
---
### Option D — Node.js (JavaScript außerhalb des Browsers)
Installiere Node.js (LTS). Dann im Terminal:
```bash
node -v
node
```
Oder Datei:
`app.js`:
```js
console.log("Hallo aus Node!");
```
Run:
```bash
node app.js
```
**Merke:** Browser-JS hat DOM/Web-APIs, Node hat dafür File-System etc.
---
## 1) Grundsyntax & Variablen
### `let`, `const`, (vermeide `var`)
```js
let x = 10; // kann neu zugewiesen werden
x = 11;
const y = 20; // darf nicht neu zugewiesen werden
// y = 21; // TypeError
const obj = { a: 1 };
obj.a = 2; // erlaubt! (Objektinhalt mutiert)
// obj = { a: 3 }; // nicht erlaubt (Neuzuweisung)
```
**Python-Vergleich:** `const` ist kein echtes Immutable wie `tuple`, sondern verhindert nur Reassignment der Variable.
---
## 2) Datentypen, Equality, Truthy/Falsy
### Primitive Typen
- `number` (integers + floats)
- `string`
- `boolean`
- `undefined`
- `null`
- `bigint`
- `symbol`
```js
let a; // undefined
let b = null; // absichtlich "leer"
```
### `==` vs `===` (wichtig)
- `===` vergleicht **ohne** Typumwandlung → nutze das fast immer
- `==` macht implizite Konvertierung → vermeide für Anfänger
```js
0 == false // true (komisch)
0 === false // false (gut/strikt)
"5" == 5 // true
"5" === 5 // false
```
### Truthy / Falsy
Falsy sind u. a.: `false`, `0`, `""`, `null`, `undefined`, `NaN`
```js
if ("") console.log("läuft nicht");
if ("0") console.log("läuft"); // nicht leerer String ist truthy
```
---
## 3) Strings & Template Literals
```js
const name = "Ada";
const age = 30;
console.log("Hallo " + name + ", du bist " + age);
console.log(`Hallo ${name}, du bist ${age}`); // Template Literal
```
Nützliche String-Methoden:
```js
"Hello".toUpperCase(); // "HELLO"
" hi ".trim(); // "hi"
"abc".includes("b"); // true
"1,2,3".split(","); // ["1","2","3"]
```
---
## 4) Arrays (Listen) & Methoden
```js
const nums = [1, 2, 3];
nums.push(4); // [1,2,3,4]
nums.pop(); // entfernt letztes
nums[0]; // 1
```
### Iteration
```js
for (const n of nums) {
console.log(n);
}
```
### `map`, `filter`, `reduce` (sehr wichtig)
```js
const doubled = nums.map(n => n * 2); // [2,4,6]
const evens = nums.filter(n => n % 2 === 0); // [2]
const sum = nums.reduce((acc, n) => acc + n, 0); // 6
```
**Python-Vergleich:** `map/filter/reduce` ähnlich, aber in JS extrem häufig in UI/Frontend.
---
## 5) Objekte (Dictionaries) & JSON
### Objekte (Key-Value)
```js
const user = {
name: "Ada",
age: 30,
isAdmin: true
};
console.log(user.name);
console.log(user["age"]);
```
### Dynamische Keys
```js
const key = "score";
const obj = { [key]: 42 };
console.log(obj.score); // 42
```
### Object Destructuring
```js
const { name, age } = user;
console.log(name, age);
```
### Spread (Kopieren/Mergen)
```js
const a = { x: 1, y: 2 };
const b = { ...a, y: 999, z: 3 }; // {x:1,y:999,z:3}
```
### JSON
```js
const json = JSON.stringify(user);
const parsed = JSON.parse(json);
```
---
## 6) Kontrollfluss (if, switch, Schleifen)
```js
const n = 7;
if (n > 10) {
console.log("groß");
} else if (n > 5) {
console.log("mittel");
} else {
console.log("klein");
}
```
### `switch`
```js
const role = "admin";
switch (role) {
case "admin":
console.log("Alles erlaubt");
break;
case "user":
console.log("Standardrechte");
break;
default:
console.log("Unbekannt");
}
```
### Schleifen
```js
for (let i = 0; i < 3; i++) console.log(i);
let i = 0;
while (i < 3) {
console.log(i);
i++;
}
```
---
## 7) Funktionen (inkl. Arrow Functions)
### Funktionsdeklaration
```js
function add(a, b) {
return a + b;
}
```
### Function Expression
```js
const add2 = function (a, b) {
return a + b;
};
```
### Arrow Function
```js
const add3 = (a, b) => a + b;
```
### Default-Parameter
```js
function greet(name = "Welt") {
return `Hallo ${name}`;
}
```
### Rest-Parameter
```js
function sum(...nums) {
return nums.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3); // 6
```
---
## 8) Scope, Hoisting, Closures
### Block-Scope: `let/const`
```js
if (true) {
let x = 1;
}
// console.log(x); // ReferenceError
```
### Hoisting (vereinfachte Regel)
- `var` wird “hochgezogen” → vermeiden
- `let/const` existieren zwar “vorher”, sind aber in der **Temporal Dead Zone** → besser/strikter
### Closure
```js
function makeCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const c = makeCounter();
c(); // 1
c(); // 2
```
**Python-Vergleich:** ähnlich wie inner functions mit captured variables.
---
## 9) Module (import/export)
**Browser-Module**: In HTML:
```html
<script type="module" src="./main.js"></script>
```
`math.js`:
```js
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
```
`main.js`:
```js
import { add, PI } from "./math.js";
console.log(add(2, 3));
console.log(PI);
```
---
## 10) Klassen & Prototypen
### Klasse
```js
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hi ${this.name}`;
}
}
const u = new User("Ada");
console.log(u.greet());
```
### Vererbung
```js
class Admin extends User {
constructor(name) {
super(name);
this.role = "admin";
}
}
const a = new Admin("Grace");
```
**Merke:** JS ist prototyp-basiert; `class` ist syntactic sugar.
---
## 11) Fehlerbehandlung (try/catch)
```js
try {
JSON.parse("{ broken");
} catch (err) {
console.error("Parsing fehlgeschlagen:", err.message);
} finally {
console.log("läuft immer");
}
```
Eigene Fehler:
```js
function requirePositive(n) {
if (n <= 0) throw new Error("n muss > 0 sein");
return n;
}
```
---
## 12) Asynchronität: Event Loop, Promises, async/await
### Warum async?
Im Browser soll UI nicht blockieren. In Node gehts um I/O.
### Promise Basics
```js
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve("fertig"), 500);
});
p.then(value => console.log(value));
```
### `async/await` (empfohlen)
```js
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function run() {
console.log("start");
await wait(300);
console.log("nach 300ms");
}
run();
```
### Parallel vs. sequenziell
```js
async function parallel() {
const p1 = wait(200);
const p2 = wait(300);
await Promise.all([p1, p2]);
console.log("beide fertig");
}
```
---
## 13) DOM: Webseiten manipulieren
### Elemente finden
```js
const h1 = document.querySelector("h1");
const items = document.querySelectorAll("li");
```
### Text/HTML ändern
```js
h1.textContent = "Neuer Titel";
h1.innerHTML = "<em>Kursiv</em>"; // vorsichtig (XSS bei fremden Daten!)
```
### Klassen und Styles
```js
h1.classList.add("highlight");
h1.style.color = "tomato";
```
### Elemente erstellen & anhängen
```js
const ul = document.querySelector("ul");
const li = document.createElement("li");
li.textContent = "Neues Item";
ul.appendChild(li);
```
---
## 14) Events (Click, Input, Delegation)
`index.html`:
```html
<input id="name" placeholder="Name" />
<button id="save">Speichern</button>
<div id="out"></div>
```
`main.js`:
```js
const input = document.querySelector("#name");
const btn = document.querySelector("#save");
const out = document.querySelector("#out");
btn.addEventListener("click", () => {
out.textContent = `Hallo ${input.value}`;
});
```
### Event Delegation (praktisch bei Listen)
```js
document.querySelector("#list").addEventListener("click", (e) => {
if (e.target.matches("li")) {
console.log("geklickt:", e.target.textContent);
}
});
```
---
## 15) Fetch API (HTTP), APIs, JSON
### GET Request
```js
async function loadTodo() {
const res = await fetch("https://jsonplaceholder.typicode.com/todos/1");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
}
loadTodo().catch(console.error);
```
### POST Request
```js
async function createPost() {
const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Hi", body: "Text", userId: 1 })
});
const data = await res.json();
console.log("created:", data);
}
```
---
## 16) Praktische Mini-Projekte
### Projekt 1: Counter
`index.html`:
```html
<h1 id="count">0</h1>
<button id="dec">-</button>
<button id="inc">+</button>
<button id="reset">reset</button>
<script defer src="./main.js"></script>
```
`main.js`:
```js
let count = 0;
const el = document.querySelector("#count");
const render = () => (el.textContent = String(count));
document.querySelector("#inc").addEventListener("click", () => {
count++;
render();
});
document.querySelector("#dec").addEventListener("click", () => {
count--;
render();
});
document.querySelector("#reset").addEventListener("click", () => {
count = 0;
render();
});
render();
```
### Projekt 2: Todo-Liste (minimal)
`index.html`:
```html
<input id="todo" placeholder="Neues Todo" />
<button id="add">Add</button>
<ul id="list"></ul>
<script defer src="./main.js"></script>
```
`main.js`:
```js
const input = document.querySelector("#todo");
const btn = document.querySelector("#add");
const list = document.querySelector("#list");
btn.addEventListener("click", () => {
const text = input.value.trim();
if (!text) return;
const li = document.createElement("li");
li.textContent = text;
list.appendChild(li);
input.value = "";
input.focus();
});
// Klick zum Entfernen (Delegation)
list.addEventListener("click", (e) => {
if (e.target.matches("li")) e.target.remove();
});
```
---
## 17) Tooling: npm, Vite, Linting (kurz)
Wenn du über “nur HTML+JS” hinaus willst (Module, Bundling, Dev-Server):
### Vite Setup
```bash
npm create vite@latest my-app
cd my-app
npm install
npm run dev
```
Das erstellt ein modernes Dev-Setup mit Hot Reload.
### Linting (optional)
- ESLint hilft, typische Fehler früh zu finden.
- Prettier formatiert Code automatisch.
---
## 18) Cheatsheet: Python vs. JavaScript
### Datenstrukturen
- Python `list` ≈ JS `Array`
- Python `dict` ≈ JS `Object` oder `Map`
- Python `None` ≈ JS `null` (oder `undefined` je nach Kontext)
### Funktionen
- Python: `def f(a=1): ...`
- JS: `function f(a = 1) { ... }` oder `(a = 1) => ...`
### Strings
- Python: `f"{x}"`
- JS: `` `${x}` ``
### Imports
- Python: `import x`
- JS (ESM): `import x from "./x.js"` / `import {a} from ...`
### Iteration
- Python: `for x in xs:`
- JS: `for (const x of xs) { ... }`
### Async
- Python: `async def`, `await`
- JS: `async function`, `await` (sehr ähnlich im Feeling, andere Runtime-Details)
---
## Nächste Schritte (Empfehlung)
1. Baue die Mini-Projekte nach und verändere sie (z. B. Todo: “erledigt” toggle statt löschen).
2. Übe `map/filter/reduce` auf Arrays mit echten Daten (z. B. aus `fetch`).
3. Wenn du Web-Apps willst: lerne danach ein Framework (React/Vue/Svelte) aber erst, wenn DOM + async sitzen.
---
## Offene Fragen (damit ich das Tutorial besser anpassen kann)
- Willst du primär **Frontend im Browser** lernen oder auch **Node.js Backend**?
- Arbeitest du lieber mit **Vanilla JS** (ohne Framework) oder willst du schnell Richtung **React/Vue**?
```
Wenn du willst, kann ich daraus auch mehrere Obsidian-Notizen machen (z. B. „JS Basics“, „DOM“, „Async“, „Mini-Projekte“) und dir eine sinnvolle Link-Struktur (MOC) anlegen.
@@ -0,0 +1,6 @@
Anbei ist eine Notiz zu ==\<Thema\>==.
Bitte prüfe dieses Dokument:
* Korrigiere Fehler
* Ergänzen fehlende Infos
* Stelle sicher, dass das Dokument gut lesbar ist und wesentliche Infos schnell erfasst werden können
* Lege Links zu wichtigen Themen an, die z.B von Obsidian als solche erkannt werden (Bsp. "bla bla [[wichtiges Thema]] bla")(diese kann ich dann bei Gelegenheit später mit Inhalt füllen)
+1
View File
@@ -0,0 +1 @@
https://www.librechat.ai/
@@ -0,0 +1,164 @@
Unten eine vollständige, schrittweise Anleitung (auf Deutsch), wie du eine AppImage unter /opt ablegst, ins Startmenü einbindest und optional ein Icon extrahierst. Ich gebe dir Beispielbefehle — ersetze die Platzhalter durch den echten Dateinamen/deine App-Namen.
Voraussetzungen
- Du brauchst sudo-Rechte.
- AppImage-Datei (z. B. ExampleApp.AppImage) ist im Downloads-Ordner.
Schritt 1 — AppImage ausführbar machen
Öffne ein Terminal und mache die Datei ausführbar:
```
cd ~/Downloads
chmod +x ExampleApp.AppImage
```
Schritt 2 — AppImage nach /opt verschieben
Erstelle ein Unterverzeichnis unter /opt (z. B. /opt/exampleapp) und verschiebe die AppImage dort hin:
```
sudo mkdir -p /opt/exampleapp
sudo mv ExampleApp.AppImage /opt/exampleapp/
sudo chown -R root:root /opt/exampleapp
```
Optional: Um den Namen konsistent zu halten, kannst du die Datei umbenennen:
```
sudo mv /opt/exampleapp/ExampleApp.AppImage /opt/exampleapp/exampleapp.AppImage
```
Schritt 3 — Einfachen Startbefehl anlegen (Symlink oder Wrapper)
Damit die App systemweit mit kurzem Namen startet, lege einen Symlink oder ein kleines Wrapper-Skript in /usr/local/bin an.
Variante A — Symlink:
```
sudo ln -s /opt/exampleapp/exampleapp.AppImage /usr/local/bin/exampleapp
sudo chmod +x /usr/local/bin/exampleapp
```
Variante B — Wrapper-Skript (empfohlen, falls Argumente weitergeleitet werden sollen):
```
sudo tee /usr/local/bin/exampleapp > /dev/null <<'EOF'
#!/bin/sh
exec /opt/exampleapp/exampleapp.AppImage "$@"
EOF
sudo chmod +x /usr/local/bin/exampleapp
```
Schritt 4 — Icon aus dem AppImage extrahieren (optional, aber empfohlen)
Viele AppImages haben ein eingebettetes Icon (.DirIcon) oder eine .png-Datei. So extrahierst du es:
```
cd /tmp
/opt/exampleapp/exampleapp.AppImage --appimage-extract
# die extrahierten Dateien liegen jetzt in /tmp/squashfs-root
```
Suche das Icon:
```
ls squashfs-root | grep -i DirIcon || ls squashfs-root | grep -i png
```
Beispiel: wenn squashfs-root/.DirIcon vorhanden ist, kopiere es als PNG in die Icon-Hierarchie:
```
sudo mkdir -p /usr/share/icons/hicolor/256x256/apps
sudo cp squashfs-root/.DirIcon /usr/share/icons/hicolor/256x256/apps/exampleapp.png
sudo chmod 644 /usr/share/icons/hicolor/256x256/apps/exampleapp.png
```
(Optional) Icon-Cache aktualisieren:
```
sudo gtk-update-icon-cache /usr/share/icons/hicolor
```
Aufräumen:
```
rm -rf /tmp/squashfs-root
```
Hinweis: Wenn du die App nur für deinen Benutzer installierst, kopiere das Icon nach ~/.local/share/icons/hicolor/256x256/apps/ statt /usr/share/...
Schritt 5 — .desktop-Datei anlegen (Startmenü-Eintrag)
Siehe auch hier: [[Linux .desktop Dateien]]
Systemweit (für alle Benutzer):
```
sudo tee /usr/share/applications/exampleapp.desktop > /dev/null <<'EOF'
[Desktop Entry]
Name=ExampleApp
GenericName=Example Application
Comment=Beschreibung der Anwendung
Exec=/usr/local/bin/exampleapp %U
Icon=exampleapp
Terminal=false
Type=Application
Categories=Utility;Application;
StartupWMClass=ExampleApp
EOF
```
Alternativ für nur deinen Benutzer:
```
mkdir -p ~/.local/share/applications
tee ~/.local/share/applications/exampleapp.desktop > /dev/null <<'EOF'
[Desktop Entry]
Name=ExampleApp
GenericName=Example Application
Comment=Beschreibung der Anwendung
Exec=/usr/local/bin/exampleapp %U
Icon=/home/deinuser/.local/share/icons/hicolor/256x256/apps/exampleapp.png
Terminal=false
Type=Application
Categories=Utility;Application;
StartupWMClass=ExampleApp
EOF
```
Wichtige Felder:
- Exec: Pfad zur ausführbaren Datei oder zu deinem Symlink (/usr/local/bin/exampleapp). %U erlaubt URLs/Dateien als Argumente.
- Icon: entweder der einfache Icon-Name (ohne Endung), wenn du das Icon in /usr/share/icons/hicolor abgelegt hast, oder ein voller Pfad.
- Categories: für die Kategorisierung im Menü (z. B. Utility, Development, Office).
- Terminal=false, falls kein Terminal nötig.
Setze die richtigen Rechte:
```
sudo chmod 644 /usr/share/applications/exampleapp.desktop
# oder für user:
chmod 644 ~/.local/share/applications/exampleapp.desktop
```
Schritt 6 — Desktop-Datenbank aktualisieren (falls nötig)
Für Systemmenüs:
```
sudo update-desktop-database
```
Für GNOME/andere DEs: in der Regel reicht Aus- und Einloggen oder Neustart des Shells/Session.
Schritt 7 — Testen
- Öffne dein Startmenü / Activities und suche nach "ExampleApp".
- Alternativ im Terminal: `exampleapp` (oder `/opt/exampleapp/exampleapp.AppImage`).
Optionale Hinweise
- Automatische Updates: Manche AppImages unterstützen AppImageUpdate (z. B. mit zsync) oder du kannst AppImageLauncher verwenden, das AppImage-Integration & Updates verwaltet.
- Sicherheitsaspekt: AppImages laufen nicht automatisch in einem Sandbox; für zusätzliche Isolation kannst du firejail verwenden.
- Entfernen: Entferne /opt/exampleapp, den Symlink und die .desktop/Icons, um die App rückstandsfrei zu löschen.
Kurzbeispiel (kompakt)
Angenommen Datei heißt ExampleApp.AppImage in ~/Downloads und dein Benutzername ist user:
```
cd ~/Downloads
chmod +x ExampleApp.AppImage
sudo mkdir -p /opt/exampleapp
sudo mv ExampleApp.AppImage /opt/exampleapp/exampleapp.AppImage
sudo ln -s /opt/exampleapp/exampleapp.AppImage /usr/local/bin/exampleapp
# Icon extrahieren (falls vorhanden)
/opt/exampleapp/exampleapp.AppImage --appimage-extract
sudo cp squashfs-root/.DirIcon /usr/share/icons/hicolor/256x256/apps/exampleapp.png
rm -rf squashfs-root
# .desktop anlegen
sudo tee /usr/share/applications/exampleapp.desktop > /dev/null <<'EOF'
[Desktop Entry]
Name=ExampleApp
Exec=/usr/local/bin/exampleapp %U
Icon=exampleapp
Terminal=false
Type=Application
Categories=Utility;
EOF
sudo chmod 644 /usr/share/applications/exampleapp.desktop
sudo update-desktop-database
```
Wenn du willst, schreibe mir:
- Wie die AppImage-Datei heißt, und
- ob du die Installation systemweit (für alle Benutzer) oder nur für dich wünschst.
Dann passe ich die Befehle genau für deine App an.
@@ -0,0 +1,40 @@
# BASH Basics - Übersicht
Sammlung wichtiger BASH-Befehle und Konzepte für die Linux-Konsole.
## Grundlegende Konzepte
- [[BASH Funktionen]] - Wiederverwendbare Funktionen erstellen
## Dateiverwaltung
- [[ls]] - Dateien auflisten und Größen anzeigen
- [[find]] - Dateien suchen, filtern und verarbeiten (inkl. Datum, Löschen)
- [[Symlinks]] - Symbolische Links erstellen und verwalten
## Textverarbeitung
- [[grep]] - Textsuche in Dateien
- [[sed]] - Stream-Editor für Textmanipulation
- [[awk]] - Datenextraktion und Spaltenverarbeitung
## Berechtigungen
- [[Dateiberechtigungen]] - chmod und chown (Rechte, Eigentümer, Gruppen)
## Archive und Backup
- [[tar]] - Archive erstellen/entpacken und Software installieren
- [[rsync]] - Dateien synchronisieren
## System
- [[lsblk]] - Block-Geräte anzeigen
- [[fstab Credentials]] - Zugangsdaten sicher in fstab speichern
## Verwandte Themen
Weitere Linux-Themen im übergeordneten Verzeichnis:
- [[Linux]] - Allgemeine Linux-Dokumentation
- [[SSH Verbindung in Linux]] - SSH-Verbindungen
- [[Navidrome]] - Musik-Server
@@ -0,0 +1,693 @@
# BASH Funktionen# BASH FunktionenIn **[[Bash]]** kannst du wiederverwendbare **Funktionen** definieren, um Code übersichtlicher und modularer zu gestalten.
In BASH kannst du wiederverwendbare Funktionen definieren, um Code übersichtlicher und modularer zu gestalten.Hier ist eine kurze Einführung mit Beispielen 👇
## GrundsyntaxIn BASH kannst du wiederverwendbare Funktionen definieren, um Code übersichtlicher und modularer zu gestalten.
```bash---
meine_funktion() {
echo "Das ist eine wiederverwendbare Funktion!"## Grundsyntax
}
```### 🔹 **Grundsyntax einer Funktion**
Alternative Syntax (weniger üblich):```bash
```bashmeine_funktion() {```bash
function meine_funktion {
echo "Das ist eine wiederverwendbare Funktion!" echo "Das ist eine wiederverwendbare Funktion!"meine_funktion() {
}
```} echo "Das ist eine wiederverwendbare Funktion!"
## Funktion mit Parametern```}
In BASH werden Argumente positional übergeben: `$1`, `$2`, usw.```
```bashAlternative Syntax (weniger üblich):
begruesse() {
echo "Hallo $1!"Oder alternativ (weniger üblich, aber erlaubt):
}
```bash
begruesse "Anna"
# Ausgabe: Hallo Anna!function meine_funktion {```bash
```
echo "Das ist eine wiederverwendbare Funktion!"function meine_funktion {
## Rückgabewerte
} echo "Das ist eine wiederverwendbare Funktion!"
### Numerischer Exit-Code
```}
Eine Funktion kann mit `return` einen numerischen Exit-Code (0255) zurückgeben:
```
```bash
teste_zahl() {## Funktion mit Parametern
if (( $1 > 10 )); then
return 0 # Erfolg---
else
return 1 # FehlerIn BASH werden Argumente positional übergeben: `$1`, `$2`, usw.
fi
}### 🔹 **Funktion mit Parametern**
if teste_zahl 15; then```bash
echo "Größer als 10"
elsebegruesse() {In Bash werden Argumente **positional** übergeben — also `$1`, `$2`, usw.
echo "Nicht größer als 10"
fi echo "Hallo $1!"
```
}```bash
### Text zurückgeben
begruesse() {
Um Text zurückzugeben, verwende `echo` oder `printf` und Command Substitution:
begruesse "Anna" echo "Hallo $1!"
```bash
addiere() {# Ausgabe: Hallo Anna!}
echo $(( $1 + $2 ))
}```
summe=$(addiere 3 5)begruesse "Anna"
echo "Summe: $summe" # Ausgabe: Summe: 8
```## Rückgabewerte# Ausgabe: Hallo Anna!
## Funktionen wiederverwendbar machen```
Speichere Funktionen in einer separaten Datei und lade sie mit `source`:### Numerischer Exit-Code
**funktionen.sh:**---
```bash
#!/bin/bashEine Funktion kann mit `return` einen numerischen Exit-Code (0255) zurückgeben:
begruesse() {
echo "Hallo $1!"### 🔹 **Rückgabewerte**
}
``````bash
**hauptskript.sh:**teste_zahl() {- Eine Funktion kann mit `return` einen **numerischen Exit-Code** (0255) zurückgeben.
```bash
#!/bin/bash if (( $1 > 10 )); then
source ./funktionen.sh
return 0 # Erfolg- Um Text zurückzugeben, verwendest du **`echo`** oder **`printf`** und fängst den Wert mit **Command Substitution** ein.
begruesse "Welt"
``` else
Alternative: `. ./funktionen.sh` return 1 # Fehler
## Lokale Variablen fi```bash
Verwende `local`, um Variablen nur innerhalb der Funktion sichtbar zu machen:}# numerischer Rückgabewert
```bashteste_zahl() {
addiere() {
local summe=$(( $1 + $2 ))if teste_zahl 15; then if (( $1 > 10 )); then
echo "$summe"
} echo "Größer als 10" return 0 # Erfolg
```
else else
## Default-Werte für Parameter
echo "Nicht größer als 10" return 1 # Fehler
```bash
mein_script() {fi fi
local name="${1:-Welt}" # Standardwert 'Welt'
local sprache="${2:-de}" # Standardwert 'de'```}
echo "Name: $name, Sprache: $sprache"
}
### Text zurückgebenif teste_zahl 15; then
mein_script "Anna" "en" # Name: Anna, Sprache: en
mein_script "Bob" # Name: Bob, Sprache: de echo "Größer als 10"
```
Um Text zurückzugeben, verwende `echo` oder `printf` und Command Substitution:else
## Benannte Argumente simulieren
echo "Nicht größer als 10"
### Mit case und Schleife
```bashfi
```bash
begruesse() {addiere() {```
local name="Welt"
local sprache="de" echo $(( $1 + $2 ))
for arg in "$@"; do}```bash
case $arg in
--name=*)# Text zurückgeben
name="${arg#*=}"
;;summe=$(addiere 3 5)addiere() {
--sprache=*|--lang=*)
sprache="${arg#*=}"echo "Summe: $summe" # Ausgabe: Summe: 8 echo $(( $1 + $2 ))
;;
*)```}
echo "Unbekannte Option: $arg" >&2
;;
esac
done## Funktionen wiederverwendbar machensumme=$(addiere 3 5)
echo "Hallo $name! (Sprache: $sprache)"echo "Summe: $summe"
}
Speichere Funktionen in einer separaten Datei und lade sie mit `source`:# Ausgabe: Summe: 8
begruesse --name=Anna --sprache=en
``````
**Vorteile:****funktionen.sh:**
- Reihenfolge der Argumente ist egal
- Default-Werte bleiben bestehen```bash---
- Sehr gut lesbar
#!/bin/bash
### Mit assoziativem Array
begruesse() {### 🔹 **Wiederverwendbar machen**
```bash
begruesse() { echo "Hallo $1!"
declare -A args=(
[name]="Welt"}Speichere deine Funktionen in einer separaten Datei, z. B. `funktionen.sh`, und **sourcen** sie in anderen Skripten:
[sprache]="de"
)```
for arg in "$@"; do**funktionen.sh**
[[ $arg == *=* ]] || continue
key="${arg%%=*}"**hauptskript.sh:**
val="${arg#*=}"
args[$key]="$val"```bash```bash
done
#!/bin/bash#!/bin/bash
echo "Hallo ${args[name]}! (Sprache: ${args[sprache]})"
}source ./funktionen.shbegruesse() {
begruesse name=Anna sprache=en echo "Hallo $1!"
```
begruesse "Welt"}
## Praktische Beispiele
``````
### Backup-Funktion
```bash
backup_datei() {Alternative: `. ./funktionen.sh`**hauptskript.sh**
local datei="$1"
local backup="${datei}.backup-$(date +%Y%m%d)"
if [[ -f "$datei" ]]; then## Lokale Variablen```bash
cp "$datei" "$backup"
echo "Backup erstellt: $backup"#!/bin/bash
else
echo "Fehler: $datei nicht gefunden" >&2Verwende `local`, um Variablen nur innerhalb der Funktion sichtbar zu machen:source ./funktionen.sh
return 1
fi
}
```bashbegruesse "Welt"
backup_datei wichtig.txt
```addiere() {```
### Fehlerbehandlung local summe=$(( $1 + $2 ))
```bash echo "$summe"Oder mit:
sicheres_loeschen() {
local datei="$1"}
if [[ ! -f "$datei" ]]; then``````bash
echo "Fehler: $datei existiert nicht" >&2
return 1. ./funktionen.sh
fi
## Default-Werte für Parameter```
read -p "Wirklich $datei löschen? (j/n) " antwort
if [[ "$antwort" == "j" ]]; then
rm "$datei"
echo "$datei gelöscht"```bash---
else
echo "Abgebrochen"mein_script() {
fi
} local name="${1:-Welt}" # Standardwert 'Welt'### 🔹 **Bonus: Funktionen mit lokaler Variable**
```
local sprache="${2:-de}" # Standardwert 'de'
### Mehrere Rückgabewerte
Verwende `local`, um Variablen nur innerhalb der Funktion sichtbar zu machen:
```bash
datei_info() { echo "Name: $name, Sprache: $sprache"
local datei="$1"
}```bash
if [[ -f "$datei" ]]; then
echo "$(wc -l < "$datei")" # Zeilenaddiere() {
echo "$(wc -w < "$datei")" # Wörter
echo "$(stat -c%s "$datei")" # Größemein_script "Anna" "en" # Name: Anna, Sprache: en local summe=$(( $1 + $2 ))
fi
}mein_script "Bob" # Name: Bob, Sprache: de echo "$summe"
# Verwendung```}
read zeilen woerter groesse <<< $(datei_info text.txt)
echo "Zeilen: $zeilen, Wörter: $woerter, Größe: $groesse"```
```
## Benannte Argumente simulieren
## Best Practices
---
### Eingabevalidierung
### Mit case und Schleife
```bash
verarbeite_zahl() {## 🧩 Beispiel 1: Named Arguments via `local` + Parameter Expansion
local zahl="$1"
```bash
if ! [[ "$zahl" =~ ^[0-9]+$ ]]; then
echo "Fehler: Keine gültige Zahl" >&2begruesse() {```bash
return 1
fi local name="Welt"mein_script() {
echo "Ergebnis: $((zahl * 2))" local sprache="de" local name="${1:-Welt}" # Standardwert 'Welt'
}
``` local sprache="${2:-de}" # Standardwert 'de'
### Dokumentation for arg in "$@"; do
```bash case $arg in echo "Name: $name"
# Berechnet die Summe zweier Zahlen
# Parameter: --name=*) echo "Sprache: $sprache"
# $1 - erste Zahl
# $2 - zweite Zahl name="${arg#*=}"}
# Rückgabe:
# Summe der beiden Zahlen ;;
addiere() {
echo $(( $1 + $2 )) --sprache=*|--lang=*)mein_script "Anna" "en"
}
``` sprache="${arg#*=}"mein_script "Bob"
### Fehler propagieren ;;```
```bash *)
hauptfunktion() {
hilfsfunktion || return $? echo "Unbekannte Option: $arg" >&2➡️ Ausgabe:
# Weiterer Code nur wenn hilfsfunktion erfolgreich
} ;;
```
esac```
## Siehe auch
doneName: Anna
- [[grep]] - Textsuche in Scripten
- [[sed]] - Textmanipulation in FunktionenSprache: en
- [[find]] - Dateien in Funktionen verarbeiten
echo "Hallo $name! (Sprache: $sprache)"Name: Bob
}Sprache: de
```
begruesse --name=Anna --sprache=en
```Aber das sind **positionsbasierte Argumente**, keine echten "benannten".
**Vorteile:**---
- Reihenfolge der Argumente ist egal
- Default-Werte bleiben bestehen## 🧩 Beispiel 2: Simulierte **benannte Argumente** mit `case` oder Schleife
- Sehr gut lesbar
Du kannst Argumente wie `--name=Anna` oder `--lang=en` verwenden:
### Mit assoziativem Array
```bash
```bashbegruesse() {
begruesse() { local name="Welt"
declare -A args=( local sprache="de"
[name]="Welt"
[sprache]="de" for arg in "$@"; do
) case $arg in
--name=*)
for arg in "$@"; do name="${arg#*=}"
[[ $arg == *=* ]] || continue ;;
key="${arg%%=*}" --sprache=*|--lang=*)
val="${arg#*=}" sprache="${arg#*=}"
args[$key]="$val" ;;
done *)
echo "Unbekannte Option: $arg" >&2
echo "Hallo ${args[name]}! (Sprache: ${args[sprache]})" ;;
} esac
done
begruesse name=Anna sprache=en
``` echo "Hallo $name! (Sprache: $sprache)"
}
## Siehe auch
begruesse --name=Anna --sprache=en
- [[find]] - BASH-Befehl zum Suchen von Dateienbegruesse
- [[grep]] - Textsuche in Dateien```
➡️ Ausgabe:
```
Hallo Anna! (Sprache: en)
Hallo Welt! (Sprache: de)
```
✅ Vorteil: Reihenfolge der Argumente ist egal
✅ Default-Werte bleiben bestehen
✅ Sehr gut lesbar
---
## 🧩 Beispiel 3: Named Args via **`declare -A` (assoziatives Array)**
Etwas fortgeschrittener, aber elegant:
```bash
begruesse() {
declare -A args=(
[name]="Welt"
[sprache]="de"
)
for arg in "$@"; do
[[ $arg == *=* ]] || continue
key="${arg%%=*}"
val="${arg#*=}"
args[$key]="$val"
done
echo "Hallo ${args[name]}! (Sprache: ${args[sprache]})"
}
begruesse name=Anna sprache=en
```
---
## 🧩 Beispiel 4: Default-Werte per `:`-Operator
Falls du Parameter ohne Parsing willst, kannst du Default-Werte einfach so setzen:
```bash
begruesse() {
local name="${1:-Welt}"
local sprache="${2:-de}"
echo "Hallo $name in Sprache $sprache"
}
```
---
### 🔹 Empfehlung
Wenn du Funktionen **häufig wiederverwenden** oder **CLI-ähnliche Aufrufe** unterstützen willst, ist **Variante 2 (mit `--option=wert`)** am besten:
- Lesbar
- Robust
- Einfach erweiterbar
---
@@ -0,0 +1,365 @@
# Dateiberechtigungen - chmod und chown
Verwaltung von Zugriffsrechten, Eigentümern und Gruppen in Linux.
## Rechte-System in Linux
Jede Datei hat:
- **Eigentümer (Owner)** - der Benutzer, dem die Datei gehört
- **Gruppe (Group)** - eine Benutzergruppe
- **Zugriffsrechte** für drei Bereiche:
- **u** (user) = Eigentümer
- **g** (group) = Gruppe
- **o** (others) = Andere
Jeder Bereich hat drei Rechte:
- **r** (read) = Lesen (4)
- **w** (write) = Schreiben (2)
- **x** (execute) = Ausführen (1)
## Rechte anzeigen
```bash
ls -l datei.txt
```
Ausgabe:
```
-rw-r--r-- 1 alice developers 1234 Nov 7 10:00 datei.txt
```
- Position 1: Dateityp (`-` = Datei, `d` = Verzeichnis, `l` = Link)
- Position 2-4: User-Rechte (`rw-`)
- Position 5-7: Group-Rechte (`r--`)
- Position 8-10: Other-Rechte (`r--`)
- `alice` = Eigentümer
- `developers` = Gruppe
## chmod - Zugriffsrechte ändern
### Symbolische Notation
```bash
chmod [ugoa][+-=][rwx] datei
```
**Rechte hinzufügen:**
```bash
chmod u+x script.sh # Eigentümer: ausführbar
chmod g+w datei.txt # Gruppe: schreibbar
chmod o+r datei.txt # Andere: lesbar
chmod a+x script.sh # Alle: ausführbar
```
**Rechte entfernen:**
```bash
chmod u-x script.sh # Eigentümer: nicht ausführbar
chmod g-w datei.txt # Gruppe: nicht schreibbar
chmod o-r datei.txt # Andere: nicht lesbar
```
**Rechte setzen (überschreiben):**
```bash
chmod u=rw,g=r,o= datei.txt # User: rw, Group: r, Others: keine
chmod a=r datei.txt # Alle: nur lesen
```
### Numerische Notation (Oktal)
Rechte als dreistellige Oktalzahl:
| Wert | Rechte | Bedeutung |
|------|--------|-----------|
| 0 | `---` | Keine Rechte |
| 1 | `--x` | Ausführen |
| 2 | `-w-` | Schreiben |
| 3 | `-wx` | Schreiben + Ausführen |
| 4 | `r--` | Lesen |
| 5 | `r-x` | Lesen + Ausführen |
| 6 | `rw-` | Lesen + Schreiben |
| 7 | `rwx` | Alle Rechte |
**Häufige Kombinationen:**
```bash
chmod 644 datei.txt # rw-r--r-- (Standard für Dateien)
chmod 755 script.sh # rwxr-xr-x (Standard für Scripts)
chmod 700 privat.key # rwx------ (Nur Eigentümer)
chmod 600 ~/.ssh/id_rsa # rw------- (SSH-Schlüssel)
chmod 777 verzeichnis # rwxrwxrwx (Alle Rechte - UNSICHER!)
```
Beispiel: `chmod 755` bedeutet:
- User: 7 (rwx)
- Group: 5 (r-x)
- Others: 5 (r-x)
### Rekursiv
```bash
chmod -R 755 /pfad/zum/verzeichnis
```
**Nur Verzeichnisse oder nur Dateien:**
```bash
find . -type d -exec chmod 755 {} + # Alle Verzeichnisse
find . -type f -exec chmod 644 {} + # Alle Dateien
```
### Spezielle Rechte
**Sticky Bit** (nur Eigentümer kann löschen):
```bash
chmod +t /tmp # Symbolic
chmod 1777 verzeichnis # Numeric (rwxrwxrwt)
```
**SUID** (läuft mit Rechten des Eigentümers):
```bash
chmod u+s /usr/bin/passwd # Symbolic
chmod 4755 datei # Numeric (rwsr-xr-x)
```
**SGID** (neue Dateien erben Gruppe):
```bash
chmod g+s verzeichnis # Symbolic
chmod 2755 verzeichnis # Numeric (rwxr-sr-x)
```
### Praktische Beispiele
**Script ausführbar machen:**
```bash
chmod +x meinscript.sh
./meinscript.sh
```
**SSH-Verzeichnis absichern:**
```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 600 ~/.ssh/authorized_keys
```
**Web-Verzeichnis:**
```bash
chmod -R 755 /var/www/html
find /var/www/html -type f -exec chmod 644 {} +
find /var/www/html -type d -exec chmod 755 {} +
```
**Projekt-Verzeichnis:**
```bash
chmod -R u+rwX,g+rX,o-rwx projektordner
```
(`X` = ausführbar nur für Verzeichnisse)
## chown - Eigentümer und Gruppe ändern
### Grundsyntax
```bash
chown [OPTIONEN] EIGENTÜMER[:GRUPPE] DATEI
```
### Eigentümer ändern
```bash
chown alice datei.txt
```
### Eigentümer und Gruppe ändern
```bash
chown alice:developers datei.txt
```
### Nur Gruppe ändern
```bash
chown :developers datei.txt
```
Oder mit `chgrp`:
```bash
chgrp developers datei.txt
```
### Rekursiv
```bash
chown -R alice:developers /pfad/zum/verzeichnis
```
### Von anderem Benutzer übernehmen
```bash
chown --reference=referenzdatei zieldatei
```
### Praktische Beispiele
**Web-Server Verzeichnis:**
```bash
sudo chown -R www-data:www-data /var/www/html
```
**Home-Verzeichnis korrigieren:**
```bash
sudo chown -R alice:alice /home/alice
```
**Nach Copy von Root:**
```bash
sudo cp /root/datei.txt /home/alice/
sudo chown alice:alice /home/alice/datei.txt
```
**Nur Dateien, nicht Verzeichnisse:**
```bash
find /pfad -type f -exec chown alice:developers {} +
```
**Nur bei Bedarf ändern:**
```bash
find /pfad ! -user alice -exec chown alice {} +
find /pfad ! -group developers -exec chgrp developers {} +
```
### Symbolische Links
Standardmäßig ändert `chown` das Ziel des Links:
```bash
chown alice symlink # ändert Ziel
chown -h alice symlink # ändert nur den Link selbst
```
## Kombinierte Anwendung
### Berechtigungen komplett setzen
```bash
sudo chown -R www-data:www-data /var/www/html
sudo find /var/www/html -type d -exec chmod 755 {} +
sudo find /var/www/html -type f -exec chmod 644 {} +
```
### Projekt-Setup
```bash
sudo chown -R alice:developers /opt/projekt
chmod -R u+rwX,g+rwX,o-rwx /opt/projekt
```
### Backup wiederherstellen
```bash
sudo tar -xpf backup.tar.gz # -p bewahrt Rechte
sudo chown -R alice:alice /home/alice/restored/
```
## Berechtigungen prüfen
```bash
ls -l datei.txt # Einfache Ansicht
stat datei.txt # Detaillierte Info
getfacl datei.txt # ACLs anzeigen (falls gesetzt)
```
## Eigentümer-ID statt Name
```bash
chown 1000:1000 datei.txt # Verwendet UID und GID direkt
```
UIDs anzeigen:
```bash
id alice # UID und GIDs von alice
```
## Fehler vermeiden
### Rekursive Änderungen testen
```bash
# Erst anzeigen
find /pfad -ls
# Dann ändern
sudo chown -R alice:developers /pfad
```
### NIEMALS auf Root-Verzeichnis
```bash
# GEFÄHRLICH - bricht System
sudo chown -R user:user / # NIEMALS!
sudo chmod -R 777 / # NIEMALS!
# Nur eigene Verzeichnisse
sudo chown -R user:user /home/user
```
### Zu permissive Rechte
```bash
# FALSCH - macht alles ausführbar
chmod -R 777 verzeichnis # NICHT verwenden!
# RICHTIG - differenziert
find verzeichnis -type d -exec chmod 755 {} +
find verzeichnis -type f -exec chmod 644 {} +
```
### Systemdateien
```bash
# Wichtige Systemdateien sollten root gehören
ls -l /etc/passwd /etc/shadow
# -rw-r--r-- 1 root root ... /etc/passwd
# -rw-r----- 1 root shadow ... /etc/shadow
```
## Mit sudo
`chown` erfordert meist Root-Rechte:
```bash
sudo chown root:root /etc/wichtig.conf
sudo chmod 644 /etc/wichtig.conf
```
Ohne sudo:
```bash
# Nur eigene Dateien
chmod 644 meine_datei.txt
# chown nur als root
chown alice datei.txt # Permission denied (außer eigene Datei)
```
## Zusammenfassung
| Befehl | Zweck | Beispiel |
|--------|-------|----------|
| `chmod` | Rechte ändern | `chmod 755 script.sh` |
| `chown` | Eigentümer ändern | `chown alice:developers file` |
| `chgrp` | Nur Gruppe ändern | `chgrp developers file` |
| `ls -l` | Rechte anzeigen | `ls -l file` |
| `stat` | Details anzeigen | `stat file` |
**Standard-Rechte:**
- Dateien: `644` (rw-r--r--)
- Scripts: `755` (rwxr-xr-x)
- Verzeichnisse: `755` (rwxr-xr-x)
- Private Dateien: `600` (rw-------)
## Siehe auch
- [[find]] - Dateien mit bestimmten Rechten/Eigentümern finden
- [[ls]] - Rechte und Eigentümer anzeigen
- [[Symlinks]] - Links bleiben bei chown erhalten
- [[tar]] - Rechte in Archiven bewahren
- [[rsync]] - Rechte bei Synchronisation
@@ -0,0 +1,115 @@
# Linux BASH: Permanente Verfügbarkeit von Dateien und Pfaden
Es gibt mehrere Methoden, um Dateien oder Pfade in Linux BASH permanent verfügbar zu machen:
## PATH-Variable erweitern
### Temporär (aktuelle Session)
```bash
export PATH="$PATH:/pfad/zum/verzeichnis"
```
### Permanent für aktuellen Benutzer
Füge folgende Zeile in `~/.bashrc` oder `~/.profile` ein:
```bash
export PATH="$PATH:/pfad/zum/verzeichnis"
```
### Permanent systemweit
Bearbeite `/etc/environment`:
```bash
sudo nano /etc/environment
```
Erweitere die PATH-Zeile:
```
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/dein/pfad"
```
## Symbolische Links erstellen
### Link in systemweitem Bin-Verzeichnis
```bash
sudo ln -s /vollständiger/pfad/zur/datei /usr/local/bin/dateiname
```
### Link in persönlichem Bin-Verzeichnis
```bash
mkdir -p ~/bin
ln -s /vollständiger/pfad/zur/datei ~/bin/dateiname
# ~/bin zu PATH hinzufügen falls nicht vorhanden
echo 'export PATH="$PATH:$HOME/bin"' >> ~/.bashrc
```
## Aliase verwenden
### In ~/.bashrc hinzufügen
```bash
alias meinprogramm='/vollständiger/pfad/zur/datei'
alias cdprojekt='cd /pfad/zum/projekt'
```
## Umgebungsvariablen für Pfade
### In ~/.bashrc definieren
```bash
export MEIN_PROJEKT_PFAD="/pfad/zum/projekt"
export MEIN_SCRIPT_PFAD="/pfad/zu/scripts"
```
Verwendung:
```bash
cd $MEIN_PROJEKT_PFAD
$MEIN_SCRIPT_PFAD/meinscript.sh
```
## Anwendung der Änderungen
Nach Bearbeitung der Konfigurationsdateien:
```bash
source ~/.bashrc
# oder
exec bash
# oder Terminal neu starten
```
## Praxisbeispiele
### Eigene Scripts verfügbar machen
```bash
# 1. Persönliches Scripts-Verzeichnis erstellen
mkdir -p ~/scripts
# 2. Script dort ablegen
cp meinscript.sh ~/scripts/
# 3. Ausführbar machen
chmod +x ~/scripts/meinscript.sh
# 4. PATH erweitern in ~/.bashrc
echo 'export PATH="$PATH:$HOME/scripts"' >> ~/.bashrc
# 5. Änderungen laden
source ~/.bashrc
```
### Häufig verwendete Verzeichnisse
```bash
# In ~/.bashrc
alias proj='cd /home/user/projekte'
alias docs='cd /home/user/dokumente'
export WORKSPACE="/home/user/workspace"
```
## Wichtige Hinweise
- **Reihenfolge im PATH**: Erste Treffer werden verwendet
- **Sicherheit**: Keine unsicheren Verzeichnisse in PATH aufnehmen
- **Systemweite vs. Benutzer-spezifische** Änderungen beachten
- **Backup**: Konfigurationsdateien vor Änderungen sichern
---
**Verwandte Themen:**
- [[Linux Shell Konfiguration]]
- [[BASH Umgebungsvariablen]]
- [[Linux Dateisystem Navigation]]
+107
View File
@@ -0,0 +1,107 @@
# Symbolische Links (Symlinks)
Ein symbolischer Link (Symlink) ist eine spezielle Datei, die auf eine andere Datei oder ein Verzeichnis verweist.
## Symlink erstellen
```bash
ln -s /pfad/zum/ziel /pfad/zum/link
```
Optionen:
- `-s` → Symlink erstellen (statt Hardlink)
- `-f` → vorhandenen Link überschreiben
- `-n` → falls Link auf Verzeichnis verweist, Link selbst überschreiben
Beispiel:
```bash
ln -s /opt/programm/binary /usr/local/bin/programm
```
## Ziel eines Symlinks anzeigen
```bash
readlink meinlink
```
Mit absolutem Pfad (löst verschachtelte Links auf):
```bash
readlink -f meinlink
```
Beispiel:
```bash
$ readlink mysoftlink
../zielordner/datei.txt
$ readlink -f mysoftlink
/home/user/zielordner/datei.txt
```
## Symlink aktualisieren
Einen Symlink kann man nicht direkt ändern, sondern muss ihn neu erstellen:
```bash
ln -sfn /neues/ziel meinlink
```
Beispiel:
```bash
#!/bin/bash
link="meinlink"
# Aktuelles Ziel auslesen
altes_ziel=$(readlink "$link")
echo "Aktuelles Ziel: $altes_ziel"
# Neues Ziel setzen
neues_ziel="/pfad/zum/neuen/ziel"
ln -sfn "$neues_ziel" "$link"
echo "Neues Ziel: $(readlink $link)"
```
## Symlinks vs. Hardlinks
**Symlinks:**
- Verweisen auf Pfad (nicht auf Inode)
- Können auf Dateien und Verzeichnisse verweisen
- Funktionieren über Dateisystemgrenzen hinweg
- Brechen, wenn Ziel gelöscht wird
**Hardlinks:**
- Verweisen direkt auf Inode
- Nur für Dateien (nicht für Verzeichnisse)
- Müssen im gleichen Dateisystem liegen
- Bleiben gültig, auch wenn Originaldatei gelöscht wird
## Desktop-Verknüpfungen erstellen
Für Desktop-Umgebungen (GNOME, KDE, XFCE) verwendet man `.desktop`-Dateien:
**weblink.desktop:**
```ini
[Desktop Entry]
Name=Open ChatGPT
Type=Link
URL=https://chat.openai.com/
Icon=web-browser
```
Ausführbar machen:
```bash
chmod +x weblink.desktop
```
## Siehe auch
- [[find]] - Dateien suchen (z.B. nach Symlinks mit `-type l`)
- [[ls]] - Symlinks in Verzeichnissen anzeigen
- [[Dateiberechtigungen]] - Rechte von Links und Zielen
- [[lsblk]] - Block-Geräte anzeigen
+257
View File
@@ -0,0 +1,257 @@
# awk - Textverarbeitung und Datenextraktion
`awk` ist eine mächtige Programmiersprache für Textverarbeitung, besonders nützlich für spaltenbasierte Daten.
## Grundsyntax
```bash
awk 'MUSTER { AKTION }' datei.txt
```
## Spalten ausgeben
### Einzelne Spalten
```bash
awk '{print $1}' datei.txt # Erste Spalte
awk '{print $2}' datei.txt # Zweite Spalte
awk '{print $NF}' datei.txt # Letzte Spalte
```
`$0` = ganze Zeile, `$1` = erste Spalte, `$2` = zweite, etc.
### Mehrere Spalten
```bash
awk '{print $1, $3}' datei.txt
awk '{print $1 " - " $3}' datei.txt
```
## Trennzeichen (Delimiter)
### Standard (Leerzeichen/Tab)
```bash
awk '{print $1}' datei.txt
```
### Eigenes Trennzeichen
```bash
awk -F: '{print $1}' /etc/passwd # Doppelpunkt
awk -F, '{print $1, $3}' datei.csv # Komma
awk -F'|' '{print $2}' datei.txt # Pipe
```
### Mehrere Trennzeichen
```bash
awk -F'[,:]' '{print $1}' datei.txt
```
## Muster (Pattern)
### Zeilen mit bestimmtem Text
```bash
awk '/ERROR/ {print}' logfile.txt
awk '/ERROR/' logfile.txt # Kurzform
```
### Reguläre Ausdrücke
```bash
awk '/^[0-9]/ {print}' datei.txt # Zeilen mit Zahl am Anfang
awk '/ERROR|WARNING/' logfile.txt # ERROR oder WARNING
```
### Spaltenbasierte Bedingungen
```bash
awk '$3 > 100 {print}' datei.txt # 3. Spalte > 100
awk '$1 == "root" {print}' /etc/passwd # 1. Spalte = "root"
awk '$2 != "active" {print}' status.txt # 2. Spalte ≠ "active"
```
### Mehrere Bedingungen
```bash
awk '$3 > 100 && $4 < 200 {print}' datei.txt
awk '$1 == "Alice" || $1 == "Bob" {print}' datei.txt
```
## Berechnungen
### Summe
```bash
awk '{sum += $1} END {print sum}' zahlen.txt
```
### Durchschnitt
```bash
awk '{sum += $1; count++} END {print sum/count}' zahlen.txt
```
### Maximum/Minimum
```bash
awk 'BEGIN {max=0} {if($1>max) max=$1} END {print max}' zahlen.txt
awk 'NR==1 {min=$1} {if($1<min) min=$1} END {print min}' zahlen.txt
```
## Formatierte Ausgabe
### Mit printf
```bash
awk '{printf "%s: %d\n", $1, $2}' datei.txt
awk '{printf "%-10s %5d\n", $1, $2}' datei.txt # Formatiert
```
### Spalten ausrichten
```bash
awk '{printf "%-15s %10s\n", $1, $2}' datei.txt
```
## Eingebaute Variablen
```bash
awk '{print NR, $0}' datei.txt # NR = Zeilennummer
awk '{print NF, $0}' datei.txt # NF = Anzahl Felder
awk 'NR==5 {print}' datei.txt # Nur Zeile 5
awk 'NR>=10 && NR<=20' datei.txt # Zeilen 10-20
```
Wichtige Variablen:
- `NR` = Nummer der aktuellen Zeile
- `NF` = Anzahl der Felder
- `FS` = Field Separator (Eingabe)
- `OFS` = Output Field Separator (Ausgabe)
## BEGIN und END
```bash
awk 'BEGIN {print "Start"} {print} END {print "Ende"}' datei.txt
```
```bash
awk 'BEGIN {FS=":"; OFS="\t"} {print $1, $3}' /etc/passwd
```
## Praktische Beispiele
### /etc/passwd auswerten
```bash
# Alle Benutzernamen
awk -F: '{print $1}' /etc/passwd
# User mit UID >= 1000
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
# User und Shell
awk -F: '{print $1 ": " $7}' /etc/passwd
```
### Prozesse analysieren
```bash
# Speichernutzung
ps aux | awk '{sum += $6} END {print sum/1024 " MB"}'
# Top 5 Prozesse nach Speicher
ps aux | awk '{print $6, $11}' | sort -rn | head -5
```
### CSV-Dateien
```bash
# Zweite Spalte summieren
awk -F, '{sum += $2} END {print sum}' data.csv
# Filtern und ausgeben
awk -F, '$3 > 1000 {print $1, $2}' sales.csv
```
### Logfile-Analyse
```bash
# Nur ERROR-Zeilen mit Zeitstempel
awk '/ERROR/ {print $1, $2, $0}' app.log
# Fehler zählen
awk '/ERROR/ {count++} END {print count}' app.log
# Nach Zeit filtern
awk '$1 >= "2025-11-07" && $1 <= "2025-11-08"' log.txt
```
### Apache/Nginx Logs
```bash
# IP-Adressen extrahieren
awk '{print $1}' access.log | sort | uniq -c | sort -rn
# Nur 404-Fehler
awk '$9 == 404 {print $7}' access.log
```
### Duplikate zählen
```bash
awk '{count[$1]++} END {for(key in count) print key, count[key]}' datei.txt
```
## Arrays
```bash
awk '{arr[$1] += $2} END {for (key in arr) print key, arr[key]}' datei.txt
```
## Mehrere Dateien
```bash
awk '{print FILENAME, $0}' datei1.txt datei2.txt
```
## Mit Pipes
```bash
cat datei.txt | awk '{print $1}'
ls -l | awk '{print $9, $5}'
df -h | awk 'NR>1 {print $1, $5}'
```
## Komplexes Beispiel
```bash
# Benutzerdefinierte Funktion
awk '
function celsius(f) {
return (f - 32) * 5/9
}
{
printf "%s: %.2f°C\n", $1, celsius($2)
}
' temperatures.txt
```
## Vergleich: awk vs. andere Tools
| Task | Tool |
|------|------|
| Spalten extrahieren | `awk '{print $2}'` oder `cut -f2` |
| Suchen | `awk '/pattern/'` oder `grep pattern` |
| Ersetzen | `sed 's/alt/neu/'` |
| Rechnen | `awk '{sum+=$1}'` |
## Siehe auch
- [[grep]] - Textsuche
- [[sed]] - Stream-Editor
- [[find]] - Dateien finden
- [[BASH Funktionen]] - awk in Funktionen nutzen
- [[ls]] - Ausgabe mit awk verarbeiten
+362
View File
@@ -0,0 +1,362 @@
# find - Dateien und Verzeichnisse suchen
Der Befehl `find` durchsucht Verzeichnisse rekursiv nach Dateien oder Ordnern anhand verschiedener Kriterien.
## Grundsyntax
```bash
find [Pfad] [Suchkriterien] [Aktionen]
```
## Suchkriterien
### Nach Namen suchen
```bash
find . -name "datei.txt" # exakte Übereinstimmung
find . -iname "datei.txt" # case-insensitive
find . -name "*.log" # mit Wildcards
```
### Nach Dateityp suchen
```bash
find . -type f # nur Dateien
find . -type d # nur Verzeichnisse
find . -type l # symbolische Links
```
### Nach Dateigröße suchen
```bash
find . -size +10M # größer als 10 MB
find . -size -100k # kleiner als 100 KB
find . -size 0 # leere Dateien
```
### Nach Berechtigungen suchen
```bash
find . -perm 644 # Dateien mit Rechten 644
find . -user alice # Dateien von User "alice"
find . -group admins # Dateien von Gruppe "admins"
```
### Suchtiefe begrenzen
```bash
find . -maxdepth 1 -type f
```
Nur im aktuellen Ordner, nicht in Unterordnern.
## Suche nach Datum und Zeit
### Zeitstempel-Typen
- **mtime** (modification time) = Inhalt geändert
- **atime** (access time) = Datei gelesen
- **ctime** (change time) = Metadaten geändert (chmod, chown)
### Relative Zeitangaben (Tage)
```bash
find . -mtime -7 # in den letzten 7 Tagen geändert
find . -mtime +30 # älter als 30 Tage
find . -atime -1 # in den letzten 24 Stunden geöffnet
find . -ctime -1 # Metadaten in letzten 24h geändert
```
Dateien zwischen X und Y Tagen:
```bash
find . -mtime +7 -mtime -30
```
### Absolute Zeitangaben (Datum, GNU find)
```bash
find . -newermt "2025-04-01" # mtime nach Datum
find . -newerat "2025-04-01" # atime nach Datum
find . -newerct "2025-04-01" # ctime nach Datum
find . -newermt "2023-09-01" ! -newermt "2023-09-10" # zwischen zwei Daten
```
**Hinweis:** `-newermt/at/ct` sind GNU-Erweiterungen (nicht auf BSD/macOS).
### Mit Referenzdatei
```bash
touch -d "2025-04-01" /tmp/refdate
find . -newer /tmp/refdate
```
### Übersicht Zeitoptionen
| Option | Bedeutung |
|--------|-----------|
| `-mtime -7` | in den letzten 7 Tagen geändert |
| `-mtime +30` | älter als 30 Tage |
| `-atime -2` | in den letzten 2 Tagen geöffnet |
| `-ctime -1` | Metadaten in letzten 24h geändert |
| `-newermt "2023-09-01"` | mtime nach Datum (GNU) |
| `-newerat "2023-09-01"` | atime nach Datum (GNU) |
| `-newerct "2023-09-01"` | ctime nach Datum (GNU) |
| `-newer datei.txt` | neuer als Referenzdatei |
## Bedingungen kombinieren
### UND-Verknüpfung (Standard)
```bash
find . -type f -size +1M -mtime -7
```
Dateien größer als 1 MB UND in den letzten 7 Tagen geändert.
### ODER-Verknüpfung
```bash
find . -type f \( -name "*.jpg" -o -name "*.png" \)
```
Alle `.jpg` ODER `.png` Dateien.
### Negation
```bash
find . -type f ! -iname "*.mp3"
```
Alle Dateien, die NICHT auf `.mp3` enden.
Mehrere Endungen ausschließen:
```bash
find . -type f ! \( -iname "*.mp3" -o -iname "*.flac" \)
```
## Aktionen auf gefundene Dateien
### Anzeigen
```bash
find . -name "*.log" -print # Standard
find . -name "*.log" -ls # mit Details
```
### Dateien löschen
**Grundprinzip:** Immer erst testen, dann löschen!
```bash
# 1. Testen
find . -name "*.tmp" -print
# 2. Anzahl prüfen
find . -name "*.tmp" | wc -l
# 3. Dry-run
find . -name "*.tmp" -exec echo rm {} +
# 4. Löschen
find . -name "*.tmp" -delete
```
Alternative mit `-exec`:
```bash
find . -name "*.tmp" -exec rm {} + # effizient (mehrere auf einmal)
find . -name "*.tmp" -exec rm {} \; # einzeln
find . -name "*.tmp" -exec rm -i {} \; # mit Rückfrage
```
Mit xargs (sicher bei Leerzeichen):
```bash
find . -name "*.tmp" -print0 | xargs -0 rm
```
### Mit -exec Befehle ausführen
```bash
find . -name "*.log" -exec rm {} + # Löschen
find . -type f -name "*.sh" -exec chmod +x {} + # Ausführbar machen
find /etc -type f -mtime -1 -exec cp {} /backup/ \; # Kopieren
find . -type f -name "*.log" -mtime +7 -exec gzip {} + # Komprimieren
```
- `{}` = Platzhalter für gefundene Datei
- `\;` = Ende des Befehls (einzeln, langsamer)
- `+` = mehrere Dateien gleichzeitig (effizienter)
### Komplexe Shell-Befehle
```bash
find . -type f -name "*.jpg" -exec sh -c 'for f; do
convert "$f" -resize 800x "${f%.jpg}_small.jpg"
done' _ {} +
```
## Pfad- und Namensfilter
### Mit -path (Glob-Muster)
```bash
find ~/Musik -type f -path "*/zzz Verschiedene/AlbumArt_*"
```
`-path` verwendet Shell-Wildcards (Globs), nicht reguläre Ausdrücke.
### Mit -regex (Reguläre Ausdrücke)
```bash
find ~/Musik -type f -regextype posix-extended \
-regex '.*/zzz Verschiedene/AlbumArt_.*'
```
`-regex` matcht den gesamten Pfad, daher oft `.*` am Anfang nötig.
## Praktische Anwendungsfälle
### Alte Dateien löschen
```bash
find /tmp -type f -mtime +7 -delete
```
### Leere Dateien/Verzeichnisse finden
```bash
find . -type f -empty # leere Dateien
find . -type d -empty # leere Ordner
```
### Dateien mit falschen Rechten
```bash
find / -type f -perm -o+w # weltweit schreibbar
```
### Große Dateien finden
```bash
find /home -type f -size +100M
find . -type f -exec du -h {} + | sort -rh | head -10 # Top 10 größte
```
### Dateien nach Datum und Pfad
```bash
find ~/Musik -type f \
-newermt "2025-04-01" \
-path "*/zzz Verschiedene/AlbumArt_*" \
-print
```
### Dateien sichern
```bash
find /etc -type f -mtime -1 -exec cp {} /backup/ \;
```
### Backup-Kandidaten mit Datum
```bash
find /backups -type f -name "*.tar.gz" \
-newermt "2023-08-01" ! -newermt "2023-08-31"
```
### Logfile-Analyse
```bash
find /var/log -type f -size +100M -newermt "2023-09-01"
```
### Nur Dateien, nicht Verzeichnisse ändern
```bash
find . -type f -exec chmod 644 {} +
find . -type d -exec chmod 755 {} +
```
## Best Practices und Fehler vermeiden
### Sicherheit beim Löschen
```bash
# IMMER erst testen
find . -name "*.tmp" -print
find . -name "*.tmp" | wc -l
find . -name "*.tmp" -exec echo rm {} +
# Dann löschen
find . -name "*.tmp" -delete
```
### Leerzeichen in Dateinamen
```bash
# RICHTIG: -print0 und xargs -0
find . -name "*.txt" -print0 | xargs -0 rm
# RICHTIG: -exec mit +
find . -name "*.txt" -exec rm {} +
# FALSCH: Pipe ohne -print0
find . -name "*.txt" | rm # funktioniert nicht!
```
### Trailing Slash bei -path
```bash
find . -path "*/ordner/*" # Dateien IN ordner/
find . -path "*/ordner" # NUR ordner/ selbst
```
### -delete Reihenfolge
```bash
# RICHTIG: -type f VOR -delete
find . -type f -name "*.tmp" -delete
# FALSCH: kann Verzeichnisse löschen
find . -name "*.tmp" -delete
```
### Zu viele Argumente
```bash
# FALSCH: kann "Argument list too long" geben
find . -name "*.txt" -exec rm {} \;
# RICHTIG: mit +
find . -name "*.txt" -exec rm {} +
# RICHTIG: mit xargs
find . -name "*.txt" -print0 | xargs -0 rm
```
## Alternative Tools
- **fd** - moderner, schneller find-Ersatz mit besserer Syntax
- **ripgrep (rg)** - für Textsuche in Dateien
- **locate** - schnelle Dateinamensuche (nutzt Datenbank)
Beispiel mit fd:
```bash
fd "*.log" # Einfacher als find
fd -t f -s +100M # Dateien > 100MB
fd -e jpg -x convert {} ... # Mit exec
```
## Siehe auch
- [[ls]] - Dateien auflisten
- [[grep]] - Textsuche in gefundenen Dateien
- [[Dateiberechtigungen]] - Rechte und Eigentümer von Dateien
- [[tar]] - Gefundene Dateien archivieren
- [[rsync]] - Dateien synchronisieren
- [[sed]] - Gefundene Dateien bearbeiten
- [[awk]] - Ausgabe von find verarbeiten
@@ -0,0 +1,127 @@
# fstab - Credentials sicher speichern
Zugangsdaten (Benutzername/Passwort) sollten nicht im Klartext in `/etc/fstab` stehen.
## Credentials-Datei verwenden
Viele Treiber wie `cifs` oder `smbfs` unterstützen separate Credential-Dateien.
### fstab-Eintrag
```fstab
//server/share /mnt/share cifs credentials=/etc/samba/credentials,iocharset=utf8,uid=1000,gid=1000 0 0
```
### Credentials-Datei erstellen
**/etc/samba/credentials:**
```
username=meinuser
password=meinpasswort
domain=meinedomain
```
### Datei absichern
```bash
sudo chmod 600 /etc/samba/credentials
sudo chown root:root /etc/samba/credentials
```
Nur root kann die Datei lesen, `/etc/fstab` enthält keine Secrets.
## Kernel Keyring nutzen
Für temporäre Mounts (z.B. bei CIFS):
```bash
cifscreds add -u meinuser servername
```
Dann kann der Mount in fstab ohne Passwort erfolgen - der Kernel holt die Daten aus dem Keyring.
**Hinweis:** Funktioniert hauptsächlich für interaktive Sessions, nicht für automatische Boot-Mounts.
## Systemd-Units verwenden
Statt `/etc/fstab` kann man systemd `.mount`-Units mit Credentials nutzen.
**Beispiel:** `/etc/systemd/system/mnt-share.mount`
```ini
[Unit]
Description=SMB Share Mount
[Mount]
What=//server/share
Where=/mnt/share
Type=cifs
Options=credentials=/etc/samba/credentials,iocharset=utf8,uid=1000,gid=1000
[Install]
WantedBy=multi-user.target
```
Aktivieren:
```bash
sudo systemctl daemon-reload
sudo systemctl enable mnt-share.mount
sudo systemctl start mnt-share.mount
```
## Kerberos-Authentifizierung
Für Netzwerke mit Active Directory oder Kerberos:
### NFS mit Kerberos
```fstab
server:/export /mnt/nfs nfs sec=krb5,rw 0 0
```
### CIFS mit Kerberos
```fstab
//server/share /mnt/share cifs sec=krb5,multiuser,rw 0 0
```
Keine Passwörter nötig - Authentifizierung über Kerberos-Tickets.
## Secrets-Management-Systeme
Für Produktivumgebungen mit höheren Sicherheitsanforderungen:
- **HashiCorp Vault** - zentrales Secrets-Management
- **AWS Secrets Manager** - für Cloud-Umgebungen
- **GPG-verschlüsselte Dateien** - lokal verschlüsselt
Beispiel mit GPG:
```bash
# Credentials verschlüsselt speichern
echo "username=user\npassword=pass" | gpg -e -r you@example.com > /etc/samba/credentials.gpg
# In Mount-Skript entschlüsseln
gpg -d /etc/samba/credentials.gpg > /tmp/credentials
mount -t cifs -o credentials=/tmp/credentials //server/share /mnt/share
rm /tmp/credentials
```
## Zusammenfassung
| Methode | Sicherheit | Komplexität | Anwendungsfall |
|---------|-----------|-------------|----------------|
| Credentials-Datei | Gut | Niedrig | Standard für CIFS/SMB |
| Kernel Keyring | Mittel | Mittel | Interaktive Sessions |
| Kerberos | Sehr gut | Hoch | Enterprise/AD-Umgebungen |
| Systemd-Credentials | Sehr gut | Mittel | Moderne Systeme |
| Secrets Manager | Sehr gut | Hoch | Produktivumgebungen |
**Empfehlung:** Für den Alltag ist eine separate Credentials-Datei mit restriktiven Rechten (600) der beste Kompromiss aus Sicherheit und Einfachheit.
## Siehe auch
- [[Symlinks]] - Symbolische Links erstellen
- [[Dateiberechtigungen]] - Dateien absichern mit chmod/chown
- [[lsblk]] - Block-Geräte anzeigen
+202
View File
@@ -0,0 +1,202 @@
# grep - Textsuche in Dateien
Der `grep`-Befehl durchsucht Dateien oder Textströme nach Mustern (Strings oder reguläre Ausdrücke).
## Grundsyntax
```bash
grep [OPTIONEN] MUSTER [DATEI...]
```
## Einfache Suche
```bash
grep "suchtext" datei.txt
```
In mehreren Dateien:
```bash
grep "suchtext" *.txt
```
Rekursiv in Verzeichnissen:
```bash
grep -r "suchtext" /pfad/zum/verzeichnis
```
## Wichtige Optionen
### Groß-/Kleinschreibung
```bash
grep -i "suchtext" datei.txt # case-insensitive
```
### Zeilen mit Kontext
```bash
grep -A 3 "suchtext" datei.txt # 3 Zeilen danach
grep -B 3 "suchtext" datei.txt # 3 Zeilen davor
grep -C 3 "suchtext" datei.txt # 3 Zeilen davor und danach
```
### Nur Dateinamen anzeigen
```bash
grep -l "suchtext" *.txt # Dateien mit Treffer
grep -L "suchtext" *.txt # Dateien ohne Treffer
```
### Zeilennummern anzeigen
```bash
grep -n "suchtext" datei.txt
```
### Anzahl der Treffer
```bash
grep -c "suchtext" datei.txt
```
### Invertierte Suche (nicht enthalten)
```bash
grep -v "suchtext" datei.txt
```
Zeigt alle Zeilen, die den Suchtext NICHT enthalten.
### Ganzes Wort
```bash
grep -w "wort" datei.txt
```
Findet "wort", aber nicht "worte" oder "hauptwort".
## Reguläre Ausdrücke
### Einfache Regex (Basic)
```bash
grep "^Start" datei.txt # Zeilen, die mit "Start" beginnen
grep "Ende$" datei.txt # Zeilen, die mit "Ende" enden
grep "^$" datei.txt # Leere Zeilen
```
### Extended Regex
```bash
grep -E "fehler|warnung" datei.txt # fehler ODER warnung
grep -E "[0-9]{3}-[0-9]{4}" datei.txt # Telefonnummern
grep -E "^(root|admin)" /etc/passwd # Zeilen mit root oder admin am Anfang
```
### Perl-kompatible Regex
```bash
grep -P "\d{3}-\d{4}" datei.txt
```
## Praktische Anwendungsfälle
### Logfiles durchsuchen
```bash
grep -i "error" /var/log/syslog
grep -E "error|warning|critical" /var/log/syslog
```
### Mit Zeitstempel
```bash
grep "2025-11-07" /var/log/application.log
```
### Konfigurationsdateien
```bash
# Alle nicht-kommentierten Zeilen
grep -v "^#" /etc/ssh/sshd_config | grep -v "^$"
```
### In komprimierten Dateien
```bash
zgrep "suchtext" datei.log.gz
```
### Mit find kombinieren
```bash
find . -name "*.log" -exec grep -l "ERROR" {} +
```
### Mehrere Muster aus Datei
```bash
grep -f muster.txt datei.txt
```
**muster.txt:**
```
fehler
warnung
critical
```
## Pipe-Verwendung
```bash
ps aux | grep firefox
cat datei.txt | grep -v "^#" | grep "wichtig"
dmesg | grep -i usb
```
## Farbige Ausgabe
```bash
grep --color=auto "suchtext" datei.txt
```
Alias in `.bashrc` setzen:
```bash
alias grep='grep --color=auto'
```
## Alternative Tools
- **ripgrep (rg)** - sehr schnell, modern, empfohlen
- **ag (The Silver Searcher)** - schneller als grep
- **ack** - für Code-Suche optimiert
Beispiel mit ripgrep:
```bash
rg "suchtext" /pfad # automatisch rekursiv, ignoriert .gitignore
```
## Zusammenfassung wichtiger Optionen
| Option | Beschreibung |
|--------|--------------|
| `-i` | Case-insensitive |
| `-r` | Rekursiv |
| `-n` | Mit Zeilennummern |
| `-c` | Anzahl der Treffer |
| `-l` | Nur Dateinamen |
| `-v` | Invertiert (nicht enthalten) |
| `-w` | Ganzes Wort |
| `-E` | Extended Regex |
| `-A/-B/-C` | Kontext anzeigen |
## Siehe auch
- [[find]] - Dateien nach Namen/Eigenschaften suchen
- [[sed]] - Stream-Editor für Textmanipulation
- [[awk]] - Textverarbeitung und Datenextraktion
- [[ls]] - Ausgabe von ls filtern
+390
View File
@@ -0,0 +1,390 @@
# ls - Dateien und Verzeichnisse auflisten
Der `ls`-Befehl listet Dateien und Verzeichnisse auf und zeigt deren Eigenschaften.
## Grundsyntax
```bash
ls [OPTIONEN] [PFAD...]
```
## Grundlegende Verwendung
### Einfache Auflistung
```bash
ls # Aktuelles Verzeichnis
ls /pfad/zum/ordner # Bestimmtes Verzeichnis
ls datei.txt # Einzelne Datei
```
### Versteckte Dateien anzeigen
```bash
ls -a # Alle Dateien (inkl. .dotfiles)
ls -A # Alle außer . und ..
```
## Detaillierte Ausgabe
### Long Format (-l)
```bash
ls -l
```
Beispielausgabe:
```
-rw-r--r-- 1 alice developers 1234 Nov 7 10:00 datei.txt
drwxr-xr-x 2 alice developers 4096 Nov 7 09:30 ordner
lrwxrwxrwx 1 alice developers 15 Nov 7 08:00 link -> /pfad/zu/ziel
```
Spalten:
- **1. Zeichen**: Typ (`-` = Datei, `d` = Verzeichnis, `l` = Link)
- **2-10**: Rechte (rwx für User, Group, Others)
- **Zahl**: Anzahl Hardlinks
- **User**: Eigentümer
- **Group**: Gruppe
- **Größe**: in Bytes
- **Datum/Zeit**: letzte Änderung
- **Name**: Dateiname
### Menschenlesbare Größen (-h)
```bash
ls -lh
```
Beispielausgabe:
```
-rw-r--r-- 1 user staff 12K Nov 7 10:00 file.txt
-rw-r--r-- 1 user staff 1.2M Nov 7 09:30 big.dat
drwxr-xr-x 2 user staff 4.0K Nov 7 08:00 ordner
```
Größen werden in KB, MB, GB statt Bytes angezeigt.
## Sortierung
### Nach Name (Standard)
```bash
ls # Alphabetisch
ls -r # Umgekehrt
```
### Nach Änderungsdatum
```bash
ls -lt # Neueste zuerst
ls -ltr # Älteste zuerst
```
### Nach Größe
```bash
ls -lS # Größte zuerst
ls -lSr # Kleinste zuerst
```
### Nach Erweiterung
```bash
ls -lX # Gruppiert nach Dateityp
```
## Rekursive Auflistung
```bash
ls -R # Alle Unterverzeichnisse
ls -R /pfad # Ab bestimmtem Pfad
```
## Nur bestimmte Dateien
### Mit Wildcards
```bash
ls *.txt # Alle .txt Dateien
ls *.{jpg,png} # Alle .jpg und .png
ls file[0-9]* # file0, file1, file2, ...
```
### Nur Verzeichnisse
```bash
ls -d */ # Nur Verzeichnisse
ls -ld */ # Mit Details
```
### Nur Dateien (keine Verzeichnisse)
```bash
ls -p | grep -v /
```
## Farben
```bash
ls --color=auto # Farbige Ausgabe
ls --color=never # Ohne Farben
ls --color=always # Immer Farben (auch in Pipes)
```
Typische Farben:
- **Blau**: Verzeichnisse
- **Grün**: Ausführbare Dateien
- **Cyan**: Symbolische Links
- **Rot**: Archive
- **Gelb**: Devices
## Spezielle Formate
### Einzelne Spalte
```bash
ls -1 # Eine Datei pro Zeile
```
### Komma-getrennt
```bash
ls -m # Komma-getrennte Liste
```
### Mit Inode-Nummern
```bash
ls -i # Zeigt Inode-Nummern
```
### Numerische UIDs/GIDs
```bash
ls -n # User/Group als Zahlen statt Namen
```
## Dateigrößen analysieren
### Größe einzelner Dateien
```bash
ls -lh datei.txt
```
Ausgabe:
```
-rw-r--r-- 1 user staff 12K Nov 7 10:00 datei.txt
```
### Größe mit stat
Nur die Größe in Bytes:
```bash
stat -c%s datei.txt
```
Mit Dateiname:
```bash
stat -c "%s %n" *
```
### Größe von Verzeichnissen
`ls` zeigt nur die Größe des Verzeichniseintrags (meist 4K), nicht den Inhalt!
Für echte Verzeichnisgröße nutze `du`:
```bash
du -sh ordner/ # Gesamtgröße
du -h --max-depth=1 # Größen aller Unterordner
```
Beispielausgabe:
```
200M ./Bilder
1.3G ./Videos
50K ./Dokumente
1.5G .
```
Mit 1000er-Schritten statt 1024er:
```bash
du -h --si --max-depth=1
```
### Nach Größe sortiert
```bash
du -sh * | sort -h # Alle Dateien/Ordner sortiert
ls -lhS # Nur Dateien, größte zuerst
```
### Größte Dateien finden
Top 10 größte Dateien:
```bash
du -ah . | sort -rh | head -n 10
```
Mit [[find]]:
```bash
find . -type f -exec du -h {} + | sort -rh | head -n 10
```
### Speicherplatznutzung überwachen
Gesamter Speicherplatz:
```bash
df -h # Dateisysteme
df -h /home # Bestimmter Mountpoint
```
## Zeitstempel
### Änderungszeit (Standard)
```bash
ls -l # Zeigt mtime (modification time)
```
### Zugriffszeit
```bash
ls -lu # Zeigt atime (access time)
```
### Statusänderungszeit
```bash
ls -lc # Zeigt ctime (change time)
```
### Mit vollständigem Zeitstempel
```bash
ls -l --time-style=full-iso
ls -l --time-style=long-iso
ls -l --time-style=iso
```
## Praktische Kombinationen
### Übersichtliche Dateiliste
```bash
ls -lhA # Details, lesbar, alle außer . und ..
ls -lhAtr # Dazu sortiert nach Datum, älteste zuerst
```
### Schnelle Dateisuche
```bash
ls -la | grep datei # Suche in aktueller Liste
```
### Nur Größen von Verzeichnissen
```bash
du -sh */ # Alle Unterverzeichnisse
```
### Dateien nach Änderung heute
```bash
ls -lt | head # Neueste Dateien
```
### Ausführbare Dateien finden
```bash
ls -l | grep '^-..x'
```
### Große Dateien finden
```bash
ls -lhS | head -n 10 # Top 10 größte Dateien
```
### Versteckte Dateien zählen
```bash
ls -A | wc -l
```
## Nützliche Aliases
Setze in `~/.bashrc`:
```bash
alias ll='ls -lhA'
alias la='ls -A'
alias l='ls -CF'
alias lt='ls -lhAtr'
alias lsize='ls -lhS'
```
## Zusammen mit anderen Befehlen
### Mit find
```bash
find . -name "*.log" -exec ls -lh {} \;
```
### Mit grep
```bash
ls -la | grep "Nov 7" # Dateien von heute
ls -la | grep "^d" # Nur Verzeichnisse
```
### Mit awk
```bash
ls -l | awk '{print $9, $5}' # Name und Größe
```
### Mit xargs
```bash
ls *.txt | xargs rm # VORSICHT: Löscht alle .txt
```
## Fehler vermeiden
### Dateien mit Leerzeichen
```bash
# FALSCH
ls *.txt | xargs rm
# RICHTIG
find . -name "*.txt" -print0 | xargs -0 rm
```
### Alias-Konflikte
Viele Systeme haben `ls` als Alias mit `--color=auto` definiert. Um den echten Befehl zu nutzen:
```bash
\ls # Umgeht Alias
command ls # Umgeht Alias
/bin/ls # Direkter Pfad
```
## Siehe auch
- [[find]] - Erweiterte Dateisuche mit Kriterien
- [[grep]] - Ausgabe filtern
- [[Dateiberechtigungen]] - Bedeutung der Rechtespalten
- [[lsblk]] - Block-Geräte statt Dateien
- [[du]] - Detaillierte Größenanalyse
+177
View File
@@ -0,0 +1,177 @@
# lsblk - Block-Geräte auflisten
Der Befehl `lsblk` (list block devices) zeigt eine hierarchische Übersicht aller Blockgeräte: Festplatten, SSDs, USB-Sticks, Partitionen, LVMs, RAID-Geräte usw.
## Grundsyntax
```bash
lsblk [OPTIONEN] [GERÄTE...]
```
Ohne Parameter werden alle erkannten Blockgeräte in Baumstruktur angezeigt.
## Typische Ausgabe
```bash
lsblk
```
Beispiel:
```
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 512G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 64G 0 part /
└─sda3 8:3 0 447.5G 0 part /home
sdb 8:16 1 128G 0 disk
└─sdb1 8:17 1 128G 0 part /media/usb
```
Spalten:
- **NAME** = Gerätename (sda, sdb, ...)
- **SIZE** = Größe
- **TYPE** = Art (disk, part, rom, lvm ...)
- **MOUNTPOINTS** = Einbindungspunkt im Dateisystem
## Wichtige Optionen
### Bestimmte Spalten anzeigen
```bash
lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT
```
Beispiel:
```
NAME FSTYPE SIZE MOUNTPOINT
sda 512G
├─sda1 vfat 512M /boot/efi
├─sda2 ext4 64G /
└─sda3 ext4 447.5G /home
```
### Dateisystemtypen anzeigen
```bash
lsblk -f
```
Zeigt Dateisystemtyp, UUID und Label.
### Nur Geräte ohne Partitionen
```bash
lsblk -d
```
Zeigt nur die Hauptgeräte (`sda`, `sdb`), keine Partitionen.
### Alle Geräte inklusive leere
```bash
lsblk -a
```
Zeigt auch Geräte ohne Medium (z.B. leere CD-Laufwerke).
### Mit UUIDs und Labels
```bash
lsblk -o NAME,SIZE,UUID,LABEL,MOUNTPOINT
```
Wichtig für eindeutige Identifizierung in `/etc/fstab`.
### Nur Namen ausgeben
```bash
lsblk -n -o NAME
```
Beispiel:
```
sda
sda1
sda2
sda3
sdb
sdb1
```
Praktisch für Skripte.
### Listen- oder JSON-Format
```bash
lsblk -l # Listenformat
lsblk -J # JSON-Format
```
## Praktische Anwendungsfälle
### Herausfinden, welche Geräte angeschlossen sind
```bash
lsblk
```
### Prüfen, welche Partitionen wohin gemountet sind
```bash
lsblk -o NAME,SIZE,MOUNTPOINT
```
### Dateisystemtypen ermitteln
```bash
lsblk -f
```
### Neu eingesteckten USB-Stick identifizieren
Vorher:
```bash
lsblk
```
Stick einstecken, dann:
```bash
lsblk
```
Das neue Gerät (z.B. `sdb1`) erscheint.
### UUIDs für fstab ermitteln
```bash
lsblk -o NAME,UUID,MOUNTPOINT
```
### Geräte mit bestimmtem Dateisystem finden
```bash
lsblk -o NAME,FSTYPE,SIZE | grep ext4
```
## Zusammenfassung wichtiger Optionen
| Option | Beschreibung |
|--------|--------------|
| `lsblk` | Baumstruktur aller Blockgeräte |
| `lsblk -f` | Mit Dateisystemtypen |
| `lsblk -d` | Nur Hauptgeräte |
| `lsblk -a` | Alle inkl. leere Geräte |
| `lsblk -o SPALTEN` | Bestimmte Spalten |
| `lsblk -l` | Listenformat |
| `lsblk -J` | JSON-Format |
## Siehe auch
- [[ls]] - Dateien und Verzeichnisse auflisten
- [[find]] - Dateien suchen
- [[fstab Credentials]] - Geräte automatisch einbinden
- [[Symlinks]] - Verknüpfungen zu Geräten
- [[Dateiberechtigungen]] - Rechte von Geräten prüfen
+275
View File
@@ -0,0 +1,275 @@
# rsync - Dateien synchronisieren
Der `rsync`-Befehl synchronisiert Dateien und Verzeichnisse effizient zwischen verschiedenen Orten (lokal oder über Netzwerk).
## Grundsyntax
```bash
rsync [OPTIONEN] QUELLE ZIEL
```
## Grundlegende Optionen
Die häufigste Kombination:
```bash
rsync -av quelle/ ziel/
```
- `-a` = archive (behält Rechte, Zeitstempel, Symlinks)
- `-v` = verbose (zeigt Details)
## Lokale Synchronisation
### Verzeichnis synchronisieren
```bash
rsync -av /quelle/verzeichnis/ /ziel/verzeichnis/
```
**Wichtig:** Trailing Slash `/` macht einen Unterschied!
```bash
rsync -av quelle/ ziel/ # Inhalt von quelle/ nach ziel/
rsync -av quelle ziel/ # quelle/ als Unterordner in ziel/quelle/
```
## Über Netzwerk (SSH)
### Zu Remote-Server
```bash
rsync -av /lokaler/pfad/ user@server:/remote/pfad/
```
### Von Remote-Server
```bash
rsync -av user@server:/remote/pfad/ /lokaler/pfad/
```
### Anderen SSH-Port
```bash
rsync -av -e "ssh -p 2222" /lokal/ user@server:/remote/
```
## Wichtige Optionen
### Fortschritt anzeigen
```bash
rsync -av --progress quelle/ ziel/
```
### Dry-run (simulieren)
```bash
rsync -avn quelle/ ziel/
```
- `-n` = dry-run (nichts ändern, nur anzeigen)
### Dateien löschen im Ziel
```bash
rsync -av --delete quelle/ ziel/
```
Löscht Dateien im Ziel, die in der Quelle nicht existieren.
### Kompression (für Netzwerk)
```bash
rsync -avz quelle/ user@server:/remote/
```
- `-z` = compress (während Übertragung)
### Teilweise übertragene Dateien behalten
```bash
rsync -av --partial quelle/ ziel/
```
Nützlich bei unterbrochenen Übertragungen.
### Bandbreite begrenzen
```bash
rsync -av --bwlimit=1000 quelle/ ziel/
```
Begrenzt auf 1000 KB/s.
## Dateien ausschließen
### Einzelne Muster
```bash
rsync -av --exclude='*.tmp' --exclude='.git' quelle/ ziel/
```
### Aus Datei
```bash
rsync -av --exclude-from=exclude.txt quelle/ ziel/
```
**exclude.txt:**
```
*.tmp
*.log
.git/
node_modules/
```
### Nur bestimmte Dateien
```bash
rsync -av --include='*.pdf' --exclude='*' quelle/ ziel/
```
## Praktische Beispiele
### Backup erstellen
```bash
rsync -av --delete /home/user/dokumente/ /backup/dokumente/
```
### Backup mit Zeitstempel
```bash
rsync -av /quelle/ /backup/backup-$(date +%Y%m%d)/
```
### Nur geänderte Dateien kopieren
```bash
rsync -av --update quelle/ ziel/
```
Überschreibt nur, wenn Quelle neuer ist.
### Große Dateien übertragen
```bash
rsync -av --progress --partial-dir=.rsync-partial quelle/ ziel/
```
### Backup auf NAS
```bash
rsync -av --delete /home/user/ user@nas:/backup/user/
```
### Website hochladen
```bash
rsync -avz --delete website/ user@webserver:/var/www/html/
```
### Mit Ausschlüssen
```bash
rsync -av --delete \
--exclude='node_modules' \
--exclude='.git' \
--exclude='*.log' \
projekt/ /backup/projekt/
```
## Inkrementelles Backup
```bash
#!/bin/bash
CURRENT=/backup/current
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
rsync -av --delete --link-dest=$CURRENT /quelle/ /backup/$TIMESTAMP/
rm -f $CURRENT
ln -s $TIMESTAMP $CURRENT
```
Erstellt platzsparende Backups durch Hardlinks.
## Rechte und Eigentümer
### Rechte bewahren
```bash
rsync -av quelle/ ziel/ # Standard mit -a
```
### Als Root mit Original-Eigentümer
```bash
sudo rsync -av quelle/ ziel/
```
### Nur als aktueller User
```bash
rsync -rlptv quelle/ ziel/
```
Ohne `-o` und `-g` (Owner und Group).
## Fehler vermeiden
### Dry-run erst testen
```bash
rsync -avn --delete quelle/ ziel/
```
Prüfe die Ausgabe, bevor du wirklich synchronisierst!
### Slash bei Quelle beachten
```bash
rsync -av quelle/ ziel/ # Inhalt synchronisieren
rsync -av quelle ziel/ # Ordner synchronisieren
```
### Mit --delete vorsichtig sein
```bash
# FALSCH - löscht alles im Ziel!
rsync -av --delete /leerer/ordner/ /wichtig/
# RICHTIG - erst prüfen
rsync -avn --delete quelle/ ziel/
```
## Vergleich mit anderen Tools
| Tool | Geschwindigkeit | Delta-Transfer | Netzwerk | Verschlüsselung |
|------|----------------|----------------|----------|-----------------|
| `rsync` | Schnell | Ja | SSH | Via SSH |
| `scp` | Mittel | Nein | SSH | Ja |
| `cp` | Sehr schnell | Nein | Nein | Nein |
| `tar` | Mittel | Nein | Pipe möglich | Optional |
## Monitoring
### Fortschritt detailliert
```bash
rsync -av --progress --stats quelle/ ziel/
```
### Nur Zusammenfassung
```bash
rsync -av --stats quelle/ ziel/
```
## Siehe auch
- [[tar]] - Archive erstellen
- [[find]] - Dateien für Backup finden
- [[Symlinks]] - Links bleiben mit -a erhalten
- [[Dateiberechtigungen]] - Rechte und Eigentümer nach rsync
- [[ls]] - Übertragene Dateien anzeigen
+270
View File
@@ -0,0 +1,270 @@
# sed - Stream Editor
Der `sed`-Befehl ist ein Stream-Editor für Textmanipulation. Er eignet sich besonders für Suchen-und-Ersetzen-Operationen.
## Grundsyntax
```bash
sed [OPTIONEN] 'BEFEHL' [DATEI...]
```
## Suchen und Ersetzen
### Grundlegendes Ersetzen
```bash
sed 's/alt/neu/' datei.txt
```
Ersetzt erste Vorkommen in jeder Zeile.
### Alle Vorkommen in Zeile
```bash
sed 's/alt/neu/g' datei.txt
```
- `g` = global (alle Vorkommen)
### Datei direkt ändern
```bash
sed -i 's/alt/neu/g' datei.txt
```
- `-i` = in-place (Datei wird geändert)
### Backup vor Änderung
```bash
sed -i.bak 's/alt/neu/g' datei.txt
```
Erstellt `datei.txt.bak` vor Änderung.
## Zeilen auswählen
### Bestimmte Zeile
```bash
sed -n '5p' datei.txt # Nur Zeile 5
sed '5d' datei.txt # Zeile 5 löschen
sed '5s/alt/neu/' datei.txt # Nur in Zeile 5 ersetzen
```
### Zeilenbereich
```bash
sed -n '10,20p' datei.txt # Zeilen 10-20 anzeigen
sed '10,20d' datei.txt # Zeilen 10-20 löschen
```
### Letzte Zeile
```bash
sed -n '$p' datei.txt # Letzte Zeile
```
### Muster-basiert
```bash
sed '/^#/d' datei.txt # Zeilen mit # am Anfang löschen
sed '/ERROR/s/foo/bar/' datei.txt # Nur in Zeilen mit ERROR
```
## Zeilen einfügen und anhängen
### Vor Zeile einfügen
```bash
sed '3i\Neue Zeile' datei.txt
```
### Nach Zeile anhängen
```bash
sed '3a\Neue Zeile' datei.txt
```
### Nach Muster
```bash
sed '/TODO/a\WICHTIG: Bitte bearbeiten' datei.txt
```
## Zeilen löschen
### Leere Zeilen
```bash
sed '/^$/d' datei.txt
```
### Kommentare
```bash
sed '/^#/d' datei.txt
```
### Mehrere Muster
```bash
sed -e '/^#/d' -e '/^$/d' datei.txt
```
## Reguläre Ausdrücke
### Erweiterte Regex
```bash
sed -E 's/[0-9]{3}-[0-9]{4}/XXX-XXXX/g' datei.txt
```
- `-E` = Extended Regex
### Gruppen und Backreferences
```bash
sed 's/\([0-9]*\)-\([0-9]*\)/\2-\1/' datei.txt
```
Vertauscht Zahlen vor und nach Bindestrich.
Mit `-E`:
```bash
sed -E 's/([0-9]*)-([0-9]*)/\2-\1/' datei.txt
```
## Praktische Beispiele
### Konfigurationsdatei ändern
```bash
sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_config
```
### IP-Adressen ersetzen
```bash
sed 's/192\.168\.1\./10.0.0./g' config.txt
```
### Zeilennummern hinzufügen
```bash
sed = datei.txt | sed 'N;s/\n/\t/'
```
### Kommentare und Leerzeilen entfernen
```bash
sed -e '/^#/d' -e '/^$/d' config.conf
```
### Mehrere Ersetzungen
```bash
sed -e 's/foo/bar/g' -e 's/alt/neu/g' datei.txt
```
### Case-insensitive Suche
```bash
sed 's/fehler/ERROR/gI' datei.txt
```
- `I` = case-insensitive
### Zeilen mit Muster extrahieren
```bash
sed -n '/ERROR/p' logfile.txt
```
Zeigt nur Zeilen mit "ERROR".
### Text zwischen Mustern
```bash
sed -n '/START/,/END/p' datei.txt
```
### Zeilen nummerieren
```bash
sed = datei.txt
```
## Mit Pipes
```bash
cat datei.txt | sed 's/alt/neu/g' | grep wichtig
ps aux | sed -n '1p;/firefox/p'
```
## Mehrere Dateien
```bash
sed -i 's/alt/neu/g' *.txt
```
## Sed-Skripte
**script.sed:**
```sed
# Kommentare entfernen
/^#/d
# Leerzeilen entfernen
/^$/d
# foo durch bar ersetzen
s/foo/bar/g
```
Verwenden:
```bash
sed -f script.sed datei.txt
```
## Fehler vermeiden
### Backup erstellen
```bash
sed -i.bak 's/alt/neu/g' wichtig.txt
```
### Testen ohne Änderung
```bash
sed 's/alt/neu/g' datei.txt > test.txt
diff datei.txt test.txt
```
### Spezialzeichen escapen
```bash
# Punkt ist Wildcard
sed 's/192.168.1.1/10.0.0.1/' config # FALSCH
# Punkt escapen
sed 's/192\.168\.1\.1/10.0.0.1/' config # RICHTIG
```
## Alternative Delimiter
Wenn Pfade mit `/` vorkommen:
```bash
sed 's|/old/path|/new/path|g' datei.txt
```
Statt `/` kann `|`, `#` oder andere Zeichen verwendet werden.
## Siehe auch
- [[grep]] - Textsuche
- [[awk]] - Komplexere Textverarbeitung
- [[find]] - Dateien finden und mit sed bearbeiten
- [[BASH Funktionen]] - sed in Funktionen verwenden
+354
View File
@@ -0,0 +1,354 @@
# tar - Archive erstellen und Software installieren
Der `tar`-Befehl (tape archive) erstellt und entpackt Archive. Oft in Kombination mit Kompression (gzip, bzip2, xz).
## Grundsyntax
```bash
tar [OPTIONEN] [ARCHIV] [DATEIEN...]
```
## Archive erstellen
### Einfaches Archiv (unkomprimiert)
```bash
tar -cf archiv.tar verzeichnis/
```
- `-c` = create (erstellen)
- `-f` = file (Dateiname)
### Mit gzip-Kompression (.tar.gz)
```bash
tar -czf archiv.tar.gz verzeichnis/
```
- `-z` = gzip
### Mit bzip2-Kompression (.tar.bz2)
```bash
tar -cjf archiv.tar.bz2 verzeichnis/
```
- `-j` = bzip2
### Mit xz-Kompression (.tar.xz)
```bash
tar -cJf archiv.tar.xz verzeichnis/
```
- `-J` = xz (beste Kompression)
### Mit Fortschrittsanzeige
```bash
tar -czf archiv.tar.gz verzeichnis/ -v
```
- `-v` = verbose (Details anzeigen)
## Archive entpacken
### Automatische Kompressionserkennung
```bash
tar -xf archiv.tar.gz
```
- `-x` = extract (entpacken)
### In bestimmtes Verzeichnis
```bash
tar -xf archiv.tar.gz -C /ziel/verzeichnis
```
### Mit Fortschrittsanzeige
```bash
tar -xvf archiv.tar.gz
```
## Archiv-Inhalt anzeigen
```bash
tar -tf archiv.tar.gz
```
- `-t` = list (auflisten)
Mit Details:
```bash
tar -tvf archiv.tar.gz
```
## Praktische Beispiele
### Backup erstellen
```bash
tar -czf backup-$(date +%Y%m%d).tar.gz /home/user/dokumente
```
### Bestimmte Dateien ausschließen
```bash
tar -czf archiv.tar.gz --exclude='*.tmp' --exclude='.git' verzeichnis/
```
### Nur bestimmte Dateien hinzufügen
```bash
tar -czf logs.tar.gz /var/log/*.log
```
### Zu bestehendem Archiv hinzufügen
```bash
tar -rf archiv.tar neue_datei.txt
```
**Hinweis:** Funktioniert nur bei unkomprimierten Archiven!
### Einzelne Datei aus Archiv extrahieren
```bash
tar -xzf archiv.tar.gz pfad/zur/datei.txt
```
### Archiv auf andere Maschine übertragen
```bash
tar -czf - verzeichnis/ | ssh user@server "cd /ziel && tar -xzf -"
```
## Dateirechte bewahren
```bash
tar -czpf archiv.tar.gz verzeichnis/
```
- `-p` = preserve permissions
Als Root entpacken und Eigentümer bewahren:
```bash
sudo tar -xpf archiv.tar.gz
```
## Inkrementelles Backup
```bash
tar -czf backup-full.tar.gz -g snapshot.file verzeichnis/
tar -czf backup-incr.tar.gz -g snapshot.file verzeichnis/
```
- `-g` = incremental (inkrementell)
## Geschwindigkeit vs. Kompression
| Format | Geschwindigkeit | Kompression | Empfehlung |
|--------|----------------|-------------|------------|
| `.tar` | Sehr schnell | Keine | Lokale Kopien |
| `.tar.gz` | Schnell | Gut | Standard |
| `.tar.bz2` | Mittel | Besser | Archivierung |
| `.tar.xz` | Langsam | Beste | Langzeit-Archiv |
## Fehler vermeiden
### Führenden Slash entfernen
```bash
tar -czf archiv.tar.gz --absolute-names /home/user/dokumente # Mit /
tar -czf archiv.tar.gz -C /home/user dokumente # Ohne /
```
Zweite Variante ist sicherer beim Entpacken.
### Große Archive
Prüfe Speicherplatz vorher:
```bash
du -sh verzeichnis/
df -h .
```
### Testen vor Löschen
```bash
tar -czf backup.tar.gz daten/
tar -tzf backup.tar.gz | head # Inhalt prüfen
# Erst dann löschen:
rm -rf daten/
```
## Mit Verschlüsselung
```bash
# Erstellen und verschlüsseln
tar -czf - verzeichnis/ | gpg -c > archiv.tar.gz.gpg
# Entschlüsseln und entpacken
gpg -d archiv.tar.gz.gpg | tar -xzf -
```
## Software aus tar.gz installieren
Eine `.tar.gz`-Datei kann verschiedene Inhalte haben:
1. **Quellcode** → muss kompiliert werden
2. **Kompilierte Binaries** → nur entpacken und ausführen
3. **Paket für Distribution** → mit Paketmanager installieren
### Archiv entpacken und untersuchen
```bash
tar -xvzf paket.tar.gz
cd paket
ls -la
```
Prüfe immer `README`, `INSTALL` oder `INSTALL.txt`:
```bash
cat README
cat INSTALL
```
### Installation aus Quellcode
**Voraussetzungen installieren:**
Debian/Ubuntu:
```bash
sudo apt install build-essential
```
Fedora:
```bash
sudo dnf groupinstall "Development Tools"
```
**Standard-Kompilierung (autotools):**
```bash
./configure
make
sudo make install
```
**CMake-basierte Projekte:**
```bash
mkdir build
cd build
cmake ..
make
sudo make install
```
### Installation von fertigen Binaries
Wenn das Archiv fertige Programme enthält:
```bash
chmod +x programmname
./programmname
```
Permanent installieren nach `/usr/local/bin`:
```bash
sudo cp programmname /usr/local/bin/
```
Oder nach `~/.local/bin` (ohne sudo):
```bash
mkdir -p ~/.local/bin
cp programmname ~/.local/bin/
```
Stelle sicher, dass `~/.local/bin` im PATH ist:
```bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
```
### Deinstallation
Bei selbst kompilierten Programmen:
```bash
cd paket/
sudo make uninstall
```
Falls `make uninstall` nicht verfügbar ist:
**Mit checkinstall (empfohlen):**
```bash
sudo apt install checkinstall # Debian/Ubuntu
# Statt "sudo make install"
sudo checkinstall
# Später deinstallieren wie normales Paket
sudo apt remove paketname
```
**Manuell:**
```bash
# Liste der installierten Dateien erstellen
sudo make install > install.log 2>&1
# Zum Deinstallieren Dateien aus log löschen
```
### Beispiel-Workflow
```bash
# 1. Entpacken
tar -xzf programm-1.0.tar.gz
cd programm-1.0
# 2. Dokumentation lesen
cat README
cat INSTALL
# 3. Konfigurieren und kompilieren
./configure --prefix=/usr/local
make
# 4. Optional: Tests ausführen
make check
# 5. Installieren
sudo make install
# 6. Testen
which programmname
programmname --version
```
### Typische Verzeichnisse
Nach `make install` werden Dateien meist hier installiert:
- `/usr/local/bin/` - Programme
- `/usr/local/lib/` - Bibliotheken
- `/usr/local/share/` - Daten/Dokumentation
- `/usr/local/etc/` - Konfiguration
## Siehe auch
- [[rsync]] - Alternative für Backups
- [[find]] - Dateien für Archivierung finden
- [[grep]] - Archiv-Inhalte durchsuchen
- [[Dateiberechtigungen]] - Rechte in Archiven bewahren
- [[ls]] - Archive anzeigen
@@ -0,0 +1,243 @@
## Grundlegendes Vorgehen
Ein BASH Skript, das Argumente verarbeitet und weiterleitet, folgt diesem Muster:
```bash
#!/bin/bash
# Standardwerte definieren
DEFAULT_VALUE="standard"
VERBOSE=false
TARGET_SCRIPT="./target-script.sh"
# Argumente parsen
while [[ $# -gt 0 ]]; do
case $1 in
-v|--verbose)
VERBOSE=true
shift
;;
-f|--file)
FILE="$2"
shift 2
;;
-o|--output)
OUTPUT="${2:-$DEFAULT_VALUE}"
shift 2
;;
-h|--help)
show_help
exit 0
;;
*)
# Unbekannte Argumente sammeln
UNKNOWN_ARGS+=("$1")
shift
;;
esac
done
# Alle Argumente an Zielskript weiterleiten
"$TARGET_SCRIPT" "${UNKNOWN_ARGS[@]}"
```
## Verschiedene Weiterleitungsstrategien
### 1. Alle Argumente 1:1 weiterleiten
```bash
#!/bin/bash
./target-script.sh "$@"
```
### 2. Selektive Weiterleitung
```bash
#!/bin/bash
# Lokale Verarbeitung
WRAPPER_OPTION=""
TARGET_ARGS=()
while [[ $# -gt 0 ]]; do
case $1 in
--wrapper-only)
WRAPPER_OPTION="$2"
shift 2
;;
*)
TARGET_ARGS+=("$1")
shift
;;
esac
done
# Nur relevante Argumente weiterleiten
./target-script.sh "${TARGET_ARGS[@]}"
```
### 3. Argumente transformieren
```bash
#!/bin/bash
TRANSFORMED_ARGS=()
for arg in "$@"; do
case $arg in
--old-format)
TRANSFORMED_ARGS+=("--new-format")
;;
*)
TRANSFORMED_ARGS+=("$arg")
;;
esac
done
./target-script.sh "${TRANSFORMED_ARGS[@]}"
```
## Erweiterte Techniken
### Standardwerte und Validierung
```bash
#!/bin/bash
# Standardwerte
CONFIG_FILE="${CONFIG_FILE:-/etc/default/myapp}"
LOG_LEVEL="${LOG_LEVEL:-INFO}"
DRY_RUN=false
# Hilfsfunktion
show_help() {
cat << EOF
Usage: $0 [OPTIONS] -- [TARGET_ARGS]
OPTIONS:
-c, --config FILE Konfigurationsdatei (default: $CONFIG_FILE)
-l, --log-level LVL Log Level (default: $LOG_LEVEL)
-n, --dry-run Nur Simulation
-h, --help Diese Hilfe
Alle Argumente nach -- werden an das Zielskript weitergegeben.
EOF
}
# Parsing mit -- Separator
TARGET_ARGS=()
PARSE_TARGET=false
while [[ $# -gt 0 ]]; do
if [[ "$PARSE_TARGET" == true ]]; then
TARGET_ARGS+=("$1")
shift
continue
fi
case $1 in
-c|--config)
CONFIG_FILE="$2"
shift 2
;;
-l|--log-level)
LOG_LEVEL="$2"
shift 2
;;
-n|--dry-run)
DRY_RUN=true
shift
;;
-h|--help)
show_help
exit 0
;;
--)
PARSE_TARGET=true
shift
;;
*)
echo "Unbekannte Option: $1" >&2
show_help
exit 1
;;
esac
done
# Validierung
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "Konfigurationsdatei nicht gefunden: $CONFIG_FILE" >&2
exit 1
fi
# Ausführung
if [[ "$DRY_RUN" == true ]]; then
echo "DRY RUN: ./target-script.sh ${TARGET_ARGS[*]}"
else
./target-script.sh "${TARGET_ARGS[@]}"
fi
```
## Best Practices
### 1. Sichere Argumentbehandlung
```bash
# Verwende Arrays für Argumente
ARGS=()
while IFS= read -r -d '' arg; do
ARGS+=("$arg")
done < <(printf '%s\0' "$@")
# Sichere Weiterleitung
./target-script.sh "${ARGS[@]}"
```
### 2. Logging und Debugging
```bash
#!/bin/bash
DEBUG=${DEBUG:-false}
debug_log() {
if [[ "$DEBUG" == true ]]; then
echo "DEBUG: $*" >&2
fi
}
debug_log "Received arguments: $*"
debug_log "Passing to target: ${TARGET_ARGS[*]}"
```
### 3. Fehlerbehandlung
```bash
#!/bin/bash
set -euo pipefail # Strict mode
# Trap für Cleanup
cleanup() {
debug_log "Cleaning up..."
}
trap cleanup EXIT
# Prüfe ob Zielskript existiert
if [[ ! -x "$TARGET_SCRIPT" ]]; then
echo "Fehler: Zielskript '$TARGET_SCRIPT' nicht gefunden oder nicht ausführbar" >&2
exit 1
fi
# Führe aus und fange Exit-Code ab
if "$TARGET_SCRIPT" "$@"; then
debug_log "Zielskript erfolgreich ausgeführt"
else
exit_code=$?
echo "Zielskript fehlgeschlagen mit Exit-Code: $exit_code" >&2
exit $exit_code
fi
```
## Verwandte Konzepte
- [[Shell Scripting Best Practices]]
- [[BASH Argument Parsing]]
- [[Environment Variables in Shell Scripts]]
---
**Tags**: #bash #scripting #arguments #shell #automation
@@ -0,0 +1,132 @@
## Grundlegende Methoden
### 1. Einfache Variante mit `$0`
```bash
#!/bin/bash
SCRIPT_PATH="$0"
echo "Skript wurde aufgerufen als: $SCRIPT_PATH"
```
### 2. Absoluter Pfad des Skripts
```bash
#!/bin/bash
SCRIPT_PATH="$(realpath "$0")"
echo "Absoluter Pfad des Skripts: $SCRIPT_PATH"
```
### 3. Verzeichnis des Skripts ermitteln
```bash
#!/bin/bash
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
echo "Skript-Verzeichnis: $SCRIPT_DIR"
```
## Robuste Lösung für alle Szenarien
```bash
#!/bin/bash
# Funktion zur sicheren Ermittlung des Skript-Pfads
get_script_path() {
local source="${BASH_SOURCE[0]}"
# Auflösung von Symlinks
while [ -h "$source" ]; do
local dir="$(cd -P "$(dirname "$source")" && pwd)"
source="$(readlink "$source")"
[[ $source != /* ]] && source="$dir/$source"
done
echo "$(cd -P "$(dirname "$source")" && pwd)"
}
SCRIPT_DIR="$(get_script_path)"
SCRIPT_NAME="$(basename "$0")"
SCRIPT_FULL_PATH="$SCRIPT_DIR/$SCRIPT_NAME"
echo "Skript-Verzeichnis: $SCRIPT_DIR"
echo "Skript-Name: $SCRIPT_NAME"
echo "Vollständiger Pfad: $SCRIPT_FULL_PATH"
```
## Häufige Anwendungsfälle
### Relative Pfade vom Skript-Verzeichnis aus
```bash
#!/bin/bash
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
# Zugriff auf andere Dateien relativ zum Skript
CONFIG_FILE="$SCRIPT_DIR/config.conf"
LOG_DIR="$SCRIPT_DIR/logs"
# Prüfen ob Konfigurationsdatei existiert
if [ -f "$CONFIG_FILE" ]; then
echo "Konfiguration gefunden: $CONFIG_FILE"
fi
```
### Einbindung anderer Skripts
```bash
#!/bin/bash
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
# Andere Skripts aus dem gleichen Verzeichnis einbinden
source "$SCRIPT_DIR/common_functions.sh"
source "$SCRIPT_DIR/config.sh"
```
## Wichtige Unterschiede der Variablen
| Variable | Beschreibung | Beispiel |
|----------|--------------|----------|
| `$0` | Aufruf-Name des Skripts | `./script.sh` oder `/path/script.sh` |
| `${BASH_SOURCE[0]}` | Tatsächlicher Pfad (auch bei sourcing) | `/absolute/path/script.sh` |
| `$(dirname "$0")` | Verzeichnis des Aufrufs | `.` oder `/path` |
| `$(realpath "$0")` | Absoluter, aufgelöster Pfad | `/absolute/path/script.sh` |
## Besondere Situationen
### Bei gesourcten Skripts
```bash
# In gesourcten Skripts sollten Sie BASH_SOURCE verwenden
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
```
### Bei Symlinks
```bash
# Auflösung von Symlinks
SCRIPT_PATH="$(readlink -f "$0")"
SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
```
## Praktisches Beispiel
```bash
#!/bin/bash
# setup.sh - Installationsskript
# Ermittlung des Skript-Verzeichnisses
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
echo "Starte Installation..."
echo "Skript-Verzeichnis: $SCRIPT_DIR"
echo "Projekt-Root: $PROJECT_ROOT"
# Installation von Abhängigkeiten
pip install -r "$PROJECT_ROOT/requirements.txt"
# Kopieren von Konfigurationsdateien
cp "$SCRIPT_DIR/templates/config.ini" "$PROJECT_ROOT/config/"
echo "Installation abgeschlossen!"
```
## Tags
#bash #scripting #pfade #entwicklung
## Verwandte Themen
- [[BASH Grundlagen]]
- [[Dateisystem Navigation]]
- [[Skript Entwicklung Best Practices]]
+407
View File
@@ -0,0 +1,407 @@
Diese Anleitung führt dich praxisnah durch die wichtigsten Bootloader unter Linux **GRUB 2** (am weitesten verbreitet) und **systemd-boot** und zeigt, wie du Menüeinträge ausblendest, die **Timeout-Zeit** änderst, den **Standard-Eintrag** festlegst, **Kernel-Parameter** setzt, Themes nutzt u. v. m. Am Ende findest du auch Tipps für UEFI-Bootreihenfolge, Dual-Boot und Fehlerbehebung.
---
## 1) Welchen Bootloader habe ich BIOS/UEFI?
```bash
# UEFI oder BIOS?
[ -d /sys/firmware/efi ] && echo "UEFI" || echo "BIOS/Legacy"
# GRUB oder systemd-boot?
bootctl status 2>/dev/null | grep -q 'systemd-boot' && echo "systemd-boot" || echo "GRUB (sehr wahrscheinlich)"
```
- **GRUB 2**: Standard bei Ubuntu, Debian, Fedora, openSUSE, Arch (sofern nicht umgestellt).
- **systemd-boot**: Häufig bei minimalistischen Setups (Arch, Fedora/Silverblue, Pop!_OS, Manjaro-Varianten) nur im UEFI-Modus.
> **Wichtig:** **Bearbeite nie direkt** die generierte Datei `/boot/grub/grub.cfg`. Änderungen gehören in `/etc/default/grub` (GRUB) bzw. `/boot/loader/loader.conf` + `…/entries/*.conf` (systemd-boot), und **danach** wird die Konfiguration neu generiert.
---
## 2) GRUB 2 konfigurieren (die häufigste Variante)
### 2.1 Ort der Einstellungen
- Hauptdatei: `/etc/default/grub`
- Menüeinträge (automatisch generiert): `/boot/grub/grub.cfg`
- Regenerieren:
- Debian/Ubuntu: `sudo update-grub`
- Fedora/RHEL/openSUSE:
- BIOS: `sudo grub2-mkconfig -o /boot/grub2/grub.cfg`
- UEFI: `sudo grub2-mkconfig -o /boot/efi/EFI/<distro>/grub.cfg`
- Arch: `sudo grub-mkconfig -o /boot/grub/grub.cfg`
> Tipp: Mach vor Änderungen ein Backup:
> `sudo cp /etc/default/grub /etc/default/grub.bak.$(date +%F)`
### 2.2 Zeit bis zur automatischen Auswahl (Timeout)
In `/etc/default/grub` anpassen:
```ini
GRUB_TIMEOUT=2 # Sekunden bis Autostart
GRUB_TIMEOUT_STYLE=menu # "hidden" blendet das Menü aus (siehe unten)
```
- **Menü ausblenden**:
```ini
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
```
-> System bootet sofort, Menü erscheint **nur** wenn du beim Einschalten **Shift (BIOS)** oder **Esc (UEFI)** gedrückt hältst (je nach Firmware/Distro).
- **Menü immer zeigen**:
```ini
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=5
```
Danach Konfiguration neu generieren (siehe 2.1).
### 2.3 Standard-Eintrag festlegen
Variante A fester Index (0-basierend, **ändert sich bei Kernel-Updates ggf.**):
```ini
GRUB_DEFAULT=0
```
Variante B per Name (stabiler):
```ini
GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 6.10.5"
```
Variante C „zuletzt gebooteten“ Eintrag merken:
```ini
GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true
```
Einmalig einen anderen Eintrag für den **nächsten** Boot setzen:
```bash
sudo grub-reboot "Ubuntu, with Linux 6.10.5"
# oder nach Index:
sudo grub-reboot 2
```
### 2.4 Kernel-Parameter setzen (leiser, schneller, NVIDIA, etc.)
In `/etc/default/grub`:
```ini
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX="resume=UUID=<swap-uuid> mitigations=auto"
```
Häufige Parameter:
- `quiet splash` leiser Boot mit Grafiksplash (Plymouth).
- `nomodeset` Notfall bei Grafiktreibern.
- `nowatchdog` schaltet Watchdogs aus (Debug/Workarounds).
- `acpi_osi=` / `acpi_backlight=` Backlight-Probleme bei Laptops.
- `amd_pstate=active` / `intel_pstate=` CPU-Scaling steuern.
- `mitigations=off` (nur Test!) Sicherheits-Mitigations deaktivieren.
> Nach Änderung immer Konfiguration regenerieren (2.1).
### 2.5 Einträge ausblenden / aufräumen
- **Andere OS suchen (Dual-Boot)** wird teils aus Sicherheitsgründen deaktiviert. Falls Windows fehlt:
```ini
GRUB_DISABLE_OS_PROBER=false
```
Danach:
```bash
sudo update-grub # bzw. grub2-mkconfig ...
```
- Bestimmte **Recovery-Einträge** ausblenden: In vielen Distros via Paket `grub-customizer` oder durch eigene Skripte unter `/etc/grub.d/` (fortgeschritten).
Minimal: Notfalls Einträge in `/etc/grub.d/40_custom` definieren und Standardliste ausblenden (nicht empfohlen, weil Updates überschreiben können).
### 2.6 Themes, Auflösung und Optik
In `/etc/default/grub`:
```ini
GRUB_GFXMODE=1920x1080
GRUB_GFXPAYLOAD_LINUX=keep
GRUB_THEME="/boot/grub/themes/mein-theme/theme.txt"
```
- Auflösung prüfen: In der GRUB-Konsole `videoinfo` eintippen (interaktiv).
- Themes bekommst du aus Paketquellen (z. B. `grub-theme-*`) oder GitHub. Theme in `/boot/grub/themes/...` ablegen.
### 2.7 Sonderfälle (UEFI-Pfad, BIOS, LUKS, Btrfs)
- **UEFI**: Achte beim `grub2-mkconfig` auf den richtigen **Ausgabepfad** (siehe 2.1).
- **Vollverschlüsselt (LUKS)**: Kernel-Parameter und initramfs müssen passen (meist automatisch korrekt).
- **Btrfs-Snapshots** (z. B. mit Snapper): Paket **grub-btrfs** integriert Snapshots ins Menü.
- **Sichere Bootreihenfolge**: Siehe Abschnitt 4 (efibootmgr).
---
## 3) systemd-boot konfigurieren (UEFI-Only, sehr schlank)
### 3.1 Dateien & Struktur
- Hauptdatei: `/boot/loader/loader.conf`
- Einträge: `/boot/loader/entries/*.conf` (eine Datei pro Eintrag)
- Kernel/Initrd liegen meist unter `/boot` oder `/efi`.
### 3.2 Menü ausblenden, Timeout, Standard
`/boot/loader/loader.conf`:
```ini
timeout 2 # Sekunden (0 = sofort)
default arch # oder: @saved
editor no # verhindert Bearbeiten im Menü
console-mode auto # Grafikmodus: auto, 0..4
```
- **Menü ausblenden**: `timeout 0`
-> Menü erscheint bei **gedrückter Leertaste** oder wenn mehrere Einträge vorhanden sind (je nach Firmware/Distribution).
- **Zuletzt gebooteten Eintrag merken**: `default @saved`
Beim Booten auswählen; systemd-boot speichert die Wahl in `loader/`.
### 3.3 Einträge bearbeiten
Beispiel `/boot/loader/entries/arch.conf`:
```ini
title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options root=UUID=<root-uuid> rw quiet splash
```
- **Kernel-Parameter** hängst du einfach an `options` an.
- Mehrere `initrd` Zeilen sind erlaubt (z. B. Microcode + initramfs).
### 3.4 Kernel installieren/aktualisieren
- Viele Distros nutzen `kernel-install` Hooks, die automatisch passende `entries/*.conf` erzeugen.
- Ansonsten Einträge manuell pflegen (simpel und transparent).
---
## 4) UEFI-Bootreihenfolge & Dual-Boot
### 4.1 Bootreihenfolge mit `efibootmgr`
Liste anzeigen:
```bash
sudo efibootmgr
```
Reihenfolge setzen (Beispiel, IDs anpassen):
```bash
sudo efibootmgr -o 0003,0001,0002
```
**GRUB** oder **systemd-boot** sollte ganz vorn stehen.
Ein einzelnes Boot-Target (z. B. Windows) **einmalig** booten:
```bash
sudo efibootmgr -n 0002
```
### 4.2 Windows fehlt im Menü?
- Bei **GRUB**: `GRUB_DISABLE_OS_PROBER=false` (siehe 2.5) und neu generieren.
- Bei **systemd-boot**: eigenen `windows.conf` Eintrag unter `entries/` anlegen oder die automatische Erkennung der Distribution nutzen.
---
## 5) Häufige Aufgaben Schritt-für-Schritt
### A) Menü ausblenden & Sofort-Boot (GRUB)
1. `sudo nano /etc/default/grub`
2. Setze:
```ini
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
```
3. `sudo update-grub` (oder passendes `grub*-mkconfig`)
4. Test: Reboot, ggf. **Shift/Esc** halten, um das Menü zu zeigen.
### B) Timeout auf 5 s und Standard-Kernel merken (GRUB)
1. `/etc/default/grub`:
```ini
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=5
GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true
```
2. Regenerieren.
3. Nächster Boot merkt sich deine Auswahl automatisch.
### C) Ruhiger, schneller Boot mit Splash (GRUB)
1. `/etc/default/grub`:
```ini
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
```
2. Optional Plymouth-Theme installieren.
3. Regenerieren und neu starten.
### D) systemd-boot: Menü 1 s, zuletzt Gebootetes merken
1. `sudoedit /boot/loader/loader.conf`:
```ini
timeout 1
default @saved
editor no
```
2. Reboot, Auswahl wird gemerkt.
---
## 6) Sicherheit, Recovery & Wartung
- **Secure Boot**: Mit GRUB in der Regel via `shim` signiert bei eigenen Kernel/Modulen ggf. MOK-Signatur nötig. systemd-boot lädt nur signierte Images, wenn Secure Boot aktiv ist.
- **Recovery-Pfad**: Halte mindestens einen **nicht-minimalen** Kernel-Eintrag ohne aggressive Parameter bereit (ohne `nomodeset`, ohne `mitigations=off` etc.).
- **Backups**: Sichere `/etc/default/grub`, `loader.conf` und eigene `entries/*.conf`.
- **Fallback-Boot**: Notiere einen **UEFI-One-Shot** Befehl (`efibootmgr -n <ID>`), falls das Menü einmal nicht erscheint.
---
## 7) Troubleshooting (schnelle Checks)
- GRUB-Menü erscheint nicht:
- Firmware zeigt direkt Windows → Reihenfolge mit `efibootmgr` korrigieren.
- `GRUB_TIMEOUT_STYLE=hidden`? → Temporär **Shift/Esc** beim Start.
- Neue Kernel erscheinen nicht:
- Nach Updates `update-grub` / `grub*-mkconfig` ausgeführt?
- Pfad für UEFI-Ausgabe korrekt?
- Dual-Boot-Einträge fehlen:
- `os-prober` aktivieren (`GRUB_DISABLE_OS_PROBER=false`), dann neu generieren.
- Schwarzer Bildschirm nach Grafiktreiber-Wechsel:
- Temporär `nomodeset` im Bootmenü ergänzen (e), dann dauerhaft in `GRUB_CMDLINE_LINUX_DEFAULT`.
---
## 8) Nützliche Befehle (Cheatsheet)
```bash
# GRUB neu generieren (Debian/Ubuntu)
sudo update-grub
# GRUB neu generieren (UEFI, Fedora-Beispiel)
sudo grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg
# Standard-Eintrag nur für den nächsten Boot (GRUB)
sudo grub-reboot 2
sudo grub-reboot "Advanced options for Ubuntu>Ubuntu, with Linux 6.10.5"
# Zuletzt gebooteten Eintrag merken (Konfig siehe oben)
# -> einfach normal auswählen; GRUB speichert es.
# systemd-boot Status
bootctl status
# UEFI Boots verwalten
sudo efibootmgr
sudo efibootmgr -o 0003,0001,0002
sudo efibootmgr -n 0002 # One-shot
# Welche Auflösungen unterstützt GRUB?
# (in GRUB-Konsole: drücke 'c', dann)
videoinfo
```
---
## 9) Empfehlung nach Use-Case
- **Einsteiger / klassische Desktop-Distro** → **GRUB 2** beibehalten, Timeout 25 s, `saved`-Default, `quiet splash`.
- **Schlanke, transparente Setups (UEFI)** → **systemd-boot**: `timeout 1`, `default @saved`.
- **Dual-Boot mit Windows** → GRUB 2 + `os-prober` aktivieren; in UEFI die Reihenfolge mit `efibootmgr` sichern.
- **Schneller „kioskartiger“ Boot** → Menü verstecken (`hidden/0` bzw. `timeout 0`) und Hotkey kennen (Shift/Esc/Leertaste).
---
Wenn du mir deine Distribution und dein Ziel (z. B. „Menü vollständig verstecken“, „Windows hinzufügen“, „Splash aktivieren“) nennst, schreibe ich dir die **exakten** Befehle für dein System in einem kleinen, kopierfertigen Block.
@@ -0,0 +1,85 @@
Alles klar 👍 hier eine **allgemeine Schritt-für-Schritt-Anleitung**, wie du unter [[Linux]] mit `dd` einen **bootfähigen USB-Stick aus _beliebigen_ ISO-Dateien** erstellst:
---
## 🔹 Bootfähigen USB-Stick mit `dd` erstellen
### 1. ISO-Datei bereitlegen
Speichere die ISO-Datei in einem bekannten Pfad, z. B.:
```
~/Downloads/dein.iso
```
---
### 2. USB-Stick einstecken und Gerät identifizieren
Liste alle Laufwerke:
```bash
lsblk
```
oder
```bash
sudo fdisk -l
```
Beispielausgabe:
```
sda 500G # deine interne Festplatte
sdb 16G # dein USB-Stick
```
👉 Der Stick ist hier `/dev/sdb`.
⚠️ Wichtig: **Niemals eine Partition (z. B. `/dev/sdb1`) wählen, immer das ganze Gerät (`/dev/sdb`).**
---
### 3. ISO auf den Stick schreiben
Ersetze die Platzhalter:
```bash
sudo dd if=/pfad/zur/datei.iso of=/dev/sdX bs=4M status=progress oflag=sync
```
- `if=` → Pfad zur ISO-Datei (z. B. `~/Downloads/dein.iso`)
- `of=` → dein USB-Gerät (z. B. `/dev/sdb`)
- `bs=4M` → Blockgröße, sorgt für schnelleres Schreiben
- `status=progress` → zeigt den Fortschritt
- `oflag=sync` → sorgt für sauberes Schreiben
**Beispiel:**
```bash
sudo dd if=~/Downloads/bazzite.iso of=/dev/sdb bs=4M status=progress oflag=sync
```
---
### 4. Schreibvorgang abschließen
Bevor du den Stick abziehst:
```bash
sync
sudo eject /dev/sdb
```
---
### 5. Stick zum Booten nutzen
Jetzt kannst du den Stick in den Zielrechner stecken, im BIOS/UEFI den Stick auswählen und davon booten.
---
@@ -0,0 +1,76 @@
How can I disable the [[kvm]] Kernel in [[Linux]], so that I can launch a virtual machine in VirtualBox
---
When you run [[VirtualBox]] on a Linux host, it can conflict with the **KVM kernel modules** (`kvm` and `kvm_intel` or `kvm_amd`). VirtualBox doesnt use KVM, and if those modules are loaded, they can prevent VirtualBox VMs from starting properly.
To disable KVM, you can either **temporarily unload** the modules or **permanently blacklist** them.
---
### 🔹 Option 1: Temporarily Disable KVM
Run the following commands (with root privileges):
```bash
sudo modprobe -r kvm_intel
sudo modprobe -r kvm_amd
sudo modprobe -r kvm
```
- If your CPU is Intel, unload `kvm_intel`.
- If your CPU is AMD, unload `kvm_amd`.
- Then unload the generic `kvm` module.
This will disable KVM until the next reboot.
---
### 🔹 Option 2: Permanently Disable KVM
To prevent KVM from loading on boot, blacklist the modules:
1. Create a blacklist file:
```bash
sudo nano /etc/modprobe.d/blacklist-kvm.conf
```
2. Add these lines:
```
blacklist kvm
blacklist kvm_intel
blacklist kvm_amd
```
3. Save and exit.
4. Update initramfs (on some distros, required):
```bash
sudo update-initramfs -u
```
5. Reboot your system.
---
### 🔹 Verify
After reboot (or unloading), check that no KVM modules are loaded:
```bash
lsmod | grep kvm
```
If the output is empty, KVM is disabled and VirtualBox should work.
---
⚠️ **Note:** If you ever want to use QEMU/KVM again, youll need to remove those blacklist entries and reboot.
Would you like me to also show you how to make VirtualBox auto-unload KVM just when you launch a VM (without disabling it system-wide)? That way, you can keep using both VirtualBox and KVM on the same system.
@@ -0,0 +1,418 @@
Hier ist ein umfassendes Shell-Skript für die Installation von DisplayLink-Treibern unter Linux:
```bash
#!/bin/bash
# DisplayLink Driver Installation Script for Linux
# Author: Assistant
# Version: 1.0
# Date: $(date +%Y-%m-%d)
set -e
# Farben für Output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging
LOG_FILE="/var/log/displaylink-install.log"
exec > >(tee -a "$LOG_FILE")
exec 2>&1
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} DisplayLink Driver Installation Script${NC}"
echo -e "${BLUE}========================================${NC}"
# Funktionen
log() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] INFO: $1${NC}"
}
warn() {
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
}
error() {
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
}
check_root() {
if [[ $EUID -ne 0 ]]; then
error "Dieses Skript muss als root ausgeführt werden!"
exit 1
fi
}
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
DISTRO=$ID
VERSION=$VERSION_ID
log "Distribution erkannt: $PRETTY_NAME"
else
error "Distribution konnte nicht erkannt werden"
exit 1
fi
}
install_dependencies() {
log "Installiere benötigte Abhängigkeiten..."
case $DISTRO in
ubuntu|debian)
apt update
apt install -y wget curl unzip dkms build-essential \
linux-headers-$(uname -r) git libdrm-dev \
x11-xserver-utils mesa-utils
;;
fedora|centos|rhel)
if command -v dnf &> /dev/null; then
dnf install -y wget curl unzip dkms gcc make \
kernel-devel-$(uname -r) git libdrm-devel \
xrandr mesa-utils
else
yum install -y wget curl unzip dkms gcc make \
kernel-devel-$(uname -r) git libdrm-devel \
xrandr mesa-utils
fi
;;
opensuse*)
zypper install -y wget curl unzip dkms gcc make \
kernel-default-devel git libdrm-devel \
xrandr Mesa-utils
;;
arch|manjaro)
pacman -Sy --noconfirm wget curl unzip dkms base-devel \
linux-headers git libdrm xorg-xrandr mesa-utils
;;
*)
warn "Unbekannte Distribution. Versuche generische Installation..."
;;
esac
}
download_displaylink_driver() {
log "Lade neueste DisplayLink-Treiber herunter..."
# Erstelle temporäres Verzeichnis
TEMP_DIR=$(mktemp -d)
cd "$TEMP_DIR"
# DisplayLink Download URL (Ubuntu 22.04 kompatibel)
DRIVER_VERSION="5.8.0-63.33"
DRIVER_URL="https://www.synaptics.com/sites/default/files/Ubuntu/pool/stable/main/all/synaptics-repository-keyring.deb"
# Alternative: Verwende evdi Repository
log "Installiere EVDI (Extensible Virtual Display Interface)..."
git clone https://github.com/DisplayLink/evdi.git
cd evdi
make && make install
cd ..
# Offizieller DisplayLink Treiber Download
OFFICIAL_URL="https://www.synaptics.com/sites/default/files/Ubuntu/pool/stable/main/all/"
# Neueste verfügbare Version ermitteln
log "Ermittle neueste verfügbare Treiberversion..."
# Fallback: Direkte Installation über Repository
case $DISTRO in
ubuntu|debian)
# Füge DisplayLink Repository hinzu
wget -O - https://www.synaptics.com/sites/default/files/Ubuntu/displaylink-debian-ubuntu-signing-key.pub | apt-key add -
echo "deb https://www.synaptics.com/sites/default/files/Ubuntu/ $(lsb_release -cs) stable" > /etc/apt/sources.list.d/displaylink.list
apt update
apt install -y displaylink-driver
;;
*)
# Manuelle Installation für andere Distributionen
DRIVER_FILE="displaylink-driver-5.8.0-63.33.zip"
log "Lade $DRIVER_FILE herunter..."
# Beispiel-Download (URL muss aktualisiert werden)
if ! wget -q --spider "https://www.displaylink.com/downloads/file?id=1768"; then
warn "Automatischer Download fehlgeschlagen. Manuelle Installation erforderlich."
log "Bitte laden Sie den neuesten Treiber von https://www.displaylink.com/downloads/ubuntu herunter"
return 1
fi
;;
esac
}
install_displaylink_driver() {
log "Installiere DisplayLink-Treiber..."
# Stoppe potentiell laufende Services
systemctl stop dlm.service 2>/dev/null || true
systemctl stop displaylink-driver.service 2>/dev/null || true
case $DISTRO in
ubuntu|debian)
# Bereits über Repository installiert
log "Treiber über Repository installiert"
;;
*)
# Manuelle Installation
if [ -f "displaylink-driver-*.run" ] || [ -f "DisplayLink*.run" ]; then
chmod +x DisplayLink*.run 2>/dev/null || chmod +x displaylink-driver-*.run
./DisplayLink*.run --noexec --target displaylink-driver 2>/dev/null || ./displaylink-driver-*.run --noexec --target displaylink-driver
cd displaylink-driver
./displaylink-installer.sh install
fi
;;
esac
# EVDI Modul laden
modprobe evdi || warn "EVDI Modul konnte nicht geladen werden"
}
configure_services() {
log "Konfiguriere SystemD Services..."
# DisplayLink Service aktivieren
systemctl enable dlm.service 2>/dev/null || systemctl enable displaylink-driver.service 2>/dev/null || true
# Erstelle Custom Service falls nötig
if [ ! -f "/etc/systemd/system/displaylink.service" ]; then
cat > /etc/systemd/system/displaylink.service << EOF
[Unit]
Description=DisplayLink Manager Service
After=display-manager.service
[Service]
Type=forking
ExecStartPre=/sbin/modprobe evdi
ExecStart=/opt/displaylink/DisplayLinkManager
ExecStop=/opt/displaylink/DisplayLinkManager --stop
Restart=always
RestartSec=5
[Install]
WantedBy=graphical.target
EOF
systemctl daemon-reload
systemctl enable displaylink.service
fi
}
fix_common_issues() {
log "Behebe bekannte Probleme..."
# Problem 1: EVDI Modul beim Boot laden
if ! grep -q "evdi" /etc/modules; then
echo "evdi" >> /etc/modules
log "EVDI zu /etc/modules hinzugefügt"
fi
# Problem 2: Xorg Konfiguration
mkdir -p /etc/X11/xorg.conf.d/
cat > /etc/X11/xorg.conf.d/20-displaylink.conf << EOF
Section "OutputClass"
Identifier "DisplayLink"
MatchDriver "evdi"
Driver "modesetting"
Option "AccelMethod" "none"
EndSection
EOF
# Problem 3: Udev Regeln
cat > /etc/udev/rules.d/99-displaylink.rules << EOF
# DisplayLink USB devices
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="17e9", TAG+="systemd", ENV{SYSTEMD_WANTS}="displaylink.service"
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="17e9", ATTR{idProduct}=="*", RUN+="/bin/systemctl start displaylink.service"
EOF
udevadm control --reload-rules
# Problem 4: Permissions
usermod -a -G plugdev $SUDO_USER 2>/dev/null || true
# Problem 5: Wayland Kompatibilität (für GNOME)
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
warn "Wayland erkannt. DisplayLink funktioniert besser mit X11."
log "Erstelle GDM Custom Config für X11..."
mkdir -p /etc/gdm3
cat > /etc/gdm3/custom.conf << EOF
[daemon]
WaylandEnable=false
DefaultSession=gnome-xorg
EOF
fi
}
check_installation() {
log "Überprüfe Installation..."
# Service Status
if systemctl is-active --quiet dlm.service || systemctl is-active --quiet displaylink-driver.service || systemctl is-active --quiet displaylink.service; then
log "DisplayLink Service läuft erfolgreich"
else
warn "DisplayLink Service läuft nicht. Starte Service..."
systemctl start displaylink.service 2>/dev/null || systemctl start dlm.service 2>/dev/null || true
fi
# Modul Status
if lsmod | grep -q evdi; then
log "EVDI Kernel Modul erfolgreich geladen"
else
warn "EVDI Kernel Modul nicht geladen. Versuche manuelles Laden..."
modprobe evdi || error "EVDI Modul konnte nicht geladen werden"
fi
# USB Geräte check
if lsusb | grep -i displaylink; then
log "DisplayLink USB-Gerät erkannt"
else
warn "Kein DisplayLink USB-Gerät erkannt. Schließen Sie ein Gerät an."
fi
}
create_troubleshooting_script() {
log "Erstelle Troubleshooting-Skript..."
cat > /usr/local/bin/displaylink-troubleshoot << 'EOF'
#!/bin/bash
echo "=== DisplayLink Troubleshooting ==="
echo ""
echo "1. Service Status:"
systemctl status displaylink.service dlm.service displaylink-driver.service 2>/dev/null || echo "Services nicht gefunden"
echo ""
echo "2. Kernel Module:"
lsmod | grep evdi || echo "EVDI Modul nicht geladen"
echo ""
echo "3. USB Devices:"
lsusb | grep -i displaylink || echo "Keine DisplayLink Geräte gefunden"
echo ""
echo "4. Displays:"
xrandr --listproviders 2>/dev/null || echo "Xrandr nicht verfügbar"
echo ""
echo "5. Logs:"
journalctl -u displaylink.service --no-pager -n 10 2>/dev/null || echo "Keine Service Logs"
echo ""
echo "=== Schnelle Fixes ==="
echo "Service neu starten:"
echo " sudo systemctl restart displaylink.service"
echo ""
echo "Modul neu laden:"
echo " sudo modprobe -r evdi && sudo modprobe evdi"
echo ""
echo "Display erkennung:"
echo " xrandr --setprovideroutputsource 1 0 && xrandr --auto"
EOF
chmod +x /usr/local/bin/displaylink-troubleshoot
log "Troubleshooting-Skript erstellt: /usr/local/bin/displaylink-troubleshoot"
}
cleanup() {
log "Räume temporäre Dateien auf..."
cd /
rm -rf "$TEMP_DIR" 2>/dev/null || true
}
main() {
log "Starte DisplayLink Installation..."
check_root
detect_distro
install_dependencies
download_displaylink_driver
install_displaylink_driver
configure_services
fix_common_issues
check_installation
create_troubleshooting_script
cleanup
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} Installation abgeschlossen!${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
log "Installation erfolgreich abgeschlossen!"
log "Bitte starten Sie das System neu für beste Ergebnisse."
log "Bei Problemen verwenden Sie: displaylink-troubleshoot"
echo ""
echo -e "${YELLOW}Nächste Schritte:${NC}"
echo "1. System neu starten"
echo "2. DisplayLink Gerät anschließen"
echo "3. Monitor-Konfiguration mit: xrandr --auto"
echo "4. Bei Problemen: displaylink-troubleshoot ausführen"
}
# Trap für Cleanup
trap cleanup EXIT
# Hauptfunktion ausführen
main "$@"
```
## Zusätzliche Konfigurationsdateien
### 1. Desktop-Shortcut für schnelle Display-Konfiguration:
```bash
#!/bin/bash
# Erstelle Desktop-Shortcut
cat > ~/Desktop/configure-displays.desktop << EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=Configure DisplayLink Displays
Comment=Configure external displays via DisplayLink
Exec=bash -c 'xrandr --setprovideroutputsource 1 0 && xrandr --auto && notify-send "Displays konfiguriert"'
Icon=preferences-desktop-display
Terminal=false
Categories=System;Settings;
EOF
chmod +x ~/Desktop/configure-displays.desktop
```
### 2. Automatische Display-Konfiguration bei USB-Anschluss:
```bash
# Udev-Regel für automatische Konfiguration
cat > /etc/udev/rules.d/99-displaylink-autoconfig.rules << EOF
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="17e9", RUN+="/usr/local/bin/displaylink-autoconfig.sh"
EOF
# Autoconfig-Skript
cat > /usr/local/bin/displaylink-autoconfig.sh << 'EOF'
#!/bin/bash
sleep 3
export DISPLAY=:0
xrandr --setprovideroutputsource 1 0
xrandr --auto
EOF
chmod +x /usr/local/bin/displaylink-autoconfig.sh
```
## Verwendung:
1. Skript als root ausführen:
```bash
sudo bash displaylink-install.sh
```
2. Nach der Installation System neu starten
3. Bei Problemen Troubleshooting ausführen:
```bash
displaylink-troubleshoot
```
Das Skript automatisiert die komplette Installation und behebt die häufigsten Probleme mit DisplayLink-Treibern unter verschiedenen Linux-Distributionen.
@@ -0,0 +1,140 @@
Kurz gesagt: **Nein GNU Stow führt keine Skripte aus.**
Und das ist auch Absicht 🙂
GNU Stow macht **nur eine Sache**:
> Es erzeugt und entfernt Symlinks.
Keine Hooks.
Keine Post-Deploy-Skripte.
Keine Automatik.
---
# 🧠 Warum ist das so?
Stow ist bewusst:
* minimalistisch
* deterministisch
* side-effect-frei
Dadurch bleibt dein Setup transparent und reproduzierbar.
---
# ✅ Aber: Man kann es kombinieren
Wenn du beim „Deploy“ zusätzlich Dinge tun willst (z. B. Monitor-Symlink setzen, Pakete installieren, Cache leeren, etc.), gibt es saubere Lösungen:
---
# 🔹 Lösung 1: Bootstrap-Script (empfohlen)
Du schreibst dir ein Script wie:
```bash
#!/bin/bash
set -e
cd ~/dotfiles
echo "→ Stowing configs"
stow hypr
stow waybar
stow zsh
echo "→ Setting monitor config"
ln -sf desktop.conf hypr/.config/hypr/monitors/current.conf
echo "→ Reloading Hyprland"
hyprctl reload
```
Dann einfach:
```bash
./install.sh
```
💡 Das ist die professionellste Lösung.
---
# 🔹 Lösung 2: Hostname-basierte Logik im Script
```bash
HOST=$(hostname)
if [[ "$HOST" == "desktop" ]]; then
ln -sf desktop.conf hypr/.config/hypr/monitors/current.conf
elif [[ "$HOST" == "laptop" ]]; then
ln -sf laptop.conf hypr/.config/hypr/monitors/current.conf
fi
```
Dann musst du nichts manuell wählen.
---
# 🔹 Lösung 3: Makefile (sehr elegant)
Beispiel:
```make
install:
stow hypr
stow waybar
./scripts/select-monitor.sh
```
Dann:
```bash
make install
```
Sehr beliebt in Dotfile-Repos.
---
# 🔹 Lösung 4: „echte“ Dotfile-Manager
Wenn du wirklich Logik + Templates willst:
* chezmoi
* yadm
Diese können:
* Hostname erkennen
* Variablen verwenden
* Templates generieren
* Skripte ausführen
Aber sie sind komplexer als Stow.
---
# 🎯 Empfehlung für dich (Hyprland + mehrere Systeme)
Da du:
* Monitor-Configs pro System brauchst
* wahrscheinlich Arch nutzt
* modular arbeiten willst
👉 **Stow + Bootstrap-Script** ist die perfekte Balance.
---
# 💬 Kurzantwort auf deine Frage
| Frage | Antwort |
| ------------------------ | ----------------- |
| Führt Stow Skripte aus? | ❌ Nein |
| Kann man es kombinieren? | ✅ Ja |
| Beste Praxis? | Stow + install.sh |
---
@@ -0,0 +1,23 @@
Für Integration von Programmen ins Startmenü
Lege Datei `some_awesome_app.desktop` mit folgendem Inhalt:
```bash
[Desktop Entry]
Name=Name of Application
GenericName=Super generic Name
Comment=This is an awesome application
Exec=/path/to/executable
Icon=/path/to/icon
Type=Application
Terminal=false
Categories=Utility;Application;
```
- Für aktuellen Nutzer: `~/.local/share/applications`
- Systemweit (`sudo` beim Anlegen nicht vergessen): `/usr/share/applications`
## Weitere Felder
```bash
# ...
Encoding=UTF-8
Version=1.0
StartupWMClass=ExampleApp
```
+29
View File
@@ -0,0 +1,29 @@
Ich hab ein bisschen recherchiert und ein paar gute Optionen gefunden — sowohl Open Source / native [[Linux]]-PlugIns als auch Tipps, wie man bewährte Windows/Proprietär-Drum-Libraries unter Linux laufen lassen kann. Wenn du willst, kann ich auch ein paar kommerzielle Kandidaten heraussuchen, die unter Linux getestet sind. Hier zunächst ein Überblick:
---
## 🎯 Native bzw. sehr gut unter Linux laufende Drum-Sampler / Drum-PlugIns
Diese Tools/Plugins laufen nativ unter Linux / oder haben Linux-Versionen, und sind gute Alternativen oder Ergänzungen zu EZ-Drummer:
| Plugin / Tool | Format / Linux-Support | Vorteile | Einschränkungen / Punkte, auf die man achten sollte |
| -------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[[DrumGizmo]]** | VSTi & LV2 Version, stand-alone auch; multichannel, multilayered. | Sehr gute Drumsounds mit mehreren Velocity-Schichten; man kann einzelne Mikros / Kanäle nutzen, also gute Flexibilität beim Mischen. | Die Drums werden nicht immer sofort so fett wie bei kommerziellen Tools; erfordert gutes Setup (Routing, Mix) und ggf. eigene Kits. |
| **[[LinuxSampler]]** | VST, LV2, DSSI etc. | Sehr mächtig, kann große Sample-Libraries nutzen; volle Kontrolle. | Bedienung nicht so „slick“ wie bei Markenprodukten, evtl. Lernkurve; große Sample-Bibliotheken nötig für gute Vielfalt. |
| **[[drumkv1]]** | LV2 / Standalone (JACK / ALSA MIDI)-Client; native Linux. | Leichtgewichtig, einfach einzurichten; ideal wenn man nicht so viele Features braucht. | Kein High-End-Drumkit mit riesiger Bibliothek; klingt eher sauber/klassisch, nicht unbedingt super „produziert“. |
| **Geonkick** | Synthesizer Drum / Percussion; VST3 und LV2 auf Linux. | Sehr flexibel bei perkussiven Sounds, interessant wenn man eigene, eher synthetische Drums bauen will. | Eher auf Drum-Synthese fokussiert, nicht ein „Drumkit-Sammler“ mit kompletten Kits wie bei EZ Drummer etc. Kann sein, dass man noch eigene Samples oder Bearbeitung braucht, damits wirklich gut passt. |
| **Sitala** | Stand-alone / PlugIn Version, unterstützt Linux in früheren Versionen (V1) zumindest; sehr leicht zu bedienen. | Schnelle Ergebnisse; ideal für kreative Ideen, wenn man schnell Drums triggern möchte; UI ist simpel und effizient. | Wenn man ganz spezifische Kits oder sehr aufwendige Layer/Velocity braucht, stößt man evtl. an Grenzen; neuere Versionen evtl. eingeschränkter Linux-Support. |
---
## 🔧 Kommerzielle PlugIns / Windows-Drum-Libraries unter Linux verwenden
Wenn dir die Qualität / Klang von EZ-Drummer oder ähnlichen wichtig ist und du nicht komplett auf native Alternativen umsteigen willst, hier ein paar Tipps, wie man kommerzielle Plugins unter Linux zuverlässiger nutzen kann:
- **Wine + VST Bridge / yabridge**: Viele Nutzer berichten, dass Windows-VSTs mit yabridge in Reaper unter Linux ziemlich gut laufen. Manche hatten Probleme mit Soundlibrary-Pfaden etc., aber wenn man das richtig einrichtet (z. B. Wineprefix, korrekter Pfad zu den Samples), dann klappts oft sehr gut.
- **Reaper Native + Linux-VST Unterstützung**: Die Linux-Version von Reaper kann native Linux VSTs nutzen, und mit yabridge auch Windows VSTs; das heißt, du kannst beides kombinieren.
- **Sample Libraries exportieren / konvertieren**: Wenn du z. B. Libraries hast, die in einem Format sind, das EZ-Drummer verwendet, könnte man prüfen, ob man die Samples in ein universelles Format bringt (z.B. SFZ) und dann mit einem Sampler wie LinuxSampler oder DrumGizmo nutzen. Das erspart Abhängigkeiten.
---
Wenn du möchtest, kann ich ein paar **kommerziell verfügbare Drum-PlugIns** heraussuchen, die nachweislich unter Linux + Reaper stabil laufen, inkl. Preis & Klangbeispiele, damit du vergleichen kannst? Möchtest du das?
@@ -0,0 +1,32 @@
Kann ich in einer [[Linux]] Konsole die komplette Eingabe auf einmal löschen? (z.B. wenn man sich beim Blättern durch die Historie oder beim Scuehn mit `STRG-R` "verrannt" hat)?
---
Ja, das geht 😊 in der Linux-Shell (z. B. Bash, Zsh) kannst du mit **einem Shortcut die ganze Eingabezeile löschen**, ohne Zeichen für Zeichen löschen zu müssen:
- **`Strg-u`**
Löscht den gesamten Text von der aktuellen Cursorposition bis zum Zeilenanfang.
Wenn der Cursor am Ende der Zeile steht (Standardfall), verschwindet die ganze Eingabe.
Weitere nützliche "Kill"-Shortcuts in der Bash/Zsh:
- `Strg-k` → löscht von der Cursorposition bis zum Zeilenende
- `Strg-w` → löscht das Wort links vom Cursor
- `Strg-y` → fügt das zuletzt Gelöschte wieder ein (ähnlich "Paste")
Wenn du dich mit **`Strg-r` (Reverse Search)** "verrannt" hast:
- Einfach **`Strg-g`** drücken → bricht die History-Suche ab und bringt dich zurück in eine leere Eingabezeile.
👉 Falls du wirklich _immer_ eine komplett neue, leere Zeile willst, ist die schnellste Kombination:
- `Strg-u` (Cursor am Ende) oder
- `Strg-g` (falls du gerade in einer History-Suche bist).
Willst du, dass ich dir eine kleine Übersicht als "Spickzettel" für Bash/Zsh-Shortcuts schreibe?
+272
View File
@@ -0,0 +1,272 @@
Ich bin auf der Suche nach einer guten Software für meine MP3 Musiksammlung in Linux, mit die Synchronisation mit meinem Android Handy gut funktioniert.
### Hintergrund
Bisher habe ich als Ex-Windows-Nutzer das Programm "Media-Monkey" in der Pro Version verwendet, d.h. auf dem PC und dem Handy mit der gleichnamigen App.
### Anfrage
Bitte zeige mir gute Alternativen, bestehend aus Linux Programm für PC und Android App für Handy.
### Anforderungen:
* Flexible Organisation der Library nach Benutzerdefinierten Kriterien (z.B. Album Artist, Genre, Album, etc.)
* Bearbeitungsmöglichkeiten aller Song Infos
* Bewertungssystem und Verschlagwortung
* Playlisten: statisch und dynamsisch (d.h. regelbasiert)
* Leichte Synchronisierbarkeit zwischen Rechner und Handy:
* Änderungen an Metadaten, insbes. "Last Played" werden in beide Richtungen übernommen
* Möglichkeit die Bitrate der MP3s beim Synchronisieren anzupassen (z.B. um Speicherplatz auf Handy zu sparen)
* Synchronisation kabelgebunden oder über WLAN
### Optionale Anforderungen
* Möglichkeit, fehlende Metadaten aus WWW zu ergänzen
* Erstellung von Benutzerdefinierten Metadaten Feldern, z.B. als Berechnung aus anderen Feldern
---
---
Super, danke für die präzise Beschreibung das hilft sehr!
Ich fasse mal die Landschaft für dich zusammen: es gibt unter Linux kein exaktes 1:1-Pendant zu **MediaMonkey**, aber einige Kombinationen aus Desktop-Software + Android-App können sehr nahe herankommen.
---
## 1. **MusicBee (via Wine) + Gonemad / PowerAmp (Android)**
- **Linux (Wine):** MusicBee läuft recht stabil unter Wine. Viele Ex-MediaMonkey-User nutzen es als Ersatz, weil es die meisten Features (flexible Library, Tags, Bewertungen, Smart-Playlists, Metadaten aus dem Netz) abdeckt.
- **Android:** Keine eigene App, aber Sync mit **GoneMAD** oder **PowerAmp** möglich. Mit Tools wie `syncthing` oder `Resilio Sync` kannst du Library, Ratings & Playcounts abgleichen.
- **Pro:** Funktionsumfang fast wie MediaMonkey.
- **Contra:** Keine native Linux-App, Integration Handy↔PC muss manuell über Sync-Tools eingerichtet werden.
---
## 2. **Clementine / Strawberry (Linux) + Android App Clementine Remote / DSub**
- **Linux:** [[Strawberry 1]] ist ein Fork von Clementine, moderner gepflegt.
- Bibliotheksorganisation nach vielen Kriterien.
- Metadatenbearbeitung, inkl. Coverdownload von Last.fm, MusicBrainz.
- Playlists: statisch + dynamisch.
- **Android:** Offizielle Clementine-Remote-App für Steuerung, oder Streaming via Subsonic-kompatibler Apps (z. B. [[DSub]], [[Ultrasonic]]).
- siehe auch [[Subsonic-API]]
- **Sync:**
- Metadaten (Playcount, Ratings) werden am PC gespeichert.
- Handy-Sync ist etwas frickelig, echte **bidirektionale Playcount-Synchronisation** gibt es nicht nativ.
- **Pro:** Native Linux-App, offene Formate.
- **Contra:** Sync mit Handy nicht so nahtlos wie MediaMonkey.
---
## 3. **Amarok / Elisa (KDE) + Android (KDE Connect, VLC, PowerAmp)**
- **Linux:** Amarok war früher sehr stark, inzwischen etwas veraltet. Elisa ist der moderne KDE-Player, aber weniger mächtig in Smart-Playlists.
- **Android:** Mit **KDE Connect** kannst du Dateien kabellos synchronisieren, aber Metadaten-Sync (z. B. "Last Played") fehlt.
- **Pro:** Schön in KDE integriert.
- **Contra:** Nicht so mächtig wie MediaMonkey.
---
## 4. **Rhythmbox + Android (Lollypop / VLC)**
- **Linux:** Rhythmbox (GNOME Standard) oder Lollypop (modernere Oberfläche).
- **Features:** Library, Metadaten, Bewertungen.
- **Sync:** Per Kabel (MTP) oder WLAN/Sync-Tools, aber kein sauberer Playcount-Abgleich.
- **Contra:** Sehr basic, keine regelbasierten Playlists wie MediaMonkey.
---
## 5. **Self-Hosted Server + Android (Subsonic/Airsonic + DSub/Ampache)**
- **Linux:** Airsonic, [Navidrome] oder Koel als **Musikserver**.
- **Features:** Vollständige Weboberfläche, flexible Library, Tags, Playcounts, Bewertungen.
- **Android:** Mit Apps wie **DSub**, **Substreamer**, **Ultrasonic** Zugriff und **automatische Playcount-Sync**.
- **Pro:**
- Playcounts, Metadaten und Playlists sind _immer synchronisiert_.
- Zugriff auch von unterwegs.
- **Contra:** Kein klassischer "Desktop-Player", sondern Server-Setup. Eher für Power-User.
---
## 6. **Syncthing / rsync als Backend für bestehende Player**
- Falls dir wichtig ist, die MP3s in voller Struktur 1:1 zwischen Rechner und Handy zu haben (inkl. Playcounts, Bitrate-Anpassung), kannst du auch einen reinen Player wie **Strawberry** am PC + **GoneMAD** oder **PowerAmp** am Handy nutzen, und den Abgleich über **Syncthing** erledigen.
- Bitraten-Transkodierung beim Sync ist tricky: am besten über ein Script oder mit Tools wie **FFmpeg** beim Kopieren lösen.
---
## Fazit (Empfehlungen)
- **"Am nächsten an MediaMonkey"** → **MusicBee unter Wine + GoneMAD/PowerAmp auf Android** (aber kein native Linux).
- **Native Linux-Lösung, solide & gepflegt** → **Strawberry auf Linux + GoneMAD auf Android**, Sync per Syncthing/rsync.
- **Wenn Playcount/Rating-Sync über Geräte _wirklich_ zentral ist** → **[[Navidrome]] (Server) + DSub/Ultrasonic auf Android**.
---
👉 Frage an dich:
Ist dir wichtiger, dass das Ganze **nativ auf Linux läuft** (also Wine vermeiden), oder dass du **möglichst nahe an der MediaMonkey-Experience bleibst**, auch wenns Wine erfordert?
---
Ich ziehe es vor, wenn es nativ unter Linux läuft. Es **muss** nicht auch nicht Media Monkey nachahmen, es sollte vom Funktionsumfang nur ähnlich mächtig sein. Wenn für Synchronisation extra Tools benötigt werden ist das ok. Wichtig wäre mir, dass Bearbeitungen am PC (Hinzugefügte Songs, Playlisten statisch und dynamisch, Metadaten etc) möglichst 1 zu 1 auch auf dem Handy verfügbar sind.
---
Perfekt — danke für die Präzisierung. Du willst also **native Linux**-Werkzeuge, die in Summe ungefähr so mächtig sind wie MediaMonkey, und die Änderungen am PC (neue Songs, statische + dynamische Playlists, Metadaten usw.) sollen **möglichst 1:1 auf dem Android-Handy verfügbar** sein. Ich habe zwei praxiserprobte, native-unter-Linux-Workflows für genau dieses Ziel — einer ist _server-zentriert_ (am zuverlässigsten für Bidirektionalität von Playcounts/Playlists/Metadaten), der andere ist _Datei-Sync/Offline_-orientiert (besser für rein lokale Dateien/Offline-Nutzung, aber mit Einschränkungen bei Playcount/Ratings). Ich liste jeweils Voraussetzungen, wie es funktioniert, Vor-/Nachteile und konkrete Umsetzungspunkte.
# Empfehlung A — **(Meine Top-Wahl)** Lokaler Musik-Server ([[Navidrome]]/Airsonic) + native Player (Strawberry) auf PC + Subsonic-Client auf Android (z. B. DSub / Ultrasonic)
**Warum:** [[Navidrome]] (leichtgewichtiger, moderner Subsonic-kompatibler Server) läuft nativ unter Linux, indexiert deine Musikdateien und stellt Bibliothek + Playlists + Playcounts + Ratings zentral zur Verfügung. Android-Clients, die das Subsonic-API unterstützen, können sowohl streamen als auch offline cachen und melden Wiedergaben/Playcounts zurück an den Server — dadurch hast du eine echte 1:1-Synchronisation der Nutzungsdaten zwischen PC und Handy. [Navidrome] bietet außerdem Transcoding/Download-Transkodierung (nützlich, um Bitrate beim Übertragen zu reduzieren). Auf dem Desktop nutzt du einen richtigen Player/Tag-Editor wie **Strawberry** zum Bearbeiten der Dateien; der Server erkennt Änderungen bei Rescan/Auto-Import. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
Wie das zusammenwirkt — Kurzablauf:
1. Auf dem Linux-PC: music-folder (z. B. `~/Music`) → Strawberry zum Abspielen & Tag-Editing. Strawberry ist native, hat Smart/Dynamic-Playlists und Tag-Editoren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
2. Auf dem Linux-PC: [[Navidrome]] (als Dienst oder Docker) so konfigurieren, dass es auf genau denselben Music-Ordner zeigt. [[Navidrome]] indexiert die Dateien, liest Tags, Playlists (importiert `.m3u`) und verwaltet Playcounts/ratings serverseitig. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
3. Auf Android: Subsonic-kompatible App installieren (z. B. **DSub**, **Ultrasonic** oder Subsonic-App). Diese Apps können streamen, offline cachen/downloaden und (je nach App/Server-Einstellung) Playbacks/Playcounts an [[Navidrome]] zurückmelden; sie unterstützen auch clientseitiges Transcoding / Download-Qualitätssteuerung. (Subsonic-App-Ökosystem ist groß, DSub ist ein verbreiteter Client.) ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
Wesentliche Vorteile:
- **Echte Bidirektionalität** für Playcount/Play/Rating, wenn Client ↔ Server dies unterstützt (sehr viel zuverlässiger als reine Datei-Syncs). ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
- **On-the-fly Transcoding / Bitrate-Limit** beim Stream/Download — du kannst z. B. mobil immer in 128192 kbps laden, während der PC die Originals behält. ([[Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[Navidrome]] Configuration Options"))
- Desktop bleibt native (Strawberry), Server läuft nativ unter Linux. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
Nachteile / Dinge, die du beachten solltest:
- Es ist kein „klassischer“ Einzelprogramm-Desktop-Workflow mehr, sondern ein **Server + Clients**-Setup (läuft aber lokal auf deinem Rechner, keine Cloud nötig).
- Manche Subsonic-Clients handhaben Offline-Caching unterschiedlich (Ordnerstruktur, Caching-Verhalten). Testen lohnt sich. ([GitHub](https://github.com/airsonic-advanced/airsonic-advanced/issues/873?utm_source=chatgpt.com "DSub sync/cache with Airsonic 11 dumps all files into main ..."))
**Kurz-Setup-Hinweise:**
- Installiere [[Navidrome]] (Deb/Flatpak/Docker) und stelle `MUSIC_FOLDER` auf deinen bestehenden Musikordner. Aktiviere ggf. `AutoImportPlaylists`. ([[Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[Navidrome]] Configuration Options"))
- Installiere Strawberry als Desktop-Player und bearbeite Tags/Playlists dort; [[Navidrome]] neu scannen lassen oder Auto-Rescan aktivieren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
- Auf Android: DSub/Ultrasonic konfigurieren (Server-URL mit deiner lokalen IP), in der App die Download/Transcode-Qualität setzen. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
---
# Empfehlung B — **Datei-Sync (offline) Workflow**: Strawberry (Linux) + Syncthing (oder rsync) + Android-Player (GoneMAD / Poweramp)
**Warum:** Wenn du viel offline hörst und tatsächliche Dateien auf dem Handy brauchst (z. B. Hi-Res oder bestimmte Ordnerstruktur), ist Syncthing eine sehr komfortable, native Lösung zum Spiegeln von Ordnern PC ↔ Handy. Strawberry bearbeitet Tags/Playlists auf dem PC und die Dateien werden 1:1 auf's Handy kopiert. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
Wie das zusammenwirkt — Kurzablauf:
1. Strawberry verwaltet die Dateien lokal und erzeugt Playlists (M3U).
2. Syncthing synchronisiert den Music-Ordner (und Playlist-Exports) automatisch auf das Handy. Syncthing läuft nativ unter Linux und Android. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
3. Auf Android: ein mächtiger Offline-Player wie **GoneMAD** oder **Poweramp** liest die Dateien/Playlists vom synchronisierten Ordner.
Vorteile:
- Volle Offline-Verfügbarkeit (keine Server-Software nötig).
- Absolute Dateiintegrität — exakt die gleichen MP3/FLAC liegen auf beiden Geräten.
Wesentliche Einschränkungen (sehr wichtig):
- **Playcounts / Ratings**: Viele Android-Player (z. B. Poweramp) speichern Playcounts/Rating in einer **internen App-Datenbank** und schreiben diese **nicht** zuverlässig zurück in die MP3-Tags (POPM/PCNT). Dadurch geht die echte bidirektionale Synchronisation von „Last played / playcount / rating“ verloren, bzw. sie ist nur mit zusätzlichen Tools/Workarounds möglich. Poweramp z.B. unterstützt POPM nicht als schreibbaren Standard-Rating-Export. GoneMAD hat einige Optionen, kann aber nicht immer sauber bidirektional zu jedem Desktop-Tool synchronisieren. ([Poweramp](https://forum.powerampapp.com/topic/21099-will-not-recognize-ratings-tags/?utm_source=chatgpt.com "Will not recognize ratings tags - Poweramp Feature Requests"))
- Android-Medienindexer kann neue Dateien verzögert erkennen; manchmal muss man den Index anstoßen oder die App neu starten, wenn Syncthing neue Musik ablegt. ([Syncthing Community Forum](https://forum.syncthing.net/t/music-synced-onto-phone-not-picked-up-by-android/22191?utm_source=chatgpt.com "Music Synced onto Phone Not Picked Up by Android"))
Workarounds:
- Verwende ID3-Frames, die als Standard existieren — z. B. **PCNT** (Play Counter) oder **POPM** (Popularimeter) — und scripte gelegentlich ein Update/Export/Import dieser Frames zwischen Player-DB und Dateien. Die PCNT-Frame ist Teil der ID3-Spec und kann playcount direkt in die Datei schreiben — das funktioniert aber nur, wenn der Android-Player diese Frames auch schreibt/liest. ([id3.org](https://id3.org/id3v2.3.0?utm_source=chatgpt.com "id3v2.3.0"))
- Manche Nutzer verwenden periodische Exporte (z. B. M3U/CSV) und ein kleines Script, das die DB-Werte abgleicht — ist aber Aufwand und fragile Lösung. (Wenn du experimentierfreudig bist, möglich.)
---
# Vergleich & Entscheidungshilfe — kurz
- **Wenn du wirklich möchtest, dass Playcounts / LastPlayed / Ratings verlässlich zwischen PC ↔ Handy synchron sind → wähle den Server-Ansatz ([[Navidrome]] / Airsonic)**. Das ist die sauberste, wartungsarme Lösung für bidirektionale Nutzungsdaten; zusätzlich hast du komfortable Transcoding-Optionen für mobile Daten/Storage. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
- **Wenn du maximale Offline-Kontrolle über die Dateien willst (keine Serverstruktur) → wähle Syncthing + ein mächtiges Android-Player,** akzeptiere aber Einschränkungen bei Ratings/Playcounts bzw. plane zusätzliche Scripts/Workarounds ein. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
---
# Konkrete Vorschläge zum sofortigen Ausprobieren (in dieser Reihenfolge)
1. **Testlauf Server-Option (empfohlen):**
- Installiere [[Navidrome]] (Docker oder Paket) und zeige es auf `~/Music`. ([[Navidrome]] ist leicht, kann lokal laufen.) ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
- Installiere DSub (oder Ultrasonic) auf dem Handy, verbinde mit [[Navidrome]]. Teste Streaming + Offline-Download + setzte Download-Bitrate auf z. B. 160 kbps. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
- Auf dem PC: installiere **Strawberry**, bearbeite ein paar Tags & Playlists, lasse [[Navidrome]] neu scannen — prüfe die Änderungen im Android-Client. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
2. **Falls du stattdessen Offline-Dateien bevorzugst:**
- Installiere **Syncthing** auf PC + Android, sync einen kleinen Test-Musikordner. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
- Auf Android: teste **GoneMAD** (sehr anpassbar) oder **Poweramp** als Player, probiere, ob Ratings/Playcounts in deiner Kombination zuverlässig geschrieben/gezogen werden (Hinweis: Poweramp schreibt POPM nicht). ([Google Play](https://play.google.com/store/apps/details?hl=en_US&id=gonemad.gmmp&utm_source=chatgpt.com "GoneMAD Music Player - Apps on Google Play"))
---
# Quellen (wichtigste Belege)
- Strawberry — native Linux Player: Smart/dynamic playlists, Tag-Editor, MusicBrainz/cover lookup. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
- [[Navidrome]] — leichter Subsonic-kompatibler Server, lokal nutzbar; Optionen für AutoImportPlaylists / Transcoding/Download-Transcode. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
- Subsonic/DSub ecosystem — Android-Clients für Subsonic/[[Navidrome]] (Streaming, Offline Caching, Bitrate/Transcode Optionen). ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
- ID3-Frames (PCNT / POPM) — Playcount-Frame `PCNT` ist Teil der ID3v2-Spec (kann in Datei gespeichert werden). ([id3.org](https://id3.org/id3v2.3.0?utm_source=chatgpt.com "id3v2.3.0"))
- Poweramp & Rating/Tagging Limit: Poweramp schreibt/liest POPM/PCNT nicht standardmäßig; Ratings werden intern gespeichert — wichtige Einschränkung für Datei-Sync Workflows. ([Poweramp](https://forum.powerampapp.com/topic/21099-will-not-recognize-ratings-tags/?utm_source=chatgpt.com "Will not recognize ratings tags - Poweramp Feature Requests"))
- Syncthing für Datei-Sync Android ↔ PC — verbreitete Praxis, aber Android-Indexing / Rechte / folder ownership sind zu beachten. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
---
Wenn du willst, mache ich sofort eines von beiden für dich praktisch:
- **Variante A:** Ich erstelle dir eine Schritt-für-Schritt-Anleitung (konkret für Debian/Ubuntu/Fedora) zum Installieren/Einrichten von [[Navidrome]] + Strawberry + DSub (inkl. Beispiel-Config für Transcoding/AutoImport).
- **Variante B:** Oder ich schreibe ein kurzes Syncthing-Setup-Tutorial + Hinweise, wie du Ratings/Playcounts am besten per ID3/Script synchronisierst (inkl. Beispielscript, das `PCNT`/`POPM` per `mutagen` oder `eyeD3` setzt).
Sag mir einfach welches Setup du zuerst ausprobieren willst — ich liefere die konkrete, sofort ausführbare Anleitung (inkl. Konfig-Snippets).
@@ -0,0 +1,34 @@
Is there a keyboard shortcut on linux to open a terminal
---
Yes 👍 — most Linux desktop environments (DEs) have a default keyboard shortcut for opening a terminal, but it can vary depending on which one youre using:
- **GNOME (Ubuntu, Fedora, Debian, etc.):**
`Ctrl + Alt + T`
- **KDE Plasma (Kubuntu, openSUSE, etc.):**
Usually also `Ctrl + Alt + T` (but can be customized).
- **XFCE (Xubuntu, etc.):**
Often `Ctrl + Alt + T`, or you can set your own in _Settings → Keyboard → Application Shortcuts_.
- **Others (MATE, Cinnamon, LXQt, etc.):**
Many also use `Ctrl + Alt + T` by default.
If it doesnt work, you can always **assign your own shortcut**:
1. Go to your systems **Keyboard Settings**.
2. Find **Custom Shortcuts** (or _Keyboard Shortcuts_).
3. Add a new one:
- Command: `gnome-terminal` (or `konsole`, `xfce4-terminal`, depending on your DE).
- Shortcut: choose something like `Ctrl + Alt + T`.
---
👉 Which desktop environment or Linux distro are you using? I can give you the exact steps for your setup.
+15
View File
@@ -0,0 +1,15 @@
[[Linux Musikprogramme]]
[[Softlinks 1]]
[[Synchronisation & Backup 1]]
# Konsolen Know-How
[[Linux Konsole Zeichen löschen]]
[[Paketinstallation aus tar.gz]]
[[Disable KVM for VirtualBox]]
[[Linux Terminal Shortcut]]
[[Drives & Mounts 1]]
[[Computerkram/find]]
[[Link-Verknüpfung in Linux]]
+3
View File
@@ -0,0 +1,3 @@
* [[ssh Key erstellen]]
* [[mein fstab]]
*
@@ -0,0 +1,142 @@
**Warum:** [[Navidrome]] (leichtgewichtiger, moderner Subsonic-kompatibler Server, -> [[Subsonic-API]]) läuft nativ unter Linux, indexiert deine Musikdateien und stellt Bibliothek + Playlists + Playcounts + Ratings zentral zur Verfügung. Android-Clients, die das Subsonic-API unterstützen, können sowohl streamen als auch offline cachen und melden Wiedergaben/Playcounts zurück an den Server — dadurch hast du eine echte 1:1-Synchronisation der Nutzungsdaten zwischen PC und Handy. [Navidrome] bietet außerdem Transcoding/Download-Transkodierung (nützlich, um Bitrate beim Übertragen zu reduzieren). Auf dem Desktop nutzt du einen richtigen Player/Tag-Editor wie [[Strawberry 1]] zum Bearbeiten der Dateien; der Server erkennt Änderungen bei Rescan/Auto-Import. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
Wie das zusammenwirkt — Kurzablauf:
1. Auf dem Linux-PC: music-folder (z. B. `~/Music`) → Strawberry zum Abspielen & Tag-Editing. Strawberry ist native, hat Smart/Dynamic-Playlists und Tag-Editoren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
2. Auf dem Linux-PC: [[Navidrome]] (als Dienst oder Docker) so konfigurieren, dass es auf genau denselben Music-Ordner zeigt. [[Navidrome]] indexiert die Dateien, liest Tags, Playlists (importiert `.m3u`) und verwaltet Playcounts/ratings serverseitig. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
3. Auf Android: Subsonic-kompatible App installieren (z. B. **DSub**, **Ultrasonic** oder Subsonic-App). Diese Apps können streamen, offline cachen/downloaden und (je nach App/Server-Einstellung) Playbacks/Playcounts an [[Navidrome]] zurückmelden; sie unterstützen auch clientseitiges Transcoding / Download-Qualitätssteuerung. (Subsonic-App-Ökosystem ist groß, DSub ist ein verbreiteter Client.) ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
Wesentliche Vorteile:
- **Echte Bidirektionalität** für Playcount/Play/Rating, wenn Client ↔ Server dies unterstützt (sehr viel zuverlässiger als reine Datei-Syncs). ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
- **On-the-fly Transcoding / Bitrate-Limit** beim Stream/Download — du kannst z. B. mobil immer in 128192 kbps laden, während der PC die Originals behält. ([[Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[Navidrome]] Configuration Options"))
- Desktop bleibt native (Strawberry), Server läuft nativ unter Linux. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
Nachteile / Dinge, die du beachten solltest:
- Es ist kein „klassischer“ Einzelprogramm-Desktop-Workflow mehr, sondern ein **Server + Clients**-Setup (läuft aber lokal auf deinem Rechner, keine Cloud nötig).
- Manche Subsonic-Clients handhaben Offline-Caching unterschiedlich (Ordnerstruktur, Caching-Verhalten). Testen lohnt sich. ([GitHub](https://github.com/airsonic-advanced/airsonic-advanced/issues/873?utm_source=chatgpt.com "DSub sync/cache with Airsonic 11 dumps all files into main ..."))
**Kurz-Setup-Hinweise:**
- Installiere [[Navidrome]] (Deb/Flatpak/Docker) und stelle `MUSIC_FOLDER` auf deinen bestehenden Musikordner. Aktiviere ggf. `AutoImportPlaylists`. ([[Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[Navidrome]] Configuration Options"))
- Installiere Strawberry als Desktop-Player und bearbeite Tags/Playlists dort; [[Navidrome]] neu scannen lassen oder Auto-Rescan aktivieren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
- Auf Android: DSub/Ultrasonic konfigurieren (Server-URL mit deiner lokalen IP), in der App die Download/Transcode-Qualität setzen. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
---
### 1. **Playcounts / Metadaten in Strawberry vs. Navidrome**
- **Wenn du Strawberry „lokal“ (eigene Library, also direkt auf den Musikdateien im Dateisystem) benutzt:**
- Playcounts und Ratings werden **nur in Strawberries interner Datenbank** gepflegt, nicht in Navidrome.
- Metadatenänderungen (Tags, Cover etc.), die du in den Dateien speicherst, **sieht Navidrome** beim nächsten Scan (manuell oder automatisch). → Cover/Tags sind also synchron, **aber Playcounts und Ratings nicht**.
- **Wenn du Strawberry „über Streaming“ mit Navidrome verbindest:**
- Playcounts und Ratings werden im **Navidrome-Server** gespeichert, d.h. Handy + PC greifen auf denselben Zähler/Rating zurück.
- Änderungen in der Datei selbst sind dann nachrangig (es sei denn, du editierst die Tags explizit im Dateisystem).
👉 Empfehlung:
- Für **Playcounts und Bewertungen**, immer über das Navidrome-Streaming-Backend hören.
- Für **Tag-Bearbeitung** (Album Artist, Genre, Cover etc.) kannst du ruhig Strawberry lokal verwenden → nach dem Speichern erkennt Navidrome die geänderten Tags.
---
### 2. **Navidrome auf Synology NAS installieren sinnvoll?**
- **Ja, absolut sinnvoll.** Vorteile:
- Deine Musik liegt vermutlich sowieso schon auf der NAS.
- Navidrome kann 24/7 laufen, unabhängig vom PC.
- Dein Handy kann direkt auf die NAS zugreifen (auch unterwegs, wenn du Portfreigabe oder VPN einrichtest).
- Installationsmöglichkeiten:
- **Docker-Container** (empfohlen, wenn du Docker auf der Synology nutzt). Das offizielle Image ist `deluan/navidrome`.
- Oder als native Binary in einer Synology-Chroot/Entwicklungsumgebung (Docker ist aber deutlich einfacher).
👉 Empfehlung: Wenn die NAS immer läuft → installiere Navidrome dort. Dann kannst du Strawberry am PC so konfigurieren, dass er sich nur noch als Client auf den NAS-Server verbindet.
---
### 3. **Navidrome beim Systemstart automatisch starten lassen**
Hängt davon ab, wie du es installiert hast:
- **Systemd-Service (klassisch, wenn du es auf deinem Linux-PC laufen lässt):**
1. Service-Datei erstellen:
```ini
# /etc/systemd/system/navidrome.service
[Unit]
Description=Navidrome Music Server
After=network.target
[Service]
User=deinuser
Group=deinuser
ExecStart=/usr/local/bin/navidrome --configfile /etc/navidrome.toml
Restart=on-failure
WorkingDirectory=/home/deinuser
[Install]
WantedBy=multi-user.target
```
2. Aktivieren & starten:
```bash
sudo systemctl enable navidrome
sudo systemctl start navidrome
```
- **Docker + Systemd:**
Wenn du Navidrome via Docker laufen lässt, kannst du entweder `docker run --restart=always ...` nutzen oder einen systemd-Service schreiben, der den Container startet.
- **Synology NAS (Docker):**
Die Synology Docker-Oberfläche bietet eine Einstellung **„Automatisch starten“** beim Container an. Einfach anhaken, dann startet Navidrome mit der NAS.
---
✅ **Kurz zusammengefasst:**
- **Playcounts/Ratings:** Nur über Navidrome-Streaming → sonst bleiben sie lokal in Strawberry.
- **Metadaten (Tags, Cover):** Bearbeitung in Strawberry → Navidrome liest sie beim nächsten Scan ein.
- **NAS:** Ideal für Dauerbetrieb, am besten per Docker.
- **Autostart:** systemd-Service (Linux) oder Autostart in Synology Docker aktivieren.
---
👉 Soll ich dir eine konkrete Schritt-für-Schritt-Anleitung für **Navidrome auf Synology NAS (per Docker)** schreiben, inkl. `docker run`-Beispiel und Volume-Mounts (z. B. für `music/` und `data/`)? Dann kannst du deine PC-Instanz ablösen und alles zentralisieren.
+97
View File
@@ -0,0 +1,97 @@
<https://www.navidrome.org/>
Hier eine ausführliche Vorstellung von **Navidrome**:
---
## 🔎 Was ist Navidrome?
Navidrome ist ein **selbstgehosteter Musikserver** für \[\[Linux\]\] (und andere Plattformen). Er funktioniert ähnlich wie Spotify oder Apple Music nur mit deiner eigenen Musikbibliothek. Du lädst deine Audiodateien (MP3, FLAC, OGG, AAC etc.) auf deinen Server, und Navidrome macht sie über ein Web-Interface oder kompatible Apps (\[\[Subsonic-API\]\]) überall verfügbar.
Kurz:
👉 Deine Musik, dein Server, jederzeit und überall streambar.
---
## 🎶 Was kann Navidrome?
- **Streaming im Browser** mit einem modernen, responsiven Webplayer.
- **Unterstützt viele Clients** über die Subsonic-API (z. B. \[\[DSub\]\], \[\[Ultrasonic\]\], \[\[Substreamer\]\], Symfonium, etc.).
- **Automatische Bibliotheksindizierung**: Scannt Ordner, liest Metadaten und baut deine Mediathek.
- **Benutzerverwaltung**: Mehrere Accounts mit eigenen Playlists, Favoriten und Rechten.
- **Playlists & Favoriten** (inkl. Smart-Playlists).
- **Transcoding on the fly**: Wandelt Dateien in kleinere Formate um, falls deine Verbindung langsam ist.
- **Leichtgewichtig & ressourcenschonend** (geschrieben in Go).
- **Cross-Plattform**: \[\[Linux\]\], Windows, macOS, ARM (z. B. Raspberry Pi).
- **Docker-Images verfügbar** für einfache Installation.
---
## ✅ Vorteile gegenüber anderen Lösungen
- **Leichtgewichtiger als Plex oder Jellyfin**, weil es sich auf Musik konzentriert.
- **Moderner und aktiver entwickelt als Airsonic, Subsonic & Co.**
- **Einfach zu installieren und zu warten** (ein Binary oder Docker-Container reicht).
- **Sehr niedrige Hardware-Anforderungen** läuft problemlos auf kleinen VPS oder einem Raspberry Pi.
- **Sehr gute Client-Kompatibilität** durch \[\[Subsonic-API\]\].
---
## 🛠️ Installation unter Linux
### Variante 1: Per Binary (klassisch)
1. Lade die aktuelle Version herunter:
```bash
wget https://github.com/navidrome/navidrome/releases/latest/download/navidrome_linux_amd64.tar.gz
tar xzf navidrome_linux_amd64.tar.gz
sudo mv navidrome /usr/local/bin/
```
2. Erstelle einen Benutzer für Navidrome:
```bash
sudo useradd -r -s /bin/false navidrome
```
3. Erstelle ein Konfigurationsverzeichnis:
```bash
sudo mkdir /var/lib/navidrome
sudo chown navidrome:navidrome /var/lib/navidrome
```
4. Systemd-Service einrichten (optional).
---
### Variante 2: \[\[Docker\]\] (empfohlen)
```bash
docker run -d \
--name=navidrome \
-p 4533:4533 \
-v /pfad/zu/deiner/musik:/music \
-v /pfad/zu/navidrome/data:/data \
deluan/navidrome:latest
```
---
## ⚙️ Ersteinrichtung
- Navidrome läuft nun auf: <http://localhost:4533>
- Beim ersten Start wirst du aufgefordert, ein **Admin-Konto** anzulegen.
- Danach: Musikordner wird automatisch eingelesen (Metadaten, Cover, etc.).
---
## 📌 Dinge, die man beachten sollte
- **Firewall/Portfreigabe**: Wenn du von außen zugreifen willst, Port 4533 öffnen oder einen Reverse Proxy (nginx/traefik mit HTTPS) davor schalten.
- **Sicherung**: Datenbank & Konfigurationsordner `/data` regelmäßig sichern.
- **Rechte**: Musikordner muss für den Navidrome-Benutzer lesbar sein.
- **Transcoding**: Falls du FLAC → MP3 brauchst, sollte `ffmpeg` installiert sein.
- **Clients**: Nutze eine kompatible App für Smartphone-Streaming (z. B. Symfonium [Android], iSub [iOS]).
---
\[\[Navidrome mit Strawberry 1\]\]
@@ -0,0 +1,99 @@
## Debian-basierte Systeme (Ubuntu, Debian, Linux Mint, etc.)
### APT (Advanced Package Tool)
```bash
# Paketliste aktualisieren
sudo apt update
# Einzelnes Paket installieren
sudo apt install paketname
# Mehrere Pakete installieren
sudo apt install paket1 paket2 paket3
# System-Upgrade durchführen
sudo apt upgrade
# Paket entfernen
sudo apt remove paketname
# Paket komplett entfernen (inkl. Konfigurationsdateien)
sudo apt purge paketname
# Nach Paketen suchen
apt search suchbegriff
# Paketinformationen anzeigen
apt show paketname
```
### Alternative: APT-GET (ältere Syntax)
```bash
sudo apt-get update
sudo apt-get install paketname
sudo apt-get remove paketname
```
## Arch-basierte Systeme (Arch Linux, Manjaro, EndeavourOS, etc.)
#Pacman (Package Manager)
```bash
# Paketdatenbank synchronisieren
sudo pacman -Sy
# System komplett aktualisieren
sudo pacman -Syu
# Einzelnes Paket installieren
sudo pacman -S paketname
# Mehrere Pakete installieren
sudo pacman -S paket1 paket2 paket3
# Paket entfernen
sudo pacman -R paketname
# Paket mit Abhängigkeiten entfernen
sudo pacman -Rs paketname
# Nach Paketen suchen
pacman -Ss suchbegriff
# Installierte Pakete auflisten
pacman -Q
# Paketinformationen anzeigen
pacman -Si paketname
```
### AUR (Arch User Repository)
Für AUR-Pakete wird ein AUR-Helper wie `yay` oder `paru` benötigt:
```bash
# Mit yay installieren
yay -S paketname
# Mit paru installieren
paru -S paketname
```
## Wichtige Parameter-Erklärungen
| Debian (apt) | Arch (pacman) | Bedeutung |
|--------------|---------------|-----------|
| `update` | `-Sy` | Paketliste aktualisieren |
| `upgrade` | `-Su` | Installierte Pakete aktualisieren |
| `install` | `-S` | Paket installieren |
| `remove` | `-R` | Paket entfernen |
| `search` | `-Ss` | Nach Paketen suchen |
| `show` | `-Si` | Paketinformationen anzeigen |
## Best Practices
- **Immer vor Installation**: System aktualisieren
- **Debian**: `sudo apt update && sudo apt upgrade`
- **Arch**: `sudo pacman -Syu`
> **Tipp**: Auf Arch-Systemen sollte man niemals `pacman -Sy paketname` ohne vorheriges vollständiges System-Update verwenden, da dies zu Abhängigkeitsproblemen führen kann.
@@ -0,0 +1,101 @@
Um dich per **SSH** zwischen zwei Linux-Rechnern im Heimnetzwerk zu verbinden, gehst du so vor:
---
### 1. SSH-Server installieren und aktivieren
Auf dem Rechner, **zu dem du dich verbinden möchtest** (Zielrechner):
```bash
sudo apt update && sudo apt install openssh-server -y # Ubuntu/Debian
sudo systemctl enable ssh
sudo systemctl start ssh
```
Auf Fedora/RHEL/Arch:
```bash
sudo dnf install openssh-server -y # Fedora
sudo pacman -S openssh # Arch
sudo systemctl enable sshd
sudo systemctl start sshd
```
Status prüfen:
```bash
systemctl status ssh
```
oder
```bash
systemctl status sshd
```
---
### 2. IP-Adresse des Zielrechners herausfinden
Auf dem Zielrechner:
```bash
ip a
```
oder
```bash
hostname -I
```
Beispielausgabe: `192.168.178.42`
---
### 3. Verbindung vom Quellrechner herstellen
Auf dem Rechner, von dem du zugreifen willst:
```bash
ssh benutzername@192.168.178.42
```
Dabei:
- `benutzername` = Benutzerkonto auf dem Zielrechner
- `192.168.178.42` = IP-Adresse des Zielrechners im Heimnetz
Beim ersten Mal wirst du gefragt, ob du den Host-Fingerprint akzeptieren willst → `yes`. Danach gibst du dein Passwort ein.
---
### 4. (Optional) Passwortlose Anmeldung mit SSH-Key
Falls du dich ohne Passwort anmelden willst:
Auf dem Quellrechner:
```bash
ssh-keygen -t ed25519
```
(oder `rsa` falls gewünscht, einfach Enter drücken, um Standardpfad `~/.ssh/id_ed25519` zu nutzen)
Dann den öffentlichen Schlüssel auf den Zielrechner kopieren:
```bash
ssh-copy-id benutzername@192.168.178.42
```
Danach kannst du dich einloggen ohne Passwort:
```bash
ssh benutzername@192.168.178.42
```
---
👉 Soll ich dir ein **kurzes Beispiel-Setup mit zwei Testbenutzern** schreiben, das du direkt im Heimnetz nachmachen kannst?
@@ -0,0 +1,162 @@
### 🔧 1. SSH-Schlüssel erzeugen
Öffne ein Terminal und gib ein:
```bash
ssh-keygen -t ed25519 -C "dein.name@beispiel.de"
```
- `-t ed25519`: moderner, sicherer Schlüsseltyp (alternativ: `rsa`).
- `-C`: Kommentar zur Identifikation (z. B. deine E-Mail).
**Wenn gefragt:**
- Speicherort bestätigen mit **Enter** (Standard: `~/.ssh/id_ed25519`).
- Optional ein **Passwort** setzen (empfohlen für zusätzliche Sicherheit).
---
### 📤 2. Öffentlichen Schlüssel auf den Server kopieren
Wenn du z. B. Zugriff auf `user@server.de` hast:
```bash
ssh-copy-id user@server.de
```
Falls `ssh-copy-id` nicht installiert ist, kannst du den Schlüssel auch manuell übertragen:
```bash
cat ~/.ssh/id_ed25519.pub
```
Dann den Inhalt in die Datei `~/.ssh/authorized_keys` auf dem Server einfügen.
---
### 🔐 3. Mit dem Server verbinden
Danach kannst du dich einfach per SSH einloggen:
```bash
ssh user@server.de
```
Du wirst **nicht mehr nach dem Passwort des Servers** gefragt nur ggf. nach der Passphrase deines privaten Schlüssels.
---
### 🧩 (Optional) 4. SSH-Agent verwenden
Damit du die Passphrase nicht ständig eingeben musst:
```bash
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
```
---
Wenn `git push` weiterhin nach einem Passwort fragt, liegt das fast immer daran, dass dein Repository **über HTTPS statt SSH** verbunden ist.
Lass uns das prüfen und beheben 👇
---
## 🔎 1️⃣ Prüfen, welche Remote-URL verwendet wird
Im Repository:
```bash
git remote -v
```
Wenn du etwas siehst wie:
```
https://github.com/USERNAME/REPO.git
```
➡ Dann nutzt du **HTTPS** deshalb wird ein Passwort (bzw. Token) verlangt.
Wenn dort steht:
```
git@github.com:USERNAME/REPO.git
```
➡ Das ist korrekt (SSH).
---
## 🔁 2️⃣ Remote von HTTPS auf SSH umstellen
Ersetze die URL mit der SSH-Version:
```bash
git remote set-url origin git@github.com:USERNAME/REPO.git
```
Danach nochmal testen:
```bash
git push
```
---
## 🧪 3️⃣ SSH-Verbindung separat testen
```bash
ssh -T git@github.com
```
Du solltest eine Meldung bekommen wie:
```
Hi USERNAME! You've successfully authenticated...
```
Wenn nicht, sag mir bitte die Fehlermeldung.
---
## 🔐 4️⃣ Falls SSH korrekt ist, aber trotzdem Passwort kommt
Dann prüfen:
### Läuft der SSH-Agent?
```bash
ssh-add -l
```
Wenn dort steht:
```
The agent has no identities.
```
Dann:
```bash
ssh-add ~/.ssh/id_ed25519
```
---
## 🛠 5️⃣ Debug-Modus (wenn es immer noch nicht klappt)
```bash
ssh -vT git@github.com
```
Das zeigt, welcher Key wirklich benutzt wird.
---
### 💡 90% der Fälle:
Das Repository wurde ursprünglich per HTTPS geklont.
Wenn du möchtest, kannst du mir die Ausgabe von
`git remote -v` posten dann sage ich dir exakt, was los ist.
+137
View File
@@ -0,0 +1,137 @@
Strawberry ist ein **Musikplayer und -manager** für [[Linux]] (auch für Windows und macOS verfügbar), der sich auf **lokale Musiksammlungen** konzentriert. Er ist ein Fork von _Clementine_, das wiederum auf _Amarok_ basiert. Strawberry richtet sich vor allem an Nutzer, die eine **große Sammlung an Musikdateien (MP3, FLAC, OGG, etc.) lokal verwalten** möchten im Gegensatz zu Playern, die stark auf Streaming setzen.
---
## 🎯 Zweck von Strawberry
- **Abspielen von Musikdateien** in allen gängigen Formaten.
- **Bibliotheksverwaltung**: Organisieren großer Sammlungen anhand von Metadaten, Tags und Ordnerstrukturen.
- **Metadatenverwaltung**: Bearbeiten von Tags, Laden von Cover-Artworks, Abgleich mit Online-Datenbanken (z. B. MusicBrainz).
- **Wiedergabelisten**: Erstellen und Verwalten komplexer Playlists.
- **Audiowiedergabe in hoher Qualität** mit Unterstützung von Hi-Res-Formaten.
- **Externe Dienste**: Scrobbling zu Last.fm, Libre.fm oder ListenBrainz.
---
## ⚙️ Funktionen
- Unterstützung für FLAC, MP3, OGG, WAV, WMA, AAC u. v. m.
- Wiedergabe mit **GStreamer** (gute Audioqualität, viele Codecs).
- **Tag-Editor** für ID3, Vorbis- und FLAC-Tags.
- Automatisches Laden von **Album-Covern**.
- **EQ und ReplayGain**-Unterstützung.
- **Wiedergabelisten** im M3U-, XSPF- und PLS-Format.
- **Gerätesynchronisation**: Musik auf mobile Player kopieren.
- **Streaming-Radio** (einfache Integration, aber nicht Hauptfokus).
---
## ✅ Vorteile
- **Fokus auf lokale Musik** ideal für Sammler, die ihre eigene Bibliothek pflegen.
- **Schnell und ressourcenschonend** im Vergleich zu schwergewichtigeren Lösungen wie Amarok.
- **Moderne Code-Basis**: aktiver Fork von Clementine mit Bugfixes und Verbesserungen.
- **Hohe Audioqualität** mit vielen Formaten und Hi-Res-Support.
- **Cross-Platform**: Linux, Windows, macOS.
- **Keine Zwangs-Cloud-Anbindung** wie bei Spotify & Co.
---
## ❌ Nachteile
- **Kein nativer Streaming-Fokus** (nur begrenzte Unterstützung für Online-Dienste, keine direkte Spotify-/Apple-Music-Integration).
- **Eher klassische Oberfläche** wirkt funktional, aber nicht besonders modern/minimalistisch.
- **Weniger Community als bei großen Projekten** (z. B. Rhythmbox oder VLC).
- **Kein eigener mobiler Client** Synchronisation nur über Dateiübertragung.
---
## 💻 Installation
### Unter Ubuntu/Debian
```bash
sudo apt install strawberry
```
Falls nicht im Standard-Repo (bei älteren Versionen):
```bash
sudo add-apt-repository ppa:jonaski/strawberry
sudo apt update
sudo apt install strawberry
```
### Unter Fedora
```bash
sudo dnf install strawberry
```
### Unter Arch Linux / Manjaro
```bash
sudo pacman -S strawberry
```
### Alternative: Flatpak (universell)
```bash
flatpak install flathub org.strawberrymusicplayer.strawberry
```
---
## 🔧 Einrichtung
1. **Musikordner hinzufügen**: Beim ersten Start fragt Strawberry nach Verzeichnissen, in denen Musik liegt.
2. **Bibliothek scannen**: Die Dateien werden eingelesen und nach Tags sortiert.
3. **Audioausgabe konfigurieren**: In den Einstellungen (z. B. ALSA, PulseAudio, PipeWire auswählen).
4. **Metadaten-Services aktivieren**: Verknüpfung mit MusicBrainz, Last.fm oder Libre.fm, wenn gewünscht.
5. **Wiedergabelisten und Cover laden**: Automatisches Suchen und Speichern aktivieren.
---
## 📌 Was man beachten sollte
- Strawberry ist für **Sammler und Audiophile** gedacht wenn man hauptsächlich Spotify oder YouTube nutzt, ist es weniger passend.
- Gute Organisation der Musikordner und Tags erleichtert die Verwaltung erheblich.
- Bei **Hi-Res-Audio**: Prüfen, ob das Audiosystem (ALSA/PipeWire) korrekt konfiguriert ist.
- Für große Bibliotheken (>100.000 Tracks) sollte man auf genügend RAM und eine SSD achten, sonst wird die Suche langsam.
---
👉 Soll ich dir eine Schritt-für-Schritt-Anleitung schreiben, wie du Strawberry nach der Installation optimal für eine große Musiksammlung einrichtest (inkl. Cover, Tags, Audio-Einstellungen)?
+119
View File
@@ -0,0 +1,119 @@
Perfekt dann ist eine Subsonic-kompatible Library genau das, was du suchst 👍
Für [[Python]] gibt es z. B. [`py-sonic`](https://github.com/crustymonkey/py-sonic).
Die ist zwar nicht mehr super aktiv gepflegt, funktioniert aber mit [[Navidrome]] problemlos, weil Navidrome die [[Subsonic-API]] spricht.
---
## Installation
```bash
pip install py-sonic
```
---
## Grund-Setup
```python
from pysonic.connection import Connection
# Verbindung aufbauen
conn = Connection(
host="http://localhost:4533",
username="meinuser",
password="meinpass",
api_version="1.16.1",
client_name="pyclient"
)
```
---
## Anwendungsfälle
### 1. Playlist erstellen oder öffnen
```python
# Neue Playlist
playlist = conn.create_playlist("Importierte M3U Playlist")
# Alle Playlists abfragen
all_playlists = conn.get_playlists()
```
### 2. Tracks suchen (z. B. per Filename, Titel, Artist)
```python
search = conn.search2(query="Songtitel", songCount=5)
for song in search['song']:
print(song['id'], song['title'], song['artist'])
```
### 3. Track zur Playlist hinzufügen
```python
conn.update_playlist(
playlist_id=playlist['id'],
song_id=["12345", "67890"] # mehrere IDs möglich
)
```
### 4. Stern vergeben
```python
conn.star("12345") # Song-ID
```
### 5. Bookmark setzen
```python
conn.create_bookmark("12345", position=60000, comment="Kapitel 1")
```
---
## Workflow: M3U importieren
Du kannst einfach durch deine `.m3u`-Datei iterieren, für jede Zeile versuchen, den Track im Navidrome zu finden, und dann Aktionen ausführen:
```python
def import_m3u_to_navidrome(m3u_path, playlist_name):
# Playlist anlegen
playlist = conn.create_playlist(playlist_name)
playlist_id = playlist['id']
with open(m3u_path, encoding="utf-8") as f:
for line in f:
if line.startswith("#") or not line.strip():
continue
filename = line.strip().split("/")[-1] # nur Dateiname
# Suche im Server
search = conn.search2(query=filename, songCount=1)
if 'song' in search and search['song']:
song = search['song'][0]
song_id = song['id']
# Playlist hinzufügen
conn.update_playlist(playlist_id=playlist_id, song_id=[song_id])
# Stern setzen
conn.star(song_id)
# Bookmark bei 0 (Startpunkt)
conn.create_bookmark(song_id, position=0, comment="Importiert aus M3U")
print(f"{filename} gefunden und verarbeitet.")
else:
print(f"{filename} nicht gefunden.")
```
---
👉 Damit hättest du ziemlich genau deinen beschriebenen Workflow:
M3U → Tracks auflösen → Playlist + Sterne + Bookmarks automatisch setzen.
---
Soll ich dir ein **vollständiges Script** bauen, das direkt eine `.m3u` einliest, die passende Playlist erstellt und alle drei Aktionen (Playlist-Eintrag, Stern, Bookmark) in einem Durchlauf macht?
@@ -0,0 +1,472 @@
Alles klar ich gebe dir eine ausführliche Übersicht über **Dateisynchronisation und Backups unter Linux**, gegliedert nach typischen Anwendungsfällen (1-way Backup, 2-way Sync, Spezialfälle). Dazu zeige ich dir jeweils **interessante Funktionen**, **geeignete Tools** und **Code-Beispiele**, die du direkt ausprobieren kannst.
---
# 🔧 Dateisynchronisation und Backup unter Linux
## 1. Grundsätzliche Anwendungsfälle
1. **Backup (1-way Synchronisation)**
- Ziel: Sicherung von Daten von Quelle → Ziel.
- Änderungen im Quellordner werden ins Ziel kopiert.
- Änderungen im Ziel haben keine Wirkung zurück.
- Typisch für:
- Regelmäßige Datensicherungen (lokal oder auf Server/NAS)
- Snapshots und inkrementelle Backups
2. **Zwei-Wege-Synchronisation (2-way)**
- Ziel: Quell- und Zielordner sind identisch.
- Änderungen in beiden Richtungen werden abgeglichen.
- Typisch für:
- Zusammenarbeit zwischen Geräten
- Synchronisation von Arbeitsordnern mit Netzwerkfreigaben oder Cloud
3. **Weitere Anwendungsbeispiele**
- **Offsite-Backup** (z. B. automatisches Backup auf einen entfernten Server via SSH)
- **Versionierte Backups** (Aufbewahrung älterer Stände)
- **On-the-fly Synchronisation** (z. B. Watcher, der beim Speichern sofort synced)
- **Mobile Synchronisation** (z. B. Laptop ↔ NAS, USB-Stick ↔ Rechner)
---
## 2. Tools für 1-way Backups
### a) **rsync** (Klassiker)
Das meistgenutzte Werkzeug, effizient und flexibel.
**Einfaches Backup:**
```bash
rsync -avh /home/user/Dokumente/ /media/backup/Dokumente/
```
- `-a` = Archivmodus (erhält Rechte, Zeiten, Links)
- `-v` = verbose
- `-h` = menschenlesbare Größen
**Mit Löschen (Spiegelung):**
```bash
rsync -avh --delete /home/user/Dokumente/ /media/backup/Dokumente/
```
→ Dateien, die in Quelle gelöscht wurden, werden auch im Ziel gelöscht.
**Über SSH (z. B. auf NAS oder Server):**
```bash
rsync -avz /home/user/Dokumente/ user@server:/backup/Dokumente/
```
- `-z` = Kompression
**Interessante Funktionen:**
- `--exclude "*.tmp"` → bestimmte Dateien ignorieren
- `--progress` → Fortschrittsanzeige
- `--link-dest` → inkrementelle Backups mit Hardlinks (ähnlich Time Machine)
---
### b) **borgbackup** (für versionierte, komprimierte, verschlüsselte Backups)
Ideal für langfristige Backups mit Versionierung.
```bash
borg init --encryption=repokey /media/backup/repo
borg create --progress /media/backup/repo::2025-09-26 /home/user/Dokumente
```
Später kannst du ältere Versionen wiederherstellen.
---
## 3. Tools für 2-way Synchronisation
### a) **unison**
Ein Klassiker für bidirektionale Synchronisation.
**Einfacher Start:**
```bash
unison /home/user/Dokumente ssh://user@server//home/user/Dokumente
```
- Erkennt Änderungen auf beiden Seiten
- Fragt bei Konflikten nach
- Arbeitet ähnlich wie `rsync`, aber **beidseitig**
**Dauerhafte Konfiguration:**
In `~/.unison/default.prf`:
```
root = /home/user/Dokumente
root = ssh://user@server//home/user/Dokumente
auto = true
batch = true
```
Dann reicht:
```bash
unison
```
---
### b) **Syncthing** (komfortabel mit Weboberfläche)
- Peer-to-Peer Synchronisation (Ende-zu-Ende verschlüsselt)
- Cross-Platform (Linux, Windows, Android, macOS)
- Ideal für nahtlose Syncs ohne manuellen Eingriff
Installation:
```bash
sudo apt install syncthing
syncthing
```
→ Startet Weboberfläche auf [http://127.0.0.1:8384](http://127.0.0.1:8384)
---
## 4. Automatisierung
### a) Cron-Jobs für regelmäßige Backups
Beispiel: Täglich um 3 Uhr ein rsync-Backup:
```bash
0 3 * * * rsync -avh --delete /home/user/Dokumente/ /media/backup/Dokumente/
```
(`crontab -e`)
### b) systemd Timer (moderner als Cron)
Service-Unit (`/etc/systemd/system/backup.service`):
```ini
[Unit]
Description=Backup Dokumente
[Service]
ExecStart=/usr/bin/rsync -avh --delete /home/user/Dokumente/ /media/backup/Dokumente/
```
Timer (`/etc/systemd/system/backup.timer`):
```ini
[Unit]
Description=Backup Timer
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
```
Aktivieren:
```bash
sudo systemctl enable --now backup.timer
```
---
## 5. Zusammenfassung der interessantesten Funktionen
- **rsync** → universell, effizient, für Backups und Spiegelungen
- **borgbackup** → versioniert, verschlüsselt, platzsparend
- **unison** → 2-way Sync mit Konfliktlösung
- **syncthing** → benutzerfreundlich, kontinuierliche Synchronisation
---
👉 Tipp:
Wenn du **nur Backups** brauchst → `rsync` oder `borg`.
Wenn du **aktive Ordner synchron halten willst**`unison` oder `syncthing`.
---
Soll ich dir zum Einstieg ein **komplettes Setup-Skript für ein automatisches tägliches Backup mit rsync** schreiben, das du direkt verwenden kannst?
Sehr gute Fragen 👍 — ich gehe das mit dir systematisch durch.
---
# 🔄 Unison: Verhalten, Hintergrundbetrieb & Performance
## 1. Läuft Unison permanent im Hintergrund?
Unison an sich ist **kein permanenter Daemon** wie etwa Syncthing.
Es funktioniert normalerweise so:
- Du startest Unison → es vergleicht Quelle und Ziel → synchronisiert → beendet sich.
- Du kannst es per Cron, systemd-Timer oder manuell regelmäßig ausführen.
- Es gibt aber einen **"Unison-GUI/Repeat-Modus"**, bei dem es in einer Schleife läuft und z. B. alle 10 Sekunden die Verzeichnisse prüft.
Beispiel für wiederholte Synchronisation:
```bash
unison default -repeat watch
```
- `-repeat watch` = Unison nutzt OS-Funktionalitäten (inotify auf Linux), um Änderungen sofort zu erkennen.
- `-repeat 10` = alternativ: Polling alle 10 Sekunden.
Damit verhält sich Unison _fast_ wie Syncthing, aber ist weniger komfortabel, weil es keinen richtigen Daemon hat.
---
## 2. Start bei Systemstart
Damit Unison automatisch startet, kannst du es mit **systemd** einrichten.
### Beispiel: systemd Service-Datei
`~/.config/systemd/user/unison.service`
```ini
[Unit]
Description=Unison sync service
After=network.target
[Service]
ExecStart=/usr/bin/unison default -repeat watch
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
```
Dann aktivieren:
```bash
systemctl --user enable --now unison.service
```
→ Jetzt läuft Unison beim Login des Users automatisch und überwacht die definierten Profile.
---
## 3. Performance Impact
Die Performance hängt von der Betriebsart ab:
- **Einmalige Ausführung (Standard)**
- Minimaler Impact, nur während der Synchronisation.
- Nutzt Hashing/Datei-Checksummen, um Änderungen effizient zu erkennen.
- Bei großen Verzeichnissen ist der **erste Lauf** teuer (voller Indexaufbau), danach werden nur Änderungen geprüft.
- **Dauerbetrieb mit `-repeat watch`**
- Nutzt `inotify` → kaum CPU-Last, da nur Änderungen getriggert werden.
- Speicherbedarf: wenige Dutzend MB RAM.
- CPU-Last: fast 0, außer wenn aktiv synchronisiert wird.
- **Dauerbetrieb mit `-repeat 10` (Polling)**
- Alle 10 Sekunden kompletter Scan → deutlich mehr I/O bei vielen Dateien.
- Sollte nur verwendet werden, wenn `inotify` nicht funktioniert (z. B. bei Netzwerk-Dateisystemen).
**Kurz:**
- Lokale Ordner: `-repeat watch` → sehr effizient
- Netzwerk-Mounts (NFS, SMB): oft kein inotify → Polling nötig, etwas schwerer
---
## 4. Fazit
- Unison ist **keine Always-on-Synchronisation wie Syncthing**, aber mit `-repeat watch` + systemd lässt es sich quasi gleichwertig nutzen.
- Performance-Impact ist sehr gering, solange du `watch` nutzt.
- Für **regelmäßige Backups** → Cron oder systemd Timer reicht.
- Für **nahezu Echtzeit-Sync**`-repeat watch` + systemd Service ist die beste Lösung.
---
## 1. Voraussetzung: Config-Datei
Ja, korrekt ✅
Der Aufruf
```bash
unison default -repeat watch
```
setzt voraus, dass du eine Konfigurationsdatei `~/.unison/default.prf` hast.
Dort definierst du z. B.:
```txt
root = /home/user/Dokumente
root = ssh://user@server//home/user/Dokumente
auto = true
batch = true
```
- **`auto = true`** → versucht, Konflikte automatisch zu lösen (kein Nachfragen bei eindeutigen Fällen).
- **`batch = true`** → führt ohne Interaktion aus.
- Falls Konflikte auftreten, entscheidet er nach den Regeln oder verweigert Sync.
- Ohne `batch` würdest du wieder Fragen im Terminal sehen.
👉 Empfehlung: Für systemd immer `auto = true` und `batch = true` setzen, sonst blockiert der Prozess.
---
## 2. Rückfragen vermeiden (Default-Verhalten)
Wie du beobachtet hast, fragt Unison bei `unison [quelle] [ziel]` ohne Konfig bei **Konflikten** („Welche Version behalten?“).
- Mit **Konfig + batch + auto** → keine Rückfragen.
- Du kannst zusätzlich Regeln setzen, z. B.:
```txt
prefer = newer # Immer die neuere Version behalten
prefer = /home/user # Lokale Version gewinnt
```
Das ist wichtig für den systemd-Einsatz, weil ein Dienst nicht sinnvoll auf Eingaben warten kann.
---
## 3. Logging
### a) Standardmäßig
Unison schreibt **keine dauerhaften Logs** von sich aus.
Die Ausgaben gehen in `stdout/stderr` → wenn du es manuell startest, siehst du es im Terminal.
### b) Mit systemd
systemd fängt alles auf → mit
```bash
journalctl --user -u unison.service
```
siehst du die Logs.
Wenn dir das reicht, brauchst du nichts extra.
### c) Eigene Logdateien
Du kannst in der `.prf`-Datei angeben:
```txt
log = /var/log/unison/unison.log
```
oder direkt beim Start per `ExecStart`:
```ini
ExecStart=/usr/bin/unison default -repeat watch -logfile /var/log/unison/unison.log
```
### d) Alte Logs automatisch löschen
Unison selbst rotiert keine Logs, aber systemd oder `logrotate` kann das übernehmen.
Beispiel `logrotate`-Konfig (`/etc/logrotate.d/unison`):
```
/var/log/unison/unison.log {
daily
rotate 30
compress
missingok
notifempty
create 640 user user
}
```
→ Hält 30 Tage Logs, dann werden sie komprimiert/gelöscht.
Wenn du lieber pro Sitzung in `/tmp` loggen willst:
```ini
ExecStart=/usr/bin/unison default -repeat watch -logfile /tmp/unison-%u.log
```
und ein Cronjob/systemd-Timer löscht alte Dateien:
```bash
find /tmp -name 'unison-*.log' -mtime +30 -delete
```
---
## 4. Fazit
- **Ja**, Config-Datei nötig → dort Batch/Auto einstellen.
- **Default-Verhalten einstellen** mit `prefer`-Regeln, sonst blockieren Konflikte.
- **Logs**: systemd-Journal reicht oft, alternativ eigene Logdatei + logrotate.
---
👉 Soll ich dir eine **komplette Beispielkonfig `default.prf` + passende systemd-Service-Datei** basteln, die direkt „Headless-Sync im Hintergrund“ macht inkl. Log-Rotation?
+230
View File
@@ -0,0 +1,230 @@
# Timeshift Kommandozeilen-Nutzung
## Überblick
Timeshift ist ein Backup-Tool für Linux-Systeme, das System-Snapshots erstellt. Es kann sowohl über eine grafische Oberfläche als auch über die Kommandozeile verwendet werden.
## Installation
```bash
# Ubuntu/Debian
sudo apt update && sudo apt install timeshift
# Arch Linux
sudo pacman -S timeshift
# Fedora/CentOS
sudo dnf install timeshift
```
## Grundlegende Konfiguration
### Initialisierung
```bash
# Timeshift einrichten (wählt automatisch RSYNC oder BTRFS)
sudo timeshift --check
# Konfiguration anzeigen
sudo timeshift --list-config
```
### Backup-Typ festlegen
```bash
# RSYNC-Modus (Standard für ext4)
sudo timeshift --rsync
# BTRFS-Modus (für BTRFS-Dateisysteme)
sudo timeshift --btrfs
```
## Snapshots erstellen
### Manuellen Snapshot erstellen
```bash
# Einfacher Snapshot
sudo timeshift --create
# Snapshot mit Kommentar
sudo timeshift --create --comments "Vor System-Update"
# Snapshot mit spezifischem Namen
sudo timeshift --create --comments "Pre-Kernel-Update-$(date +%Y%m%d)"
```
### Automatische Snapshots konfigurieren
```bash
# Tägliche Snapshots aktivieren
sudo timeshift --snapshot-device /dev/sda1 --schedule-daily
# Wöchentliche Snapshots
sudo timeshift --schedule-weekly
# Monatliche Snapshots
sudo timeshift --schedule-monthly
```
## Snapshots verwalten
### Snapshots auflisten
```bash
# Alle verfügbaren Snapshots anzeigen
sudo timeshift --list
# Detaillierte Liste
sudo timeshift --list --verbose
```
### Snapshot-Informationen anzeigen
```bash
# Informationen zu einem spezifischen Snapshot
sudo timeshift --list | grep "2024-01-15"
```
## System wiederherstellen
### Komplette Systemwiederherstellung
```bash
# Neuesten Snapshot wiederherstellen
sudo timeshift --restore
# Spezifischen Snapshot wiederherstellen
sudo timeshift --restore --snapshot "2024-01-15_18-30-45"
# Wiederherstellung mit Bestätigung
sudo timeshift --restore --snapshot "2024-01-15_18-30-45" --skip-grub
```
### Einzelne Dateien wiederherstellen
```bash
# Snapshot mounten (nur-lesen)
sudo timeshift --restore --snapshot "2024-01-15_18-30-45" --clone
# Dann Dateien manuell kopieren
cp /timeshift/snapshots/2024-01-15_18-30-45/localhost/path/to/file /original/path/
```
## TTY-Sitzung (Notfall-Wiederherstellung)
### Zugang zur TTY
```bash
# Wechsel zu TTY (Strg+Alt+F1 bis F6)
# Oder über SSH wenn verfügbar
```
### Wiederherstellung in TTY
```bash
# 1. Als root anmelden
sudo su -
# 2. Snapshots auflisten
timeshift --list
# 3. System wiederherstellen
timeshift --restore --snapshot "SNAPSHOT_NAME"
# 4. System neustarten
reboot
```
### Notfall-Boot von Live-USB
```bash
# 1. Live-USB booten
# 2. Festplatte mounten
sudo mount /dev/sda1 /mnt
# 3. Timeshift auf Live-System installieren
sudo apt update && sudo apt install timeshift
# 4. Wiederherstellung auf gemountete Partition
sudo timeshift --restore --target-device /dev/sda1
```
## Nützliche Optionen
### Backup-Ausschlüsse konfigurieren
```bash
# Bestimmte Verzeichnisse ausschließen
sudo timeshift --exclude /home/user/Downloads
sudo timeshift --exclude /tmp
sudo timeshift --exclude /var/cache
```
### Aufbewahrungsrichtlinien
```bash
# Maximale Anzahl Snapshots begrenzen
sudo timeshift --max-snapshots 5
# Alte Snapshots automatisch löschen
sudo timeshift --delete-old
```
### Snapshot löschen
```bash
# Spezifischen Snapshot löschen
sudo timeshift --delete --snapshot "2024-01-15_18-30-45"
# Alle bis auf die letzten 3 löschen
sudo timeshift --delete-old --max-snapshots 3
```
## Automatisierung mit Cron
### Tägliche Backups einrichten
```bash
# Crontab bearbeiten
sudo crontab -e
# Tägliches Backup um 2:00 Uhr
0 2 * * * /usr/bin/timeshift --create --comments "Daily-Auto-$(date +\%Y\%m\%d)" && /usr/bin/timeshift --delete-old --max-snapshots 7
```
## Monitoring und Logs
### Status überprüfen
```bash
# Timeshift-Status
sudo timeshift --check
# Logs anzeigen
sudo journalctl -u timeshift
tail -f /var/log/timeshift.log
```
### Speicherplatz überwachen
```bash
# Snapshot-Größen anzeigen
du -sh /timeshift/snapshots/*
# Verfügbaren Speicher prüfen
df -h /timeshift
```
## Troubleshooting
### Häufige Probleme
```bash
# Berechtigungen reparieren
sudo timeshift --check
# Cache leeren
sudo rm -rf /tmp/timeshift*
# Snapshot-Index reparieren
sudo timeshift --delete-old --scripted
```
### Recovery bei korrupten Snapshots
```bash
# Snapshot-Konsistenz prüfen
sudo timeshift --list --check-snapshots
# Defekte Snapshots entfernen
sudo timeshift --delete --snapshot "CORRUPT_SNAPSHOT"
```
---
**Wichtige Hinweise:**
- Immer mit `sudo` ausführen
- Vor wichtigen Systemänderungen Snapshots erstellen
- Regelmäßig alte Snapshots löschen (Speicherplatz)
- Bei BTRFS-Systemen BTRFS-Modus verwenden
- Boot-Snapshots für kritische Updates erstellen
@@ -0,0 +1,111 @@
Diese Anleitung zeigt, wie du einen USB-Stick über die Kommandozeile sicher formatierst.
⚠️ **Achtung:** Falsche Gerätenamen können zu Datenverlust führen.
---
## 1. USB-Stick identifizieren
Liste alle Laufwerke auf:
```bash
lsblk
```
Beispielausgabe:
```
sda 500G
sdb 16G ← USB-Stick
```
> **Merke dir den Gerätenamen des USB-Sticks**, z. B. `/dev/sdb`.
---
## 2. USB-Stick aushängen
Falls der Stick automatisch eingehängt wurde:
```bash
sudo umount /dev/sdb*
```
---
## 3. Optional: Stick vollständig säubern
Entfernt alte Partitionstabellen:
```bash
sudo wipefs -a /dev/sdb
```
---
## 4. Neue Partitionstabelle anlegen (MBR)
```bash
sudo parted /dev/sdb mklabel msdos
```
---
## 5. Eine neue Partition über den gesamten Stick erstellen
```bash
sudo parted -a optimal /dev/sdb mkpart primary fat32 0% 100%
```
> Wenn du ein anderes Dateisystem planst, kannst du `fat32` durch einen anderen Typ ersetzen (z. B. `ext4`).
---
## 6. Dateisystem erstellen
### FAT32 (am kompatibelsten)
```bash
sudo mkfs.vfat -F 32 /dev/sdb1
```
### exFAT
```bash
sudo mkfs.exfat /dev/sdb1
```
### NTFS
```bash
sudo mkfs.ntfs -Q /dev/sdb1
```
### ext4 (für Linux-Systeme)
```bash
sudo mkfs.ext4 /dev/sdb1
```
---
## 7. Stick entfernen und neu verbinden
Der Stick wird beim Wiedereinstecken normalerweise automatisch eingehängt.
---
## 8. Optional: Label setzen
```bash
sudo fatlabel /dev/sdb1 MEINUSB
```
Für ext4:
```bash
sudo e2label /dev/sdb1 MEINUSB
```
---
Wenn du möchtest, erstelle ich dir auch eine Version als **Obsidian-Template**, z. B. mit Variablen oder Checkboxen.
+458
View File
@@ -0,0 +1,458 @@
Hier ist ein kompaktes, aber vollständiges **VIM Cheat Sheet** 📝
---
## 🔹 Modi in VIM
|Modus|Bedeutung|Wechsel|
|---|---|---|
|**Normal Mode**|Navigation & Befehle|`Esc`|
|**Insert Mode**|Texteingabe|`i`, `a`, `o`, etc.|
|**Visual Mode**|Text markieren|`v`, `V`, `Ctrl+v`|
|**Command Mode**|Speichern, Beenden, etc.|`:`|
---
## 🔹 Insert Mode Befehle
|Befehl|Wirkung|
|---|---|
|`i`|Vor Cursor einfügen|
|`a`|Nach Cursor einfügen|
|`I`|Am Zeilenanfang einfügen|
|`A`|Am Zeilenende einfügen|
|`o`|Neue Zeile unterhalb|
|`O`|Neue Zeile oberhalb|
---
## 🔹 Navigation (Normal Mode)
### Zeichenweise
```
h ← j ↓ k ↑ l →
```
### Wortweise
```
w nächstes Wort
b vorheriges Wort
e Wortende
```
### Zeilenweise
```
0 Zeilenanfang
^ Erstes Nicht-Leerzeichen
$ Zeilenende
```
### Datei
```
gg Anfang der Datei
G Ende der Datei
:n Gehe zu Zeile n
```
---
## 🔹 Löschen
|Befehl|Wirkung|
|---|---|
|`x`|Zeichen löschen|
|`dd`|Zeile löschen|
|`dw`|Wort löschen|
|`d$`|Bis Zeilenende löschen|
|`d0`|Bis Zeilenanfang löschen|
💡 Kombination: `d` + Bewegung funktioniert immer
(z.B. `d3w` = 3 Wörter löschen)
---
## 🔹 Kopieren & Einfügen
|Befehl|Wirkung|
|---|---|
|`yy`|Zeile kopieren|
|`yw`|Wort kopieren|
|`p`|Nach Cursor einfügen|
|`P`|Vor Cursor einfügen|
#### Register
Vor alle Kopieren oder Einfügen Befehle kann ein `"3` gestellt werden, um ins 3. Register zu schreiben bzw. daraus heraus zu lesen. Z.b. kopiert `"7yw` das Wort ins 7. Register und `"4p` fügt das 4. Register nach dem Curser ein.
💡 Das spezielle Register `+`/`*` ist das System-Clipboard, sehr Praktisch zum Austausch von Text mit anderen Programmen
Alle Register ansehen: `:reg`
💡 Das spezielle Register `%` enthält den aktuellen Dateipfad -> aktuelle Dateipfad in System-Clipboard: `:let @+=@%`.
---
## 🔹 Undo / Redo
```
u Undo
Ctrl+r Redo
```
---
## 🔹 Visual Mode
|Befehl|Wirkung|
|---|---|
|`v`|Zeichenweise markieren|
|`V`|Ganze Zeile markieren|
|`Ctrl+v`|Block markieren|
Nach Markierung:
```
d löschen
y kopieren
> einrücken
< ausrücken
```
---
## 🔹 Suchen & Ersetzen
```
/text Vorwärts suchen
?text Rückwärts suchen
n Nächstes Ergebnis
N Vorheriges Ergebnis
```
Ersetzen:
```
:%s/alt/neu/g Ganze Datei
:s/alt/neu/g Aktuelle Zeile
:%s/alt/neu/gc Mit Bestätigung
```
---
## 🔹 Speichern & Beenden
```
:w Speichern
:q Beenden
:wq Speichern & Beenden
:x Speichern & Beenden
:q! Ohne Speichern beenden
```
---
## 🔹 Fenster & Tabs
```
:split Horizontal teilen
:vsplit Vertikal teilen
Ctrl+w w Zwischen Fenstern wechseln
:tabnew Neuer Tab
gt Nächster Tab
gT Vorheriger Tab
```
---
## 🔹 Nützliche Shortcuts
```
. Letzte Aktion wiederholen
>> Zeile einrücken
<< Zeile ausrücken
ciw Wort ändern
cc Zeile ändern
J Zeilen zusammenführen
```
---
## 🔹 Makros
```
qa Aufnahme in Register a starten
q Aufnahme stoppen
@a Makro a ausführen
@@ Letztes Makro wiederholen
```
---
## 🔹 Zahlen-Präfixe (Sehr wichtig!)
Viele Befehle lassen sich multiplizieren:
```
3dd 3 Zeilen löschen
5w 5 Wörter vor
2yy 2 Zeilen kopieren
```
---
# Zeilennummern aus- und anschalten
---
## 🔹 Absolute Zeilennummern
### Einschalten:
```vim
:set number
```
### Ausschalten:
```vim
:set nonumber
```
### Toggle:
```vim
:set number!
```
---
## 🔹 Relative Zeilennummern
### Einschalten:
```vim
:set relativenumber
```
### Ausschalten:
```vim
:set norelativenumber
```
### Toggle:
```vim
:set relativenumber!
```
---
## 🔹 Absolute + Relative kombinieren (Sehr beliebt 🔥)
Viele nutzen diese Kombination:
```vim
:set number relativenumber
```
👉 Ergebnis:
* Aktuelle Zeile = **absolute Nummer**
* Alle anderen Zeilen = **relative Nummern**
Beispiel:
```
8
2
1
10 ← aktuelle Zeile
1
2
3
```
Das ist perfekt für Bewegungen wie:
```
5j
3k
```
---
## 🔹 Dauerhaft aktivieren (.vimrc)
In deiner `~/.vimrc`:
```vim
set number
set relativenumber
```
---
## 🔹 Smart Toggle Mapping (Optional ⭐)
Viele nutzen ein Keybinding:
```vim
nnoremap <leader>n :set number! relativenumber!<CR>
```
Dann kannst du mit:
```
\ n
```
(beim Standard-`leader`) beide gleichzeitig toggeln.
---
# Block Aus- und Einkommentieren
---
# 🔹 1️⃣ Rein mit Vim (ohne Plugin)
## ✅ Ganze Zeilen im Visual Mode kommentieren
### Schritt 1: Block markieren
* `V` → Zeilenweise markieren
* `j / k` → Bereich wählen
### Schritt 2: Kommentarzeichen einfügen
Beispiel für `#`:
```vim
:s/^/# /
```
Im Visual Mode einfach:
```vim
:'<,'>s/^/# /
```
👉 Fügt `# ` am Anfang jeder markierten Zeile ein.
---
## 🔹 Auskommentieren
```vim
:'<,'>s/^# //
```
---
## 🔹 Noch schneller (ohne `:` tippen)
Markieren mit `V`, dann:
```vim
:s/^/# /
```
Vim setzt `'<,'>` automatisch.
---
# 🔹 2️⃣ Noch effizienter: Visual Block Mode (Sehr elegant ⚡)
Perfekt für feste Kommentarzeichen wie `#`, `//`, `--`.
### Schritt 1
```
Ctrl + v
```
### Schritt 2
Mit `j/k` mehrere Zeilen markieren (nur Spalte 0)
### Schritt 3
```
Shift + i
#
Esc
```
💥 Vim fügt das in alle markierten Zeilen ein.
---
## 🔹 Entfernen mit Block Mode
1. `Ctrl + v`
2. Erste 2 Zeichen (`# `) markieren
3. `d`
---
# 🔹 3️⃣ Beste Lösung: Plugin (Empfohlen 🔥)
Wenn du regelmäßig kommentierst → nimm ein Plugin.
Sehr beliebt:
* vim-commentary von Tim Pope
### Installation (mit vim-plug):
```vim
Plug 'tpope/vim-commentary'
```
### Nutzung:
* `gcc` → aktuelle Zeile toggeln
* `gc` (im Visual Mode) → Block toggeln
💎 Vorteil:
* erkennt automatisch Kommentarzeichen je nach Dateityp
* funktioniert mit `//`, `#`, `--`, `/* */`, etc.
---
# 🔹 4️⃣ Absolute Power-User Lösung (Ohne Plugin, aber smart)
In `.vimrc`:
```vim
vnoremap <leader>c :s/^/# /<CR>
vnoremap <leader>u :s/^# //<CR>
```
Dann:
```
\c → kommentieren
\u → auskommentieren
```
---
# 🔥 Meine Empfehlung
| Wenn du... | Lösung |
| ----------------------------- | ----------------- |
| Nur selten kommentierst | Visual Block Mode |
| Viel programmierst | vim-commentary |
| Minimalistisch bleiben willst | eigenes Mapping |
---
# Verschiedenes
- `%`: zur nächsten Klammer
- `TOhtml`: HTML Export
- `:ls`: Buffer anzeigen -> `:b 3` den 3. Buffer öffnen
- `.` : letzte Aktion wiederholen
- `:e path/to/file` öffnet Datei, nur `:e` aktualisiert die geöffnete Datei, `:e!` verwirft dabei alle Änderungen
+232
View File
@@ -0,0 +1,232 @@
# Anleitung: Windows-Programme unter Linux mit **Wine** in einer eigenen Umgebung installieren
Diese Anleitung zeigt dir, wie du **Windows-Programme unter Linux mithilfe von Wine** installierst **pro Programm in einer eigenen isolierten Wine-Umgebung (Wineprefix)**.
Die Schritte funktionieren unter den meisten Linux-Distributionen (Ubuntu, Fedora, Arch, etc.).
---
## ⭐ Grundbegriffe
### **Wine**
Wine ist eine Kompatibilitätsschicht, die Windows-Programme unter Linux ausführen kann.
### **Wineprefix**
Ein *Wineprefix* ist eine Art eigener Windows-Ordner (inkl. Registry, Laufwerke, DLLs).
Standard: `~/.wine` wir nutzen jedoch **pro Programm einen eigenen Prefix**, z. B.:
```
~/wineprefixes/MeinProgramm
````
Das verhindert Konflikte zwischen Programmen.
---
## 🛠️ Voraussetzungen
### Wine & Winetricks installieren
**Ubuntu/Debian**
```bash
sudo apt update
sudo apt install wine winetricks
````
**Fedora**
```bash
sudo dnf install wine winetricks
```
**Arch Linux / Manjaro**
```bash
sudo pacman -S wine winetricks
```
> Optional: Für bessere Kompatibilität empfiehlt sich _winehq-staging_.
---
## 📁 1. Eigenen Wineprefix anlegen
Ersetze `<PROGRAMMNAME>` durch den gewünschten Namen.
```bash
export WINEPREFIX="$HOME/wineprefixes/<PROGRAMMNAME>"
wineboot --init
```
Ordnerstruktur anlegen (falls noch nicht vorhanden):
```bash
mkdir -p "$HOME/wineprefixes"
```
---
## 🧩 2. Architektur festlegen (32- oder 64-bit)
### 32-bit Prefix (für ältere Programme empfohlen)
```bash
export WINEARCH=win32
export WINEPREFIX="$HOME/wineprefixes/<PROGRAMMNAME>"
wineboot --init
```
### 64-bit Prefix
```bash
export WINEARCH=win64
export WINEPREFIX="$HOME/wineprefixes/<PROGRAMMNAME>"
wineboot --init
```
---
## 🧰 3. Prefix konfigurieren (optional)
### Wine-Konfiguration starten
```bash
export WINEPREFIX="$HOME/wineprefixes/<PROGRAMMNAME>"
winecfg
```
Hier kannst du z. B. einstellen:
- Windows-Version (Win7, Win10, Win11)
- Grafikoptionen
- Audiotreiber
---
## 📦 4. Winetricks nutzen (DLLs, Fonts, Komponenten)
Beispiel: .NET 4.8 & corefonts installieren:
```bash
export WINEPREFIX="$HOME/wineprefixes/<PROGRAMMNAME>"
winetricks dotnet48 corefonts
```
Winetricks GUI öffnen:
```bash
winetricks --gui
```
---
## 📥 5. Windows-Programm installieren
Beispiel mit einer `setup.exe`:
```bash
export WINEPREFIX="$HOME/wineprefixes/<PROGRAMMNAME>"
wine ~/Downloads/setup.exe
```
Installer wie gewohnt durchklicken.
---
## ▶️ 6. Programm starten
Wenn das Programm z. B. `Programm.exe` heißt:
```bash
export WINEPREFIX="$HOME/wineprefixes/<PROGRAMMNAME>"
wine "$WINEPREFIX/drive_c/Program Files/<Hersteller>/<Programm>/Programm.exe"
```
---
## 📌 7. Starter (Desktop-Shortcut) erstellen
Erstelle eine Datei:
```
~/.local/share/applications/<programm>.desktop
```
Inhalt:
```desktop
[Desktop Entry]
Name=<PROGRAMMNAME>
Exec=env WINEPREFIX="/home/$USER/wineprefixes/<PROGRAMMNAME>" wine "C:/Program Files/<Hersteller>/<Programm>/Programm.exe"
Type=Application
Categories=Utility;
```
Datei ausführbar machen:
```bash
chmod +x ~/.local/share/applications/<programm>.desktop
```
---
## 🧼 8. Prefix entfernen
Wenn du das Programm löschen möchtest:
```bash
rm -rf "$HOME/wineprefixes/<PROGRAMMNAME>"
```
---
## 🔍 Zusatz: Nützliche Tools
### Wine Logs anzeigen
```bash
WINEPREFIX="$HOME/wineprefixes/<PROGRAMMNAME>" wine Programm.exe &> log.txt
```
### Abhängigkeiten prüfen
```bash
winetricks dlls list
```
---
## 📚 Tipps & Best Practices
- **Jedes Programm bekommt seinen eigenen Prefix** → weniger Konflikte.
- Für Spiele: **Lutris** oder **Bottles** nutzen.
- Für Office-Software häufig nötig: `dotnet48`, `corefonts`, `vcrun2015`.
- Falls ein Programm Probleme macht:
→ WineHQ AppDB durchsuchen (Kompatibilitätsdatenbank).
---
## ✔️ Zusammenfassung
1. Wine & Winetricks installieren
2. Eigenen Prefix erstellen
3. Architektur festlegen (32/64 bit)
4. Wine konfigurieren
5. Benötigte Komponenten via Winetricks installieren
6. Setup des Programms ausführen
7. Starter optional erstellen
+106
View File
@@ -0,0 +1,106 @@
# 🧭 Übersicht: `/etc/fstab` Netzlaufwerke & SSHFS
Diese Datei enthält Einträge für automatisch eingehängte Netzlaufwerke.
Wichtig: Teste Änderungen **immer** mit
```bash
sudo mount -a
```
um Syntaxfehler zu erkennen, bevor du neustartest.
→ siehe [[fstab Grundlagen]]
---
## 🗂️ NAS-Laufwerke via NFS
```fstab
192.168.0.14:/volume1/Gemeinsam /mnt/nas/gemeinsam nfs nfsvers=3,rw,_netdev,noac,actimeo=0 0 0
```
**Annahmen:**
- NAS-IP: `192.168.0.14`
- Freigabe (Quelle): `/volume1/Gemeinsam`
- Lokaler Mountpoint (Ziel): `/mnt/nas/gemeinsam`
**Erläuterung der Optionen:**
- `nfsvers=3` → nutzt NFSv3 (älter, aber oft stabiler bei Synology)
- `rw` → Schreib-/Lesezugriff
- `_netdev` → mountet erst, wenn Netzwerk verfügbar ist
- `noac` → deaktiviert Client-Caching (nützlich bei Dateisynchronisierung, kann Performance senken)
- `actimeo=0` → setzt Cache-Timeout auf 0 (Dateiattribute werden immer neu gelesen)
👉 siehe [[NFS unter Linux]] und [[NFS Mount Optionen]]
💡 *Tipp:*
Bei neueren Systemen oder stabilen Netzwerken ist `nfsvers=4` meist die bessere Wahl. Beispiel:
```fstab
192.168.0.14:/volume1/Gemeinsam /mnt/nas/gemeinsam nfs nfsvers=4,rw,_netdev 0 0
```
📦 **Benötigtes Paket (Debian/Ubuntu):**
```bash
sudo apt install nfs-common
```
→ siehe [[NFS Client Installation]]
---
## ☁️ HiDrive via SFTP (SSHFS)
```fstab
mathias2784@sftp.hidrive.strato.com:/users/mathias2784 /mnt/hidrive fuse.sshfs defaults,_netdev,IdentityFile=/home/mathias/.ssh/id_ed25519,allow_other 0 0
```
**Erläuterung der Optionen:**
- `fuse.sshfs` → nutzt das FUSE-Modul für SSHFS
- `_netdev` → warte auf Netzwerk
- `IdentityFile=...` → Pfad zum SSH-Key
- `allow_other` → erlaubt Zugriff auch für andere Nutzer (Achtung: [[SSHFS Sicherheit]])
👉 siehe [[SSHFS unter Linux]] und [[HiDrive Konfiguration]]
💡 *Tipp:*
Füge optional `reconnect,ServerAliveInterval=15,ServerAliveCountMax=3` hinzu, damit die Verbindung stabil bleibt:
```fstab
mathias2784@sftp.hidrive.strato.com:/users/mathias2784 /mnt/hidrive fuse.sshfs _netdev,IdentityFile=/home/mathias/.ssh/id_ed25519,allow_other,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 0 0
```
📦 **Benötigtes Paket (Debian/Ubuntu):**
```bash
sudo apt install sshfs
```
→ siehe [[SSHFS Installation]]
---
## 🖥️ "Schneiderserver" via SSHFS
```fstab
root@schneiderserver.site:/root /mnt/strato_vm fuse.sshfs _netdev,IdentityFile=/home/mathias/.ssh/id_ed25519_strato_vm,allow_other 0 0
```
**Optionen wie oben**, jedoch:
- Zugriff als `root` nur wenn zwingend notwendig (besser: Benutzer mit begrenzten Rechten)
- Key-File ggf. mit restriktiven Rechten (`chmod 600`)
👉 siehe [[SSH Sicherheit]] und [[Root via SSH vermeiden]]
📦 **Benötigtes Paket (Debian/Ubuntu):**
```bash
sudo apt install sshfs
```
---
## ✅ Allgemeine Hinweise
- Testen: `sudo mount -a`
- Mounten einzelner Einträge:
```bash
sudo mount /mnt/hidrive
```
- Logs prüfen bei Problemen:
```bash
sudo journalctl -xe | grep sshfs
```
Weitere Themen: [[fstab Optionen Übersicht]], [[Mount Fehlerbehebung]], [[Systemd Automounts]]
+479
View File
@@ -0,0 +1,479 @@
# Snapper Anleitung für CachyOS - Detaillierte Version
## Was ist Snapper?
Snapper ist ein Tool für BTRFS-Dateisysteme, das automatisch Snapshots (Momentaufnahmen) erstellt. Diese Snapshots sind wie "Wiederherstellungspunkte" - sie speichern den Zustand deines Systems zu einem bestimmten Zeitpunkt, ohne zusätzlichen Speicherplatz für unveränderte Dateien zu verbrauchen.
## Installation mit pacman
```bash
# Hauptpakete installieren
sudo pacman -S snapper # Das eigentliche Snapper-Tool
sudo pacman -S snap-pac # Automatische Snapshots bei pacman-Operationen
sudo pacman -S snapper-gui-git # Grafische Benutzeroberfläche (optional)
# Optional: Für GRUB-Integration (Boot-Menü mit Snapshots)
sudo pacman -S grub-btrfs # Zeigt Snapshots im GRUB-Boot-Menü an
```
## Grundkonfiguration verstehen
### 1. Snapper-Konfiguration für Root erstellen
```bash
# Falls bereits eine Konfiguration existiert, diese entfernen
sudo umount /.snapshots 2>/dev/null || true
sudo rm -rf /.snapshots
# Neue Snapper-Konfiguration für das Root-Dateisystem erstellen
# Dies erstellt automatisch eine Konfigurationsdatei unter /etc/snapper/configs/root
sudo snapper -c root create-config /
# Das automatisch erstellte .snapshots Verzeichnis ist ein normaler Ordner
# Wir brauchen aber ein BTRFS-Subvolume für bessere Performance
sudo btrfs subvolume delete /.snapshots
sudo mkdir /.snapshots
# Subvolume in /etc/fstab eintragen (wird automatisch gemacht)
sudo mount -a
```
**Was passiert hier?**
- `-c root` = Konfigurationsname "root"
- `create-config /` = Erstelle Konfiguration für das Verzeichnis `/`
- Ein BTRFS-Subvolume ist effizienter als ein normaler Ordner für Snapshots
### 2. Konfigurationsdatei im Detail
```bash
sudo nano /etc/snapper/configs/root
```
**Wichtige Parameter erklärt:**
```ini
# SUBVOLUME: Das zu überwachende Verzeichnis
SUBVOLUME="/"
# FSTYPE: Dateisystemtyp (muss btrfs sein)
FSTYPE="btrfs"
# ALLOW_USERS/ALLOW_GROUPS: Welche Benutzer dürfen Snapshots verwalten?
ALLOW_USERS="dein-benutzername"
ALLOW_GROUPS="wheel"
# SYNC_ACL: Access Control Lists synchronisieren
SYNC_ACL="no"
# === TIMELINE SNAPSHOTS (zeitbasierte automatische Snapshots) ===
# TIMELINE_CREATE: Sollen automatische zeitbasierte Snapshots erstellt werden?
TIMELINE_CREATE="yes"
# TIMELINE_CLEANUP: Sollen alte Timeline-Snapshots automatisch gelöscht werden?
TIMELINE_CLEANUP="yes"
# Wie viele Timeline-Snapshots sollen behalten werden?
TIMELINE_MIN_AGE="1800" # Mindestens 30 Minuten alt bevor Löschung möglich
TIMELINE_LIMIT_HOURLY="10" # Maximal 10 stündliche Snapshots
TIMELINE_LIMIT_DAILY="10" # Maximal 10 tägliche Snapshots
TIMELINE_LIMIT_WEEKLY="0" # Keine wöchentlichen Snapshots
TIMELINE_LIMIT_MONTHLY="10" # Maximal 10 monatliche Snapshots
TIMELINE_LIMIT_YEARLY="10" # Maximal 10 jährliche Snapshots
# === NUMBER CLEANUP (Bereinigung nach Anzahl) ===
# NUMBER_CLEANUP: Snapshots nach Anzahl begrenzen?
NUMBER_CLEANUP="yes"
# NUMBER_MIN_AGE: Snapshots müssen mindestens so alt sein (Sekunden)
NUMBER_MIN_AGE="1800" # 30 Minuten
# NUMBER_LIMIT: Maximale Gesamtanzahl an Snapshots
NUMBER_LIMIT="50"
# NUMBER_LIMIT_IMPORTANT: Wichtige Snapshots (pre/post) getrennt begrenzen
NUMBER_LIMIT_IMPORTANT="10"
# === EMPTY CLEANUP (leere Snapshots löschen) ===
EMPTY_PRE_POST_CLEANUP="yes" # Leere Pre/Post-Snapshot-Paare löschen
EMPTY_PRE_POST_MIN_AGE="1800"
```
**Was bedeuten die verschiedenen Snapshot-Typen?**
- **Timeline**: Automatisch nach Zeit erstellt (stündlich, täglich, etc.)
- **Pre/Post**: Vor und nach Systemänderungen (z.B. Package-Updates)
- **Single**: Einzelne manuelle Snapshots
## Ein- und Ausgeschlossene Verzeichnisse verstehen
### Automatisch eingeschlossene Verzeichnisse
Standardmäßig wird **alles unter `/` gesnappt**, außer:
```bash
# Diese Verzeichnisse werden NIEMALS gesnappt (hardcoded in Snapper):
/dev/* # Device-Dateien (virtuelle Dateien)
/proc/* # Process-Informationen (virtuelle Dateien)
/sys/* # System-Informationen (virtuelle Dateien)
/tmp/* # Temporäre Dateien
/run/* # Runtime-Daten
/mnt/* # Mount-Punkte
/media/* # Wechseldatenträger
```
### Zusätzliche Ausschlüsse konfigurieren
**Option 1: Exclude-Patterns in der Hauptkonfiguration**
```bash
sudo nano /etc/snapper/configs/root
```
Füge hinzu:
```ini
# EXCLUDE_PATTERNS: Glob-Patterns für auszuschließende Dateien/Ordner
EXCLUDE_PATTERNS="/var/cache/* /var/tmp/* /var/log/* /home/*/.cache/* /root/.cache/*"
```
**Option 2: Separate Filter-Datei (empfohlen)**
```bash
# Filter-Datei erstellen
sudo mkdir -p /etc/snapper/filters
sudo nano /etc/snapper/filters/root.txt
```
Inhalt mit Erklärungen:
```bash
# Cache-Verzeichnisse (können jederzeit neu erstellt werden)
/var/cache/*
/home/*/.cache/*
/root/.cache/*
# Temporäre Dateien
/var/tmp/*
/tmp/*
# Log-Dateien (werden laufend überschrieben, Snapshots wenig sinnvoll)
/var/log/*
# Browser-Profile (sehr große, häufig ändernde Dateien)
/home/*/.mozilla/firefox/*/Cache/*
/home/*/.config/google-chrome/Default/Cache/*
# Papierkorb
/home/*/.local/share/Trash/*
# Downloads (optional - je nach Bedarf)
# /home/*/Downloads/*
# Virtuelle Maschinen (sehr groß)
/home/*/.local/share/libvirt/*
/var/lib/libvirt/*
# Docker-Daten (sehr groß und dynamisch)
/var/lib/docker/*
```
Dann in der Hauptkonfiguration referenzieren:
```ini
# In /etc/snapper/configs/root hinzufügen:
EXCLUDE_FILE="/etc/snapper/filters/root.txt"
```
### Warum diese Ausschlüsse?
- **Cache-Verzeichnisse**: Werden automatisch neu erstellt, verschwenden nur Platz
- **Log-Dateien**: Ändern sich ständig, Snapshots helfen nicht bei der Fehlersuche
- **Temporäre Dateien**: Per Definition temporär
- **Browser-Caches**: Riesig und unwichtig für System-Recovery
- **VM/Docker-Daten**: Sehr groß, haben eigene Backup-Strategien
## Manuelle Snapshots erstellen
### Einfache Snapshots
```bash
# Einfacher Snapshot mit Beschreibung
sudo snapper -c root create -d "Vor Firefox-Installation"
# Snapshot mit benutzerdefinierten Attributen
sudo snapper -c root create -d "Backup vor Kernel-Update" -u "important=yes"
```
### Pre/Post-Snapshot-Paare (empfohlen für größere Änderungen)
```bash
# 1. PRE-Snapshot erstellen (vor der Änderung)
sudo snapper -c root create -t pre -p -d "Vor großem System-Update"
# Merke dir die Nummer! Z.B. "42"
# 2. Deine Systemänderungen durchführen
sudo pacman -Syu
# 3. POST-Snapshot erstellen (nach der Änderung)
sudo snapper -c root create -t post --pre-number 42 -d "Nach großem System-Update"
```
**Warum Pre/Post-Paare?**
- Snapper kann exakt die Unterschiede zwischen vorher/nachher zeigen
- Einfacheres Rollback nur der Änderungen
- Bessere Übersicht was sich geändert hat
### Snapshots verwalten
```bash
# Alle Snapshots auflisten
sudo snapper -c root list
# Detaillierte Ansicht mit Größe
sudo snapper -c root list -t all
# Informationen zu einem bestimmten Snapshot
sudo snapper -c root info 42
# Unterschiede zwischen zwei Snapshots anzeigen
sudo snapper -c root status 40..45
# Geänderte Dateien zwischen Snapshots zeigen
sudo snapper -c root diff 40..45
```
## Automatisierung der Snapshot-Erstellung
### 1. Timeline-Snapshots (zeitbasiert)
```bash
# Systemd-Timer für stündliche Timeline-Snapshots aktivieren
sudo systemctl enable --now snapper-timeline.timer
# Timer für automatische Bereinigung alter Snapshots aktivieren
sudo systemctl enable --now snapper-cleanup.timer
# Status der Timer prüfen
systemctl status snapper-timeline.timer
systemctl status snapper-cleanup.timer
# Nächste geplante Ausführung anzeigen
systemctl list-timers | grep snapper
```
**Was macht snapper-timeline.timer?**
- Läuft stündlich
- Erstellt automatisch Timeline-Snapshots basierend auf der Konfiguration
- Berücksichtigt die TIMELINE_LIMIT-Einstellungen
**Was macht snapper-cleanup.timer?**
- Läuft täglich
- Löscht alte Snapshots basierend auf den Cleanup-Regeln
- Verhindert, dass das System mit Snapshots volläuft
### 2. Automatische Snapshots bei Package-Updates
Das Paket `snap-pac` erstellt automatisch Pre/Post-Snapshots bei jeder pacman-Operation.
```bash
# Konfiguration von snap-pac anpassen
sudo nano /etc/snap-pac.ini
```
```ini
[DEFAULT]
# Maximale Länge der Snapshot-Beschreibung
desc_limit = 72
# Standard-Beschreibungen für automatische Snapshots
pre_description = pacman pre snapshot
post_description = pacman post snapshot
# Soll snap-pac auch bei AUR-Helper-Updates Snapshots erstellen?
aur_helper = yay,paru,pikaur
[root]
# Snapshots für das root-Subvolume aktivieren
snapshot = yes
# Welche Cleanup-Strategie verwenden?
cleanup = number
# Soll snap-pac auch bei normalen pacman-Operationen (nicht nur -S) Snapshots erstellen?
important = yes
```
**Was passiert jetzt?**
- Bei jedem `sudo pacman -S paket` → automatisches Pre/Post-Snapshot-Paar
- Bei `yay -S aur-paket` → ebenfalls Snapshots (wenn konfiguriert)
- Bei `sudo pacman -R paket` → ebenfalls Snapshots
### 3. GRUB-Integration für Boot-Menü
```bash
# GRUB-Btrfs-Daemon aktivieren (überwacht Snapshot-Änderungen)
sudo systemctl enable --now grub-btrfsd
# Initramfs-Hook für Snapshot-Booting hinzufügen
sudo nano /etc/mkinitcpio.conf
```
In der HOOKS-Zeile hinzufügen:
```bash
HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block filesystems grub-btrfs-overlayfs fsck)
```
```bash
# Initramfs neu generieren
sudo mkinitcpio -P
# GRUB-Konfiguration aktualisieren
sudo grub-mkconfig -o /boot/grub/grub.cfg
```
**Was bringt das?**
- Im GRUB-Boot-Menü erscheint ein neuer Eintrag "Snapshots for GNU/Linux"
- Du kannst direkt von einem Snapshot booten ohne das System zu ändern
- Perfekt um zu testen, ob ein älterer Zustand das Problem löst
## Snapshots wiederherstellen
### 1. Einzelne Dateien wiederherstellen
```bash
# Snapshot mounten (macht ihn als Verzeichnis verfügbar)
sudo snapper -c root mount 42
# Jetzt ist der Snapshot verfügbar unter:
# /.snapshots/42/snapshot/
# Beispiel: Konfigurationsdatei wiederherstellen
sudo cp /.snapshots/42/snapshot/etc/fstab /etc/fstab
# Beispiel: Ganzes Verzeichnis wiederherstellen
sudo cp -r /.snapshots/42/snapshot/etc/NetworkManager/ /etc/
# Snapshot wieder unmounten (Speicher freigeben)
sudo snapper -c root umount 42
```
### 2. Änderungen zwischen Snapshots rückgängig machen
```bash
# Zeige was sich zwischen zwei Snapshots geändert hat
sudo snapper -c root status 40..45
# Mache alle Änderungen zwischen den Snapshots rückgängig
sudo snapper -c root undochange 40..45
# Alternativ: Rollback zu einem bestimmten Snapshot
sudo snapper -c root rollback 42
```
**Vorsicht bei undochange:**
- Überschreibt aktuelle Dateien!
- Erstelle vorher einen aktuellen Snapshot als Backup
- Teste erst in einer nicht-kritischen Umgebung
### 3. Komplettes System-Rollback (für Experten)
```bash
# ACHTUNG: Dies überschreibt dein aktuelles System!
# Erstelle erst einen Snapshot des aktuellen Zustands
sudo snapper -c root create -d "Vor Rollback - Notfall-Backup"
# Zeige verfügbare Snapshots
sudo snapper -c root list
# Rollback zu Snapshot (z.B. Nummer 42)
sudo btrfs subvolume snapshot /.snapshots/42/snapshot /
```
### 4. Boot von Snapshot über GRUB
Wenn grub-btrfs installiert ist:
1. **Computer neu starten**
2. **Im GRUB-Menü**: "Snapshots for GNU/Linux" wählen
3. **Snapshot auswählen**: Den gewünschten Snapshot aus der Liste wählen
4. **System startet** vom gewählten Snapshot (read-only)
5. **Wenn alles funktioniert**: `sudo snapper rollback` um permanent zu wechseln
## Überwachung und Wartung
### Speicherplatz überwachen
```bash
# BTRFS-Dateisystem-Nutzung anzeigen
sudo btrfs filesystem usage /
# Größe aller Snapshots anzeigen
sudo btrfs subvolume list / | grep snapshots
# Detaillierte Snapshot-Größen
for snap in $(sudo snapper -c root list | tail -n +3 | awk '{print $1}'); do
if [ "$snap" != "0" ]; then
size=$(sudo btrfs subvolume show "/.snapshots/$snap/snapshot" 2>/dev/null | grep -E "^\s*Gen:" | wc -l)
echo "Snapshot $snap: Exists"
fi
done
```
### Automatische Bereinigung konfigurieren
```bash
# Manuelle Bereinigung ausführen
sudo snapper -c root cleanup number # Nach Anzahl-Regeln
sudo snapper -c root cleanup timeline # Nach Zeit-Regeln
# Bereinigung-Logs anzeigen
journalctl -u snapper-cleanup.service
```
## Fehlerbehandlung und Tipps
### Häufige Probleme
**Problem**: `/.snapshots` ist ein normaler Ordner, kein Subvolume
```bash
# Lösung:
sudo umount /.snapshots
sudo rm -rf /.snapshots
sudo btrfs subvolume create /.snapshots
sudo systemctl restart snapper-timeline.timer
```
**Problem**: Snapshots verbrauchen zu viel Speicher
```bash
# Lösung: Bereinigungsregeln anpassen
sudo nano /etc/snapper/configs/root
# NUMBER_LIMIT reduzieren (z.B. auf 20)
# Mehr Ausschlüsse hinzufügen
```
**Problem**: Automatische Snapshots funktionieren nicht
```bash
# Debugging:
systemctl status snapper-timeline.timer
journalctl -u snapper-timeline.service
sudo snapper -c root create -d "Test" # Manuell testen
```
### Best Practices
1. **Vor großen Änderungen**: Immer manuelles Pre/Post-Snapshot-Paar
2. **Regelmäßige Kontrolle**: `sudo snapper list` alle paar Tage prüfen
3. **Speicherplatz überwachen**: Bei >80% Festplattenbelegung Snapshots reduzieren
4. **Test-Rollbacks**: Erst in VM oder Testsystem ausprobieren
5. **Backup-Strategie**: Snapper ersetzt keine externe Datensicherung!
6. **Wichtige Daten**: Separat in `/home` mit eigenem Snapshot-Schema verwalten
### Erweiterte Konfiguration für /home
```bash
# Separate Snapshot-Konfiguration für Home-Verzeichnis
sudo snapper -c home create-config /home
# Andere Bereinigungsregeln für /home (mehr Snapshots, da wichtiger)
sudo nano /etc/snapper/configs/home
```
Diese detaillierte Anleitung sollte dir ein vollständiges Verständnis von Snapper und dessen Konfiguration geben!
+84
View File
@@ -0,0 +1,84 @@
[[Navidrome]]
## 🧩 **Option 1: Über die Web-Oberfläche**
Wenn du nur die Bibliothek neu scannen willst:
1. Melde dich als **Admin** in der Weboberfläche an.
2. Gehe zu **Settings → Admin → Rescan Library** (oder „Bibliothek neu scannen“).
3. Wähle **„Full Rescan“** (Vollständiger Scan) aus.
Das ist der einfachste Weg — aber wenn du den Vorgang **per Shell oder Skript** auslösen willst, siehe Option 2 oder 3.
---
## 🐳 **Option 2: Über die Docker Shell**
Wenn du direkten Zugriff auf den Container hast:
```bash
docker exec -it <container_name> navidrome rescan --force
```
🔹 `<container_name>` ersetzt du durch den tatsächlichen Namen deines Containers, z. B. `navidrome`.
🔹 Der Parameter `--force` erzwingt eine vollständige Neuindizierung (nicht nur eine inkrementelle).
Beispiel:
```bash
docker exec -it navidrome navidrome rescan --force
```
Falls `navidrome` nicht im `PATH` ist (z. B. je nach Image):
```bash
docker exec -it navidrome /app/navidrome rescan --force
```
---
## ⚙️ **Option 3: Durch Neustart mit Umgebungsvariable**
Wenn du den Container neu startest und gleich beim Start eine Neuindizierung erzwingen willst, kannst du temporär folgende Umgebungsvariable setzen:
```bash
docker run -d \
-e ND_SCAN_ON_STARTUP=true \
-e ND_SCAN_FORCED=true \
...
--name navidrome \
deluan/navidrome:latest
```
Oder, wenn du `docker-compose` nutzt:
```yaml
environment:
- ND_SCAN_ON_STARTUP=true
- ND_SCAN_FORCED=true
```
Dann einmal:
```bash
docker compose restart navidrome
```
Das löst bei jedem Start eine **vollständige Neuindizierung** aus.
---
## 🧠 **Zusatzinfos**
- `navidrome rescan` akzeptiert auch `--quiet` (ohne Logausgabe).
- Der Fortschritt erscheint in den Logs:
```bash
docker logs -f navidrome
```
- Die Indizierung kann bei großen Bibliotheken einige Zeit dauern.
+207
View File
@@ -0,0 +1,207 @@
**Open WebUI is an [extensible](https://docs.openwebui.com/features/plugin/), feature-rich, and user-friendly self-hosted AI platform designed to operate entirely offline.** It supports various LLM runners like **Ollama** and **OpenAI-compatible APIs**, with **built-in inference engine** for RAG, making it a **powerful AI deployment solution**.
Passionate about open-source AI? [Join our team →](https://careers.openwebui.com/)
![GitHub stars](https://img.shields.io/github/stars/open-webui/open-webui?style=social) ![GitHub forks](https://img.shields.io/github/forks/open-webui/open-webui?style=social) ![GitHub watchers](https://img.shields.io/github/watchers/open-webui/open-webui?style=social) ![GitHub repo size](https://img.shields.io/github/repo-size/open-webui/open-webui) ![GitHub language count](https://img.shields.io/github/languages/count/open-webui/open-webui) ![GitHub top language](https://img.shields.io/github/languages/top/open-webui/open-webui) ![GitHub last commit](https://img.shields.io/github/last-commit/open-webui/open-webui?color=red) [![Discord](https://img.shields.io/badge/Discord-Open_WebUI-blue?logo=discord&logoColor=white)](https://discord.gg/5rJgQTnV4s) [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/tjbck)
![Open WebUI Demo](https://docs.openwebui.com/assets/images/demo-d3952c8561c4808c1d447fc061c71174.gif)
tip
**Looking for an [Enterprise Plan](https://docs.openwebui.com/enterprise)?** — **[Speak with Our Sales Team Today!](mailto:sales@openwebui.com)**
Get **enhanced capabilities**, including **custom theming and branding**, **Service Level Agreement (SLA) support**, **Long-Term Support (LTS) versions**, and **more!**
## Quick Start with [[Docker]] 🐳
info
**WebSocket** support is required for Open WebUI to function correctly. Ensure that your network configuration allows WebSocket connections.
**If Ollama is on your computer**, use this command:
```
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
```
**To run Open WebUI with Nvidia GPU support**, use this command:
```
docker run -d -p 3000:8080 --gpus all --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:cuda
```
For environments with limited storage or bandwidth, Open WebUI offers slim image variants that exclude pre-bundled models. These images are significantly smaller but download required models on first use:
```
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main-slim
```
### Open WebUI Bundled with Ollama
This installation method uses a single container image that bundles Open WebUI with Ollama, allowing for a streamlined setup via a single command. Choose the appropriate command based on your hardware setup:
- **With GPU Support**: Utilize GPU resources by running the following command:
```
docker run -d -p 3000:8080 --gpus=all -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama
```
- **For CPU Only**: If you're not using a GPU, use this command instead:
```
docker run -d -p 3000:8080 -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama
```
Both commands facilitate a built-in, hassle-free installation of both Open WebUI and Ollama, ensuring that you can get everything up and running swiftly.
After installation, you can access Open WebUI at [http://localhost:3000](http://localhost:3000). Enjoy! 😄
### Using the Dev Branch 🌙
warning
The `:dev` branch contains the latest unstable features and changes. Use it at your own risk as it may have bugs or incomplete features.
If you want to try out the latest bleeding-edge features and are okay with occasional instability, you can use the `:dev` tag like this:
```
docker run -d -p 3000:8080 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:dev
```
For the slim variant of the dev branch:
```
docker run -d -p 3000:8080 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:dev-slim
```
### Updating Open WebUI
To update Open WebUI container easily, follow these steps:
#### Manual Update
Use [Watchtower](https://containrrr.dev/watchtower) to update your Docker container manually:
```
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once open-webui
```
#### Automatic Updates
Keep your container updated automatically every 5 minutes:
```
docker run -d --name watchtower --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --interval 300 open-webui
```
🔧 **Note**: Replace `open-webui` with your container name if it's different.
## Manual Installation
info
### Platform Compatibility
Open WebUI works on macOS, [[Linux]] (x86_64 and ARM64, including Raspberry Pi and other ARM boards), and Windows.
There are two main ways to install and run Open WebUI: using the `uv` runtime manager or Python's `pip`. While both methods are effective, **we strongly recommend using `uv`** as it simplifies environment management and minimizes potential conflicts.
### Installation with `uv` (Recommended)
The `uv` runtime manager ensures seamless Python environment management for applications like Open WebUI. Follow these steps to get started:
#### 1. Install `uv`
Pick the appropriate installation command for your operating system:
- **macOS/Linux**:
```
curl -LsSf https://astral.sh/uv/install.sh | sh
```
- **Windows**:
```
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```
#### 2. Run Open WebUI
Once `uv` is installed, running Open WebUI is a breeze. Use the command below, ensuring to set the `DATA_DIR` environment variable to avoid data loss. Example paths are provided for each platform:
- **macOS/Linux**:
```
DATA_DIR=~/.open-webui uvx --python 3.11 open-webui@latest serve
```
- **Windows**:
```
$env:DATA_DIR="C:\open-webui\data"; uvx --python 3.11 open-webui@latest serve
```
note
**For PostgreSQL Support:**
The default installation now uses a slimmed-down package. If you need **PostgreSQL support**, install with all optional dependencies:
```
pip install open-webui[all]
```
### Installation with `pip`
For users installing Open WebUI with [[Python]]'s package manager `pip`, **it is strongly recommended to use Python runtime managers like `uv` or `conda`**. These tools help manage Python environments effectively and avoid conflicts.
Python 3.11 is the development environment. Python 3.12 seems to work but has not been thoroughly tested. Python 3.13 is entirely untested and some dependencies do not work with Python 3.13 yet—**use at your own risk**.
1. **Install Open WebUI**:
Open your terminal and run the following command:
```
pip install open-webui
```
- **Start Open WebUI**:
Once installed, start the server using:
```
open-webui serve
```
### Updating Open WebUI
To update to the latest version, simply run:
```
pip install --upgrade open-webui
```
This method installs all necessary dependencies and starts Open WebUI, allowing for a simple and efficient setup. After installation, you can access Open WebUI at [http://localhost:8080](http://localhost:8080). Enjoy! 😄
## Other Installation Methods
We offer various installation alternatives, including non-Docker native installation methods, Docker Compose, Kustomize, and Helm. Visit our [Open WebUI Documentation](https://docs.openwebui.com/getting-started/) or join our [Discord community](https://discord.gg/5rJgQTnV4s) for comprehensive guidance.
Continue with the full [getting started guide](https://docs.openwebui.com/getting-started).
### Desktop App
We also have an **experimental** desktop app, which is actively a **work in progress (WIP)**. While it offers a convenient way to run Open WebUI natively on your system without Docker or manual setup, it is **not yet stable**.
👉 For stability and production use, we strongly recommend installing via **Docker** or **Python (`uv` or `pip`)**.
+385
View File
@@ -0,0 +1,385 @@
# argpase
---
## 1. Grundidee von `argparse`
`argparse` ist das Standardmodul in Python, um Kommandozeilen-Argumente zu definieren, zu parsen und automatisch Hilfe-/Usage-Texte zu erzeugen.
Minimalbeispiel:
```python
import argparse
parser = argparse.ArgumentParser(description="Ein kleines Beispiel-CLI")
parser.add_argument("datei", help="Pfad zur Eingabedatei")
args = parser.parse_args()
print(args.datei)
```
Aufruf:
```bash
python script.py meine_datei.txt
```
---
## 2. Argumente definieren: `ArgumentParser.add_argument`
### 2.1 Positionsargumente
- Werden ohne führende `-` oder `--` angegeben.
- Reihenfolge ist relevant.
```python
parser.add_argument("quelle", help="Quellpfad")
parser.add_argument("ziel", help="Zielpfad")
```
Aufruf:
```bash
python script.py input.txt output.txt
```
Use-Case:
- Pflichtwerte, die immer gebraucht werden (z.B. Eingabe- und Ausgabedatei).
---
### 2.2 Optionale Argumente (Flags / Optionen)
- Beginnen mit `-` bzw. `--`.
- Reihenfolge ist egal.
- Können Standardwerte haben.
```python
parser.add_argument(
"-v", "--verbose",
action="store_true",
help="Ausführliche Ausgabe aktivieren"
)
parser.add_argument(
"-n", "--anzahl",
type=int,
default=10,
help="Anzahl der Elemente (Standard: 10)"
)
```
Aufruf:
```bash
python script.py input.txt --verbose --anzahl 5
# oder kurz:
python script.py input.txt -v -n 5
```
Use-Case:
- Konfiguration, optionales Verhalten, Debug/Verbose-Flags, Parameter mit Default.
---
## 3. Wichtige Parameter von `add_argument`
### 3.1 `name` / `flags`
- Beispiel:
- Positional: `"datei"`
- Optional: `"-v", "--verbose"`
```python
parser.add_argument("datei")
parser.add_argument("-v", "--verbose")
```
---
### 3.2 `type`
- Convertiert Eingabe in Typ.
- Validiert automatisch (bei falschem Typ Fehler + Hilfe).
```python
parser.add_argument("--port", type=int, default=8080)
parser.add_argument("--faktor", type=float)
```
Use-Case:
- Numerische Werte, Pfade, eigene Typen (z.B. `Path` aus `pathlib`).
---
### 3.3 `default`
- Standardwert, wenn Argument nicht übergeben wird.
```python
parser.add_argument("--log-level", default="INFO")
```
Use-Case:
- Sinnvolle Defaults, um CLI kompakt zu halten.
---
### 3.4 `required`
- Macht optionale Argumente zwingend erforderlich.
```python
parser.add_argument("--config", required=True)
```
Use-Case:
- Flags/Optionen, die zwingend gesetzt werden müssen (z.B. API-Key, Konfigdatei).
---
### 3.5 `help`
- Beschreibung für die `--help`-Ausgabe.
```python
parser.add_argument("--mode", help="Betriebsmodus: fast oder safe")
```
Use-Case:
- Dokumentation der Optionen (sehr wichtig für Benutzerfreundlichkeit).
---
### 3.6 `choices`
- Schränkt erlaubte Werte ein.
```python
parser.add_argument(
"--mode",
choices=["fast", "safe"],
default="safe",
help="fast = schneller, safe = sicherer"
)
```
Use-Case:
- Enum-ähnliche Optionen (z.B. `debug/info/warn/error`, `json/text`).
---
### 3.7 `action`
Steuert, was passiert, wenn das Argument gesetzt wird.
Häufige Actions:
1. `store` (Standard)
Speichert den Wert (z.B. `--port 8000``args.port = 8000`).
2. `store_true` / `store_false`
Boolean-Flag, das `True`/`False` setzt.
```python
parser.add_argument("-v", "--verbose", action="store_true")
```
3. `append`
Fügt mehrere Werte in eine Liste ein.
```python
parser.add_argument(
"-t", "--tag",
action="append",
help="Kann mehrfach verwendet werden"
)
# Aufruf: --tag a --tag b -> args.tag = ["a", "b"]
```
4. `count`
Zählt, wie oft ein Flag verwendet wurde.
```python
parser.add_argument(
"-v", "--verbose",
action="count",
default=0,
help="Mehrfach verwenden für mehr Details"
)
# -v -> 1, -vv -> 2 ...
```
Use-Case:
- Flags (bool), Mehrfachangaben (Listen), Verbosity-Level etc.
---
### 3.8 `nargs`
Gibt an, wie viele Werte zu einem Argument gehören.
Typische Varianten:
- `nargs=1` → eine Liste mit einem Element
- `nargs=2` → genau 2 Werte
- `nargs="+"` → mindestens ein Wert
- `nargs="*"` → beliebig viele (auch 0)
```python
parser.add_argument("dateien", nargs="+", help="Eine oder mehrere Dateien")
parser.add_argument("--koordinaten", nargs=2, type=float, help="x y")
```
Use-Case:
- Mehrere Dateien, Koordinaten, Listen von Werten.
---
### 3.9 `metavar`
- Steuert, wie das Argument im Help-Text angezeigt wird.
```python
parser.add_argument(
"--output",
metavar="DATEI",
help="Ausgabedatei"
)
```
Use-Case:
- Schöner formatierte Hilfe (statt generischer Namen).
---
### 3.10 `dest`
- Name des Attributes in `args`.
```python
parser.add_argument("-o", "--output", dest="ausgabedatei")
# args.ausgabedatei
```
Use-Case:
- Lesbare/konfliktfreie Python-Bezeichner, wenn CLI-Namen nicht ideal sind.
---
## 4. Subkommandos: `subparsers`
Für CLI-Tools mit mehreren Befehlen (ähnlich `git commit`, `git status`).
```python
import argparse
parser = argparse.ArgumentParser(prog="tool")
subparsers = parser.add_subparsers(dest="command", required=True)
# Subkommando: "run"
run_parser = subparsers.add_parser("run", help="Job ausführen")
run_parser.add_argument("job_id", type=int)
# Subkommando: "list"
list_parser = subparsers.add_parser("list", help="Jobs auflisten")
list_parser.add_argument("--status", choices=["open", "done"])
args = parser.parse_args()
if args.command == "run":
print(f"Starte Job {args.job_id}")
elif args.command == "list":
print(f"Liste Jobs mit Status {args.status}")
```
Aufrufe:
```bash
tool run 42
tool list --status open
```
Use-Case:
- Umfangreiche Tools mit verschiedenen Befehlen (z.B. Admin-Tools, Deployment-CLI).
---
## 5. Automatische Hilfe und Usage
`argparse` erzeugt automatisch `-h` / `--help`:
```bash
python script.py --help
```
Du bekommst:
- Beschreibung (`description`)
- Liste aller Argumente
- Default-Werte (wenn konfiguriert)
- Subkommandos (falls vorhanden)
Beispiel:
```python
parser = argparse.ArgumentParser(
description="Konvertiert Dateien in andere Formate."
)
```
---
## 6. Minimaler „Best-Practice“-Skeleton
```python
import argparse
def parse_args():
parser = argparse.ArgumentParser(
description="Beispiel-Tool für argparse"
)
# Positionsargumente
parser.add_argument("eingabe", help="Eingabedatei")
# Optionale Argumente
parser.add_argument(
"-o", "--output",
help="Ausgabedatei (Standard: stdout)"
)
parser.add_argument(
"-v", "--verbose",
action="store_true",
help="Ausführliche Ausgabe"
)
parser.add_argument(
"--mode",
choices=["fast", "safe"],
default="safe",
help="Verarbeitungsmodus (Standard: safe)"
)
return parser.parse_args()
def main():
args = parse_args()
if args.verbose:
print(f"Starte in Modus {args.mode} mit Eingabe {args.eingabe}")
# weitere Logik…
if __name__ == "__main__":
main()
```
---
@@ -0,0 +1,342 @@
Flask is a powerful and flexible micro web framework for Python, ideal for both small and large web projects. It provides a straightforward way to get a web application up and running, with all the features that you need to get started.
Over the course of this tutorial, youll explore the process of creating a boilerplate for a Flask web project. This boilerplate will serve as a great starting point for any scalable Flask web app that you wish to develop in the future, from basic web pages to complex web applications.
**In this tutorial, youll learn how to:**
- Set up a **Flask project**
- Create a `"Hello, World!"` **Flask app**
- Add **multiple pages** with blueprints
- Leverage **Jinja templates**
- Store **static files**
At the end of this tutorial, youll have created a working Flask web application that you can use to bootstrap your future Flask projects.
**Get Your Code:** [Click here to download the free source code](https://realpython.com/bonus/flask-project-code/) that shows you how to build a Flask project boilerplate.
==**Take the Quiz:**== Test your knowledge with our interactive “Build a Scalable Flask Web Project From Scratch” quiz. Youll receive a score upon completion to help you track your learning progress:
---
[
![Build a Scalable Flask Web Project From Scratch](https://files.realpython.com/media/UPDATE-Python-Web-Applications-with-Flask-1_Watermarked.3e384f2e53cf.jpg)
](https://realpython.com/quizzes/flask-project/)
**Interactive Quiz**
[Build a Scalable Flask Web Project From Scratch](https://realpython.com/quizzes/flask-project/)
Test your knowledge of Flask basics, blueprints, project structure, Jinja templates, static files, and setup steps.
## Prerequisites[](https://realpython.com/flask-project/#prerequisites "Permanent link")
You dont need any previous knowledge of Flask to complete this project. If you want to learn more about the topics that you encounter in this tutorial, then youll find links to resources along the way.
However, you should be comfortable using the [terminal](https://realpython.com/terminal-commands/) and have [basic knowledge](https://realpython.com/products/python-basics-book/) of Python. Although it helps to know about [virtual environments](https://realpython.com/python-virtual-environments-a-primer/) and [`pip`](https://realpython.com/what-is-pip/), youll learn how to set everything up as you work through the tutorial.
[Remove ads](https://realpython.com/account/join/)
## Project Overview[](https://realpython.com/flask-project/#project-overview "Permanent link")
In this tutorial, youll start building a Flask project, which could become a public message board at some point. Heres what the project will look at the end of this tutorial:
You create a basic Flask project with two pages that inherit content and style from a parent template.
The Flask project that youll build in this tutorial will be very generic. That way, its the perfect base for any of your future projects. For example, maybe youll want to [add a database](https://realpython.com/flask-database/) or implement [logging and notification messages](https://realpython.com/flask-logging-messages/).
## Get Started[](https://realpython.com/flask-project/#get-started "Permanent link")
In this section, youll prepare the development environment for your Flask project. First, youll create a **virtual environment** and install all the **dependencies** that you need for your project.
### Create a Virtual Environment[](https://realpython.com/flask-project/#create-a-virtual-environment "Permanent link")
In this section, youll build your project structure. You can name the root folder of your project any way you like. For example, you could name it `rp_flask_board/` if your ultimate goal is to create a message board. If you have another project in mind, then feel free to name your folder accordingly. Create your folder and navigate into it:
`$ mkdir rp_flask_board $ cd rp_flask_board`
In this case, you name the root folder of your project `rp_flask_board/`. The files and folders that you create over the course of this series will be located in either this folder or its subfolders.
After you navigate to the project folder, its a good idea to create and activate a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/). That way, youre installing any project dependencies not system-wide but only in your projects virtual environment.
Select your **operating system** below and use your platform-specific command to set up a virtual environment:
- [Windows](https://realpython.com/flask-project/#windows-1)
- [Linux + macOS](https://realpython.com/flask-project/#linux-macos-1)
`$ python -m venv venv $ source venv/bin/activate (venv) $`
With the commands shown above, you create and activate a virtual environment named `venv` by using Pythons built-in `venv` module. The parenthesized `(venv)` in front of the prompt indicates that youve successfully activated the virtual environment.
### Add Dependencies[](https://realpython.com/flask-project/#add-dependencies "Permanent link")
After youve created and activated your virtual environment, its time to install **Flask** with [`pip`](https://realpython.com/what-is-pip/):
`(venv) $ python -m pip install Flask`
The Flask **micro web framework** is the only direct dependency that your project requires. This is good news because that means that you can now start coding your Flask project.
[Remove ads](https://realpython.com/account/join/)
## Initiate Your Flask Project[](https://realpython.com/flask-project/#initiate-your-flask-project "Permanent link")
In this section, youll spin up a **development server** and display `"Hello, World!"` in the browser with just a few lines of code. Then, youll expand your project structure to prepare a scalable Flask web application.
### Run the Flask Development Server[](https://realpython.com/flask-project/#run-the-flask-development-server "Permanent link")
A Flask project can be as basic as one Python file, which is commonly named `app.py`. Give it a try by creating `app.py` in `rp_flask_board/` and adding the following content:
`app.py`
`from flask import Flask app = Flask(__name__) @app.route("/") def home(): return "Hello, World!" if __name__ == "__main__": app.run(host="0.0.0.0", port=8000, debug=True)`
You import the `Flask` class, giving the application access to the Flask functionality. You then create a Flask application instance named `app`. Next, you connect the URL route `"/"` to the `home()` function by [decorating](https://realpython.com/primer-on-python-decorators/) it with `@app.route("/")`. Functions like these are commonly referred to as **views** in Flask. In this case, the `home` view returns a `"Hello, World!"` string that the browser can display.
**Note:** Flasks development server defaults to port `5000`. But on newer macOS versions, the macOS [AirPlay receiver](https://en.wikipedia.org/wiki/AirPlay#Receivers) uses this port. Above, youve changed the port of your Flask app with `port=8000`. If you want, you can [change the AirPlay receiver preferences on your Mac](https://support.apple.com/guide/mac-help/change-airplay-receiver-preferences-on-mac-mchl15c9e4b5/mac) instead.
With the Python virtual environment active, you can run your application with this command in the directory containing the `app.py` file:
`(venv) $ python app.py`
When you run `app.py`, a web server will start on port 8000. If you open a browser and navigate to `http://localhost:8000`, then you should see _Hello, World!_ displayed:
[![Hello World Flask App](https://files.realpython.com/media/helloworld.c5d1d5655deb.png)](https://files.realpython.com/media/helloworld.c5d1d5655deb.png)
Congratulations, your web server is running! You can stop the development server by pressing Ctrl+C in your terminal.
Your current project structure is great for starting a Flask project. However, if you want to work on bigger projects, this structure can be limiting because youd need to add more and more code to `app.py`. Instead, youll adjust the structure a bit to create a more scalable Flask project.
### Transform Your Project Into a Package[](https://realpython.com/flask-project/#transform-your-project-into-a-package "Permanent link")
[Packages](https://realpython.com/python-modules-packages/) are useful for structuring Python code into logical groupings for large programs. Because your web project can grow large, too, transforming your project into a package makes sense. Since youre just at the start of the project, your to-do list to create the package has only three tasks:
1. Creating a package folder named `board/`
2. Moving `app.py` into `board/`
3. Renaming `app.py` to `__init__.py`
You can perform these tasks by hand or use the [terminal](https://realpython.com/terminal-commands/) to perform all three steps with two commands:
`(venv) $ mkdir board (venv) $ mv app.py board/__init__.py`
With the commands above, you create the `board/` subfolder. Then, you move `app.py` into `board/` and rename it to `__init__.py`.
By now, your Flask project structure should look like this:
`rp_flask_board/ │ └── board/ └── __init__.py`
With the new package structure in place, make sure that you stay in the `rp_flask_board/` folder and run your Flask project with this command:
`(venv) $ python -m flask --app board run --port 8000 --debug`
With the command above, youre telling Flask to look for an app named `board` and serve it in debug mode on port `8000`. When you visit `http://localhost:8000`, you see the same _Hello, World!_ displayed as before.
[Remove ads](https://realpython.com/account/join/)
### Work With an Application Factory[](https://realpython.com/flask-project/#work-with-an-application-factory "Permanent link")
An **application factory** in Flask is a design pattern thats highly beneficial for scaling Flask projects. With an application factory, you can create and configure your Flask project flexibly and efficiently, making it easier to develop, test, and maintain as it grows and evolves.
Instead of having your applications code at the root level of your `__init__.py` file, youll work with a function that returns your application. To do so, replace the content of `__init__.py` with the content below:
`board/__init__.py`
`from flask import Flask def create_app(): app = Flask(__name__) return app`
After importing `Flask`, you create a function named `create_app()` that initializes the app and returns it. The `create_app()` function is your application factory.
With an application factory, your projects structure becomes more organized. It encourages you to separate different parts of your application, like routes, configurations, and initializations, into different files later on. This encourages a cleaner and more maintainable codebase.
To see the benefits of an application factory in action, youll create your first blueprint in the next section.
## Leverage Blueprints[](https://realpython.com/flask-project/#leverage-blueprints "Permanent link")
As your Flask project grows, you have lots of view functions and other related bits of code that work together. Instead of adding all these directly to a basic `app.py` file, you can create **blueprints** that you register in your application factory.
[Blueprints](https://realpython.com/flask-blueprint/) are modules that contain related views that you can conveniently import in `__init__.py`. For example, youll have a blueprint that stores the main pages of your project.
Create a file named `pages.py` in the `board/` folder and add the content below:
`board/pages.py`
`from flask import Blueprint bp = Blueprint("pages", __name__) @bp.route("/") def home(): return "Hello, Home!" @bp.route("/about") def about(): return "Hello, About!"`
After importing `Blueprint`, you create an instance of it named `bp`. The first argument, `"pages"`, is the name of your blueprint. Youll use this name to identify this particular blueprint in your Flask project. The second argument is the blueprints `__name__`. Youll use this later when you import `pages` into `__init__.py`.
Then, you define two routes, one as the `home` view and the other as the `about` view. Each of them returns a string to indicate on which page you are on.
Before you can visit the pages, you need to connect the `pages` blueprint with your Flask project:
`board/__init__.py`
`from flask import Flask from board import pages def create_app(): app = Flask(__name__) app.register_blueprint(pages.bp) return app`
Once youve imported and registered the `pages` blueprint in your application factory, you can visit the routes that you defined in `pages.py` in your browser. When you visit `http://localhost:8000/about`, then you can see the _Hello, About!_ string:
[![Unstyled about page](https://files.realpython.com/media/02-hello-about.5a86d9ac9395.png)](https://files.realpython.com/media/02-hello-about.5a86d9ac9395.png)
If the main purpose of your Flask project were to just display plain strings, then youd be done. However, its more fun to actually display dynamic content to your users. Thats when templates come into play.
## Introduce Templates[](https://realpython.com/flask-project/#introduce-templates "Permanent link")
Templates are [HTML files](https://realpython.com/html-css-python/#create-your-first-html-file) with the capability of rendering dynamic content sent over from your Flask views. For this, Flask uses the popular [Jinja](https://realpython.com/primer-on-jinja-templating/) **template engine**, which you already installed as a dependency when you installed Flask.
With a template engine like Jinja, you can embed Python-like expressions into your templates to create dynamic web content. You can use loops, conditionals, and variables directly in your templates.
Jinja also supports **template inheritance**, allowing the creation of a **base template** that you can extend in **child templates**, promoting code reuse and a consistent layout across different pages of your project.
[Remove ads](https://realpython.com/account/join/)
### Build a Base Template[](https://realpython.com/flask-project/#build-a-base-template "Permanent link")
Create a new template named `base.html` in a `templates/` directory inside `board/`:
`board/templates/base.html`
`<!DOCTYPE html> <html lang="en"> <head> <title>Message Board - {% block title %}{% endblock title %}</title> </head> <body> <h1>Message Board</h1> <section> <header> {% block header %}{% endblock header %} </header> <main> {% block content %}<p>No messages.</p>{% endblock content %} </main> </section> </body> </html>`
Commonly, the Jinja base template is named `base.html`, and it contains the main HTML structure of your web pages. The main structure of `base.html` is similar to a normal HTML page. You start by declaring the [doctype](https://developer.mozilla.org/en-US/docs/Glossary/Doctype), wrapping everything in `<html>` tags, and setting the [`lang` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang).
Then you go on to add `<head>` and `<body>` with some other nested elements. In line 4, you set the title of your project to _Message Board_. The empty `title` block gives you the opportunity to extend the title with a child template.
**Note:** The message board is just an example for a generic Flask project. Feel free to give your Flask project a more fitting name.
In line 10, you set the `header` block. If a child template doesnt contain a `header` block, then `<header>` will stay empty.
By providing default content inside the `content` block in line 13, you either display the _No messages_ hint or show the content of the child template.
### Add Your Child Templates[](https://realpython.com/flask-project/#add-your-child-templates "Permanent link")
Your base template is designed to provide a consistent structure for your project while allowing flexibility in specific parts of the content through Jinjas block functionality. Next, create the child templates that extend `base.html` and fill in these blocks with their specific content.
Start with the template for your `home` view by creating a `home.html` file in a `pages/` subfolder of your `templates/` folder:
`board/templates/pages/home.html`
`{% extends 'base.html' %} {% block header %} <h2>{% block title %}Home{% endblock title %}</h2> {% endblock header %} {% block content %} <p> Learn more about this project by visiting the <a href="{{ url_for('pages.about') }}">About page</a>. </p> {% endblock content %}`
To connect the child template with its parent template, you must add an `{% extends %}` tag at the top of the file.
Child templates also contain `{% block %}` tags. By providing the blocks name as an argument, youre connecting the blocks from the child template with the blocks from the parent template.
When you use [`url_for()`](https://flask.palletsprojects.com/en/3.0.x/api/#flask.Flask.url_for), Flask creates the full URL to the given view for you. This means that if you change the route in your Python code, then the URL in your templates updates automatically.
Continue by creating a file named `about.html` in the same `pages/` directory:
`board/templates/pages/about.html`
`{% extends 'base.html' %} {% block header %} <h2>{% block title %}About{% endblock title %}</h2> {% endblock header %} {% block content %} <p>This is a message board for friendly messages.</p> {% endblock content %}`
Just like in `home.html`, you do something nifty with the `title` block. You add the pages title inside the `header` block and wrap it within `title`. Jinja will understand this structure and render the pages title in the `header` and `title` blocks.
With both child templates in place, you need to adjust your views to return the templates instead of the plain strings. Hop over to `pages.py` and adjust `home()` and `about()`:
`board/pages.py`
`from flask import Blueprint, render_template bp = Blueprint("pages", __name__) @bp.route("/") def home(): return render_template("pages/home.html") @bp.route("/about") def about(): return render_template("pages/about.html")`
After importing Flasks [`render_template()`](https://flask.palletsprojects.com/en/3.0.x/api/#flask.render_template), you can use the function to return the `home.html` and `about.html` templates that you placed in the `templates/pages/` folder.
By default, Flask expects your templates to be in a `templates/` directory. Therefore, you dont need to include `templates/` in the path of the templates.
To verify that your templates work, restart your Flask development server and visit `http://localhost:8000`:
[![Unstyled Home page](https://files.realpython.com/media/03-home.05daf2dda36d.png)](https://files.realpython.com/media/03-home.05daf2dda36d.png)
Your _Home_ page shows the dynamic title.
When you visit your _Home_ page, then you can click the link to the _About_ page. Since theres no link to the _Home_ page, youd need to either use the _Back_ button of your browser or enter the URL manually in the address bar.
It seems like its time to elevate the user experience and include a navigation menu in your project!
[Remove ads](https://realpython.com/account/join/)
## Improve the User Experience[](https://realpython.com/flask-project/#improve-the-user-experience "Permanent link")
A good user experience is crucial in any web application. It ensures that users find the application not only convenient to use, but also enjoyable.
In the upcoming sections, youll add a navigation menu and style your web application. While doing so, notice how these additions can contribute to a better user experience.
### Include a Navigation Menu[](https://realpython.com/flask-project/#include-a-navigation-menu "Permanent link")
The navigation of a website is usually displayed on every page. With your base and child template structure, its best to add the code for the navigation menu into `base.html`.
Instead of adding the navigation menu code directly into `base.html`, you can leverage the `{% include %}` tag. By referencing another template with `{% include %}`, youre loading the whole template into that position. If you need to make any changes in the navigation, then you know exactly where to look. Additionally, you can decide to include your navigation template on a different part of the page, for example when you [design a `404` error template](https://realpython.com/flask-logging-messages/#design-the-404-error-template).
**Included templates** are partials that contain a fraction of the full HTML code. To indicate that a template is meant to be included, you can prefix its name with an underscore (`_`).
Follow the prefix-based naming scheme and create a new template named `_navigation.html` in your `templates/` folder:
`templates/_navigation.html`
`<nav> <ul> <li><a href="{{ url_for('pages.home') }}">Home</a></li> <li><a href="{{ url_for('pages.about') }}">About</a></li> </ul> </nav>`
Note that `_navigation.html` contains neither an `{% extends %}` tag nor any `{% block %}` tags. You can focus solely on how you want to render your navigation menu.
Just like above, you use `url_for()`, and Flask creates the full URL to the given view for you. So, even when you decide to change the route to one of your pages, the navigation menu will still work.
Include `_navigation.html` in `base.html` to display your navigation menu on all of your pages:
`templates/base.html`
`<!DOCTYPE html> <html lang="en"> <head> <title>Message Board - {% block title %}{% endblock title %}</title> </head> <body> <h1>Message Board</h1> {% include("_navigation.html") %} <section> <header> {% block header %}{% endblock header %} </header> <main> {% block content %}<p>No messages.</p>{% endblock content %} </main> </section> </body> </html>`
Instead of adding the navigation menu code directly into `base.html`, you include `_navigation.html` in your websites header.
Visit `http://localhost:8000/about` to check out your new navigation menu:
[![Unstyled About page with a menu](https://files.realpython.com/media/04-about-with-menu.3aa627239a41.png)](https://files.realpython.com/media/04-about-with-menu.3aa627239a41.png)
Since both `home.html` and `about.html` extend `base.html`, you didnt need to make any changes in these templates to make the navigation menu appear. Thats template inheritance in action!
But wait, theres more! In the next section, youll leverage template inheritance to add consistent styling to your web project.
### Make Your Project Look Nice[](https://realpython.com/flask-project/#make-your-project-look-nice "Permanent link")
The templates in your project provide the logic and structure for the **front end** of your project. With the help of **Cascading Style Sheets (CSS)**, you can [style the content](https://realpython.com/html-css-python/#style-your-content-with-css).
In Flask projects, you commonly save CSS files in a `static/` directory. In this project, youll only work with one CSS file named `styles.css`. But if you decide to expand the project at some point, you can also use this folder to store images or [JavaScript files](https://realpython.com/python-vs-javascript/).
Create a new directory named `static/` inside of `board/` and place a file named `styles.css` in it with the **CSS declarations** below:
`board/static/styles.css`
`* { box-sizing: border-box; } body { font-family: sans-serif; font-size: 20px; margin: 0 auto; text-align: center; } a, a:visited { color: #007bff; } a:hover { color: #0056b3; } nav ul { list-style-type: none; padding: 0; } nav ul li { display: inline; margin: 0 5px; } main { width: 80%; margin: 0 auto; }`
The CSS declarations above ensure that the web elements are properly spaced and sized, making the website look organized and more convenient to navigate.
The color scheme for the links provides a visual cue to users about clickable elements. The font choice and size contribute to readability. The overall layout and alignment of the web elements give the website a clean and modern look.
With the style sheet in place, you need to add a link to `styles.css` inside `<head>` of `base.html`:
`templates/base.html`
`<!DOCTYPE html> <html lang="en"> <head> <title>Message Board - {% block title %}{% endblock title %}</title> <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}"> </head> <body> <!-- ... --> </body> </html>`
You can reference a CSS file with a `<link>` tag in the header of your HTML page. Just like before, you use `url_for()` to create the full URL for the `href` attribute. To link to the `styles.css` file stored in your Flask projects `static/` folder specifically, you use the `filename` argument.
By adding the CSS file reference to `base.html`, youre again taking advantage of the inheritance mechanism that Jinja templates provide. You only need to add `styles.css` in your base template to make it present in your child templates.
You may need to restart your Flask development server again to see your styling in action:
[![About page with styling](https://files.realpython.com/media/05-about-styled.5f9a679b6b21.png)](https://files.realpython.com/media/05-about-styled.5f9a679b6b21.png)
With some minimal styling, your Flask web project is starting to look like a finished web app. Feel free to add more pages and content on your own. Once youre finished, you can continue to work on the message board project by [adding a database](https://realpython.com/flask-database/) and accepting posts from your users.
[Remove ads](https://realpython.com/account/join/)
## Conclusion[](https://realpython.com/flask-project/#conclusion "Permanent link")
Congratulations on successfully setting up a Flask project. This working Flask web project is a great starting point for any future Flask projects that you may have. By understanding these foundational concepts, youre now well equipped to tackle more complex projects and further explore the capabilities of Flask.
**In this tutorial, youve learned how to:**
- Set up a **Flask project**
- Create a `"Hello, World!"` **Flask app**
- Add **multiple pages**
- Leverage **Jinja templates**
- Store **static files**
Youve successfully created a working Flask web application that you can use to bootstrap your future Flask projects.
@@ -0,0 +1,374 @@
User: In diesem Skript starte ich eine Dummy Webseite. WIe kann ich diese mit den vorhandenen Werkzeugen (traefik) übers WWW verfügbar machen?
Workspace: Collecting workspace informationUm deine Flask-Dummy-Website über Traefik im WWW verfügbar zu machen, musst du sie containerisieren und mit Traefik-Labels konfigurieren. Hier ist die Lösung:
## 1. Dockerfile erstellen
````dockerfile
FROM python:3.11-slim
WORKDIR /app
# Flask installieren
RUN pip install --no-cache-dir flask
# App-Code kopieren
COPY my_app/ /app/my_app/
# Port exponieren
EXPOSE 8000
# App starten
CMD ["python", "-m", "flask", "--app", "my_app", "run", "--host", "0.0.0.0", "--port", "8000"]
````
## 2. Docker Compose Konfiguration erstellen
````yaml
services:
dummy_website:
build: .
container_name: dummy_website
restart: unless-stopped
expose:
- "8000"
networks:
- proxy
labels:
# Traefik aktivieren
- "traefik.enable=true"
# Router-Konfiguration
- "traefik.http.routers.dummy.rule=Host(`demo.schneiderserver.site`)"
- "traefik.http.routers.dummy.entrypoints=websecure"
- "traefik.http.routers.dummy.tls.certresolver=myresolver"
# Service-Konfiguration
- "traefik.http.services.dummy.loadbalancer.server.port=8000"
- "traefik.http.services.dummy.loadbalancer.server.scheme=http"
# Optionale Sicherheits-Headers
- "traefik.http.middlewares.dummy-headers.headers.customresponseheaders.X-Frame-Options=SAMEORIGIN"
- "traefik.http.middlewares.dummy-headers.headers.customresponseheaders.X-Content-Type-Options=nosniff"
- "traefik.http.routers.dummy.middlewares=dummy-headers"
networks:
proxy:
external: true
name: traefik_proxy
````
## 3. Flask-App für Docker anpassen
````python
from flask import Flask
from my_app import pages
def create_app():
app = Flask(__name__)
# Wichtig für Reverse-Proxy-Betrieb
app.config['PREFERRED_URL_SCHEME'] = 'https'
app.register_blueprint(pages.pages_bp)
return app
````
## 4. Starten der Website
```bash
cd /opt/dummy_website
docker compose up -d
```
## 5. manage.sh erweitern (optional)
````sh
// ...existing code...
manage_single_service() {
SERVICE=$1
ACTION=$2
case $SERVICE in
traefik)
cd /opt/traefik
;;
nextcloud)
cd /opt/nextcloud
;;
navidrome)
cd /opt/navidrome
;;
dummy)
cd /opt/dummy_website
;;
*)
echo -e "${RED}❌ Unbekannter Service: $SERVICE${NC}"
exit 1
;;
esac
case $ACTION in
start|stop|restart|logs)
docker compose $ACTION
;;
*)
docker compose $ACTION
;;
esac
}
// ...existing code...
traefik|nextcloud|navidrome|dummy)
if [ -n "$2" ]; then
manage_single_service $1 $2
else
echo "Verwendung: $0 $1 [start|stop|restart|logs]"
fi
;;
// ...existing code...
````
## 6. DNS-Eintrag erstellen
Erstelle einen A-Record für `demo.schneiderserver.site` mit der IP-Adresse deines Servers.
## Zugriff
Nach erfolgreicher Konfiguration ist deine Website erreichbar unter:
- **URL:** `https://demo.schneiderserver.site`
- **SSL:** Automatisch via Let's Encrypt
- **HTTP → HTTPS:** Automatische Weiterleitung
## Verwaltung
```bash
# Status prüfen
docker ps | grep dummy_website
# Logs anzeigen
/opt/manage.sh dummy logs
# Neustart
/opt/manage.sh dummy restart
# Stoppen
/opt/manage.sh dummy stop
```
**Wichtig:** Ändere `demo.schneiderserver.site` in den Labels zu deiner gewünschten Domain und erstelle den entsprechenden DNS-Eintrag.
User: Geht es auch einfacher. ICh will (noch) nicht containerisieren. Erstmal nur test, ob und wie ich die Web App, die lokal auf Port 8000 läuft übers WWW erreichen kann, im Zweifel auch erstmal ohne traefik
GitHub Copilot: Ja, das geht viel einfacher! Hier sind die Optionen:
## Option 1: Direkt mit Traefik (ohne Container)
Traefik kann auch auf lokale Services weiterleiten. Erstelle eine **dynamische Konfiguration**:
````yaml
http:
routers:
dummy-local:
rule: "Host(`demo.schneiderserver.site`)"
entryPoints:
- websecure
service: dummy-local-service
tls:
certResolver: myresolver
middlewares:
- dummy-headers
services:
dummy-local-service:
loadBalancer:
servers:
- url: "http://127.0.0.1:8000"
middlewares:
dummy-headers:
headers:
customResponseHeaders:
X-Frame-Options: "SAMEORIGIN"
````
Dann Traefik konfigurieren, um die Datei zu laden:
````yaml
services:
traefik:
image: traefik:v3.6
container_name: traefik
restart: unless-stopped
command:
# ...existing code...
- --providers.docker.network=traefik_proxy
- --providers.docker.useBindPortIP=false
- --providers.docker.defaultRule=Host(`{{ normalize .Name }}.schneiderserver.site`)
# 📁 File Provider aktivieren
- --providers.file.directory=/etc/traefik/dynamic
- --providers.file.watch=true
# ...existing code...
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./dynamic:/etc/traefik/dynamic:ro
````
```bash
# Ordner erstellen und Traefik neustarten
mkdir -p /opt/traefik/dynamic
# Datei erstellen (siehe oben)
docker compose -f /opt/traefik/docker-compose.yml restart
```
## Option 2: Ohne Traefik - SSH Tunnel (schnellster Test)
Auf deinem **lokalen Rechner**:
```bash
ssh -L 8000:localhost:8000 user@schneiderserver.site
# Dann im Browser: http://localhost:8000
```
## Option 3: Ohne Traefik - Flask direkt exponieren (UNSICHER!)
**Nur zum Testen, NICHT für Produktion:**
````sh
python -m flask --app my_app run --host 0.0.0.0 --port 8000 --debug
````
```bash
# Firewall-Regel temporär öffnen
sudo ufw allow 8000/tcp
# Zugriff dann über: http://schneiderserver.site:8000
```
**⚠️ Achtung:** Das ist unverschlüsselt (kein HTTPS) und unsicher!
## Empfehlung
**Option 1 (Traefik mit File Provider)** ist ideal für deinen Use-Case:
- ✅ Kein Docker für deine App nötig
- ✅ Automatisches HTTPS
- ✅ Professionell
- ✅ Schnell umgesetzt
Nach der Konfiguration:
1. DNS-Eintrag für `demo.schneiderserver.site` erstellen
2. Flask-App starten: `bash /opt/dummy_website/app.sh`
3. Zugriff: `https://demo.schneiderserver.site`
Welche Option möchtest du testen?
User: # Firewall-Regel temporär öffnen
sudo ufw allow 8000/tcp
# Zugriff dann über: http://schneiderserver.site:8000
wie schließe ich den Port nach Test wieder?
GitHub Copilot: Um den Port nach dem Test wieder zu schließen:
```bash
# Port 8000 wieder schließen
sudo ufw delete allow 8000/tcp
# Status überprüfen
sudo ufw status
```
---
**Aber ich würde dir wirklich Option 1 empfehlen** (Traefik mit File Provider). Das ist genauso schnell und du musst keine Firewall-Regeln ändern:
## Schritt-für-Schritt:
### 1. Docker Compose erweitern
````yaml
command:
# ...existing code...
- --providers.docker.defaultRule=Host(`{{ normalize .Name }}.schneiderserver.site`)
# 📁 File Provider aktivieren
- --providers.file.directory=/etc/traefik/dynamic
- --providers.file.watch=true
# ------------------------
# 🌍 EntryPoints
# ------------------------
# ...existing code...
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./dynamic:/etc/traefik/dynamic:ro
````
### 2. Dynamic Config erstellen
```bash
mkdir -p /opt/traefik/dynamic
nano /opt/traefik/dynamic/dummy-website.yml
```
````yaml
http:
routers:
dummy-local:
rule: "Host(`demo.schneiderserver.site`)"
entryPoints:
- websecure
service: dummy-local-service
tls:
certResolver: myresolver
services:
dummy-local-service:
loadBalancer:
servers:
- url: "http://127.0.0.1:8000"
````
### 3. Traefik neustarten
```bash
cd /opt/traefik
docker compose restart
```
### 4. Flask-App starten
```bash
cd /opt/dummy_website
bash app.sh
```
### 5. Testen
```bash
# DNS-Eintrag für demo.schneiderserver.site erstellen
# Dann im Browser: https://demo.schneiderserver.site
```
**Vorteile:**
- ✅ Kein Firewall-Port öffnen nötig
- ✅ Automatisches HTTPS
- ✅ Saubere Lösung
- ✅ Einfach wieder zu entfernen (Datei löschen)
Möchtest du es so probieren?
@@ -0,0 +1,10 @@
1. Initialer Entwurf von ChatGPT (oder anderen LLM), evtl. mit Verweis auf Vorbild-Seite
2. Öffnen der HTML Seite in Editor
- Blue Griffon
- [http://bluegriffon-epubedition.com/BGEE.html](http://bluegriffon-epubedition.com/BGEE.html)
- Installer für Windows und Debian Derivate
- 😦 nicht für Arch-Derivate (Cachy)
- SeaMonkey
- 😀 Im AUR enthalten: `paru -S seamonkey`
- Geht auch in VS Code oder VS Codeum
- Kein WYSIWYG aber Live Preview
@@ -0,0 +1,17 @@
```bash
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/nvme0n1p2 during installation
UUID=4d4554dc-e3fc-499c-991c-074655585d11 / ext4 errors=remount-ro 0 1
# /boot/efi was on /dev/nvme0n1p1 during installation
UUID=FCBD-00BE /boot/efi vfat umask=0077 0 1
/swapfile none swap sw 0 0
UUID=04F6962EF6961FCA /media/mathias/Anbau2 ntfs-3g defaults,umask=000,uid=1000,gid=1000 0 0
UUID=A8F0EC77F0EC4D5E /media/mathias/Bilder ntfs-3g defaults,umask=000,uid=1000,gid=1000 0 0
UUID=a642b8a8-2cdd-4635-a094-e408073a236d /media/mathieu/vault ext4 defaults 0 2
```
+74
View File
@@ -0,0 +1,74 @@
# Anleitung: Template lokal forken (ohne Git-History)
Diese Anleitung beschreibt die Schritte aus diesem Chat, um ein Projekt-Template lokal zu klonen und mit einer frischen Git-History neu zu starten.
## Voraussetzungen
- Git ist installiert.
- Zugriff auf das Template-Repository ist moeglich (SSH oder HTTPS).
- Zielordner fuer das neue Projekt ist bekannt.
## Schritte
1. In den Zielordner wechseln:
```bash
cd /home/mathias/dev/web/foton
```
2. Template klonen (SSH bevorzugt):
```bash
git clone git@github.com:mathias2784/my_flask_temp.git foton_website
```
3. Falls SSH fehlschlaegt, mit HTTPS klonen:
```bash
git clone https://github.com/mathias2784/my_flask_temp.git foton_website
```
4. In das neue Projekt wechseln:
```bash
cd foton_website
```
5. Alte Git-History entfernen und frisches Repo initialisieren:
```bash
rm -rf .git
git init
```
## Optionale Naechste Schritte
- Standard-Branch auf main umbenennen:
```bash
git branch -m main
```
- Neues Remote-Repository hinzufuegen:
```bash
git remote add origin <NEUE_REPO_URL>
```
- Initialen Commit erstellen:
```bash
git add -A
git commit -m "Initial commit"
```
- Push zum neuen Remote:
```bash
git push -u origin main
```
## Hinweise
- Beim ersten SSH-Connect kann eine Host-Key-Abfrage erscheinen. Diese einmalig bestaetigen.
- Wenn SSH immer noch fehlschlaegt, HTTPS verwenden oder SSH-Key in GitHub einrichten.
+63
View File
@@ -0,0 +1,63 @@
Das Verhalten ist korrekt 🙂
`.gitignore` wirkt **nur für Dateien, die noch nicht von Git getrackt werden**.
Deine Datei `hypr/.config/hypr/env` wurde offenbar schon einmal committed. Deshalb ignoriert Git sie nicht automatisch, auch wenn sie jetzt in `.gitignore` steht.
---
## ✅ Lösung: Datei aus dem Index entfernen (aber lokal behalten)
Führe folgenden Befehl aus:
```bash
git rm --cached hypr/.config/hypr/env
```
Danach committen:
```bash
git commit -m "Stop tracking hypr env file"
```
Jetzt:
- Die Datei bleibt lokal erhalten ✅
- Git trackt sie nicht mehr ✅
- Änderungen erscheinen nicht mehr in `git status`
---
## 🔎 Warum das so ist
`.gitignore` verhindert nur das **Neu-Tracken** von Dateien.
Bereits versionierte Dateien bleiben im Index, bis man sie explizit entfernt (`git rm --cached`).
---
## 💡 Falls du viele Dateien entfernen willst
Für alle Dateien, die jetzt durch `.gitignore` ignoriert werden sollen:
```bash
git rm -r --cached .
git add .
git commit -m "Reapply gitignore"
```
⚠️ Das betrifft das ganze Repository nur verwenden, wenn du weißt, was du tust.
---
Wenn du möchtest, erkläre ich dir auch kurz den Unterschied zwischen:
- Working Directory
- Index (Staging Area)
- Repository
Das hilft extrem beim Verständnis von Git.
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
unison "$HOME/nextcloud/Notes/IT-Know-How/" "$HOME/Dokumente/01 Notizen/it-know-how/"