find und grep: Dateien und Inhalte suchen wie ein Profi
Die Fähigkeit, Dateien und Inhalte schnell zu finden, ist eine der wichtigsten Shell-Kompetenzen. find und grep sind dabei seit Jahrzehnten die Standardwerkzeuge – und ripgrep (rg) ist die moderne, deutlich schnellere Alternative zu grep.
Dieser Guide erklärt alle drei Werkzeuge von den Grundlagen bis zu fortgeschrittenen Kombinationen.
find: Dateien nach Eigenschaften suchen
Grundsyntax
find STARTVERZEICHNIS [OPTIONEN] [AUSDRUCK]
Nach Name suchen
# Datei nach exaktem Namen finden
find / -name "nginx.conf"
find /etc -name "*.conf"
# Groß-/Kleinschreibung ignorieren
find / -iname "nginx.conf" # findet auch NGINX.CONF, Nginx.Conf
# Wildcard-Muster (in Anführungszeichen wegen Shell-Glob!)
find /var/log -name "*.log"
find /home -name ".bash*"
# Dateien finden, die NICHT dem Muster entsprechen
find /etc -not -name "*.conf"
find /etc ! -name "*.conf" # gleichwertig
Nach Typ filtern
# Typ-Optionen:
# f = reguläre Datei
# d = Verzeichnis
# l = symbolischer Link
# b = Block-Gerät
# c = Zeichen-Gerät
# p = Named Pipe
# Nur Dateien (kein Verzeichnisse)
find /var/log -type f -name "*.log"
# Nur Verzeichnisse
find /home -type d -name ".config"
# Symbolische Links
find /usr/bin -type l
Nach Größe suchen
# Größer als 100 MB
find / -type f -size +100M
# Kleiner als 1 KB
find /etc -type f -size -1k
# Exakt 50 MB (selten nützlich)
find / -type f -size 50M
# Größer als 100 MB, kleiner als 1 GB
find / -type f -size +100M -size -1G
# Einheiten: c=Bytes, k=KB, M=MB, G=GB
# Tipp: Ergebnisse nach Größe sortieren
find / -type f -size +100M -printf '%s %p\n' 2>/dev/null | \
sort -rn | head -20 | numfmt --field=1 --to=iec
Nach Zeit filtern
# Modifikationszeit
find /var/log -mtime -1 # jünger als 1 Tag
find /var/log -mtime +30 # älter als 30 Tage
find /var/log -mtime 7 # genau 7 Tage alt (selten nützlich)
# Zugriffszeit
find /tmp -atime +7 # seit >7 Tagen nicht zugegriffen
# Statusänderungszeit (Berechtigungen, etc.)
find /etc -ctime -1 # Metadaten in letzter Stunde geändert
# Minuten statt Tage
find /tmp -mmin -30 # in den letzten 30 Minuten geändert
find /var/log -mmin +60 # vor mehr als 60 Minuten geändert
# Jünger als eine Referenzdatei
find /etc -newer /etc/passwd # neuer als /etc/passwd
Nach Berechtigungen suchen
# Exakte Berechtigungen
find / -perm 777 -type f # GEFAHR: world-writable Dateien
find / -perm 644 -type f
# Bestimmtes Bit gesetzt (/ = mindestens diese Bits)
find / -perm /4000 # SUID-Bit gesetzt (Sicherheitscheck!)
find / -perm /2000 # SGID-Bit gesetzt
find / -perm /0111 # ausführbar für irgendjemanden
# Alle SUID-Dateien (sicherheitsrelevant)
find / -perm /4000 -type f 2>/dev/null
# World-writable Verzeichnisse ohne Sticky Bit
find / -perm -0002 ! -perm /1000 -type d 2>/dev/null
Nach Besitzer suchen
# Dateien eines bestimmten Benutzers
find /home -user andre
find /var/www -user www-data
# Dateien einer bestimmten Gruppe
find /var/www -group www-data
# Dateien ohne gültigen Besitzer (orphaned files)
find / -nouser 2>/dev/null
find / -nogroup 2>/dev/null
Suchtiefe begrenzen
# Nur in aktuellem Verzeichnis (Tiefe 1)
find . -maxdepth 1 -name "*.py"
# Maximal 2 Ebenen tief
find /home -maxdepth 2 -name "config.yaml"
# Mindestens 3 Ebenen tief
find / -mindepth 3 -name "*.conf"
find: Aktionen ausführen
-exec: Befehl für jedes Ergebnis
# {} = Platzhalter für gefundene Datei
# \; = Ende des Befehls
# Datei-Details anzeigen
find /etc -name "*.conf" -exec ls -la {} \;
# Dateien in ein Verzeichnis verschieben
find /tmp -name "*.log" -exec mv {} /archiv/ \;
# Inhalt nach Muster durchsuchen
find /etc -name "*.conf" -exec grep -l "listen 80" {} \;
# chmod auf alle Dateien anwenden
find /var/www -type f -exec chmod 644 {} \;
find /var/www -type d -exec chmod 755 {} \;
# Schneller: + statt \; (übergibt mehrere Dateien auf einmal)
find /var/www -type f -exec chmod 644 {} +
-delete: Dateien löschen
# Leere Dateien löschen
find /tmp -type f -empty -delete
# Alte Logs löschen (älter als 30 Tage)
find /var/log -name "*.log" -mtime +30 -delete
# Erst anzeigen, dann löschen (Sicherheitscheck!)
find /tmp -name "*.tmp" -mtime +7 -print # zuerst anzeigen
find /tmp -name "*.tmp" -mtime +7 -delete # dann löschen
# Alternativ: -exec rm mit -i für Bestätigung
find /tmp -name "*.tmp" -exec rm -i {} \;
-print0 mit xargs (bei Leerzeichen im Dateinamen)
# Sicher bei Dateinamen mit Leerzeichen oder Sonderzeichen
find /home -name "*.jpg" -print0 | xargs -0 mv -t /bilder/
# Dateien komprimieren
find /var/log -name "*.log" -mtime +7 -print0 | xargs -0 gzip
grep: Inhalte durchsuchen
Grundsyntax und Flags
grep [OPTIONEN] MUSTER [DATEIEN]
# Einfache Suche in einer Datei
grep "ServerName" /etc/nginx/nginx.conf
# In mehreren Dateien
grep "error" /var/log/nginx/*.log
# Rekursiv in einem Verzeichnis
grep -r "localhost" /etc/
# Groß-/Kleinschreibung ignorieren (-i)
grep -i "ERROR" /var/log/syslog
# Zeilennummern anzeigen (-n)
grep -n "listen" /etc/nginx/nginx.conf
# Nur Dateinamen (nicht die Treffer) (-l)
grep -rl "password" /etc/
# Treffer zählen (-c)
grep -c "404" /var/log/nginx/access.log
# Inverse Suche (-v): Zeilen OHNE Muster
grep -v "^#" /etc/nginx/nginx.conf # Kommentare ausblenden
grep -v "^$" datei.txt # Leerzeilen ausblenden
# Wortgrenzen (-w): nur ganze Wörter
grep -w "root" /etc/passwd # findet "root", nicht "rootless"
# Kontext: Zeilen um den Treffer
grep -A 3 "error" syslog.txt # 3 Zeilen NACH dem Treffer
grep -B 3 "error" syslog.txt # 3 Zeilen VOR dem Treffer
grep -C 3 "error" syslog.txt # 3 Zeilen VORHER und NACHHER
Mehrere Muster
# ODER-Verknüpfung
grep -E "error|warning|critical" /var/log/syslog
grep "error\|warning" /var/log/syslog # ohne -E
# Aus Datei mit Mustern lesen
cat > muster.txt << 'EOF'
error
warning
critical
connection refused
EOF
grep -f muster.txt /var/log/syslog
Binäre Dateien überspringen
# Binäre Dateien ignorieren
grep -r --binary-files=without-match "pattern" /usr/
# Nur in bestimmten Dateitypen suchen
grep -r --include="*.py" "import os" /home/
grep -r --include="*.{conf,yaml}" "listen" /etc/
# Bestimmte Verzeichnisse ausschließen
grep -r --exclude-dir=".git" --exclude-dir="node_modules" "TODO" /home/
Reguläre Ausdrücke in grep
Grundlegende Regex
# ^ = Zeilenanfang
grep "^server" nginx.conf # Zeilen die mit "server" beginnen
# $ = Zeilenende
grep "};$" nginx.conf # Zeilen die mit "};" enden
# . = beliebiges Zeichen
grep "192.168...." /var/log/auth.log
# * = 0 oder mehr des vorherigen
grep "er*ror" datei.txt # "eror", "error", "errror", ...
# [] = Zeichenklasse
grep "[0-9]" datei.txt # Zeilen mit mindestens einer Zahl
grep "[aeiou]" datei.txt # Zeilen mit Vokalen
# [^] = Negierte Klasse
grep "[^0-9]" datei.txt # Zeilen mit Nicht-Zahlen
Erweiterte Regex (grep -E oder egrep)
# + = 1 oder mehr
grep -E "[0-9]+" datei.txt # mindestens eine Zahl
# ? = 0 oder 1
grep -E "colou?r" datei.txt # "color" oder "colour"
# {n,m} = n bis m Wiederholungen
grep -E "[0-9]{3}" datei.txt # genau 3 aufeinanderfolgende Ziffern
grep -E "[0-9]{2,4}" datei.txt # 2 bis 4 Ziffern
# () = Gruppe
grep -E "(error|warning): " syslog.txt
# | = Alternation
grep -E "nginx|apache|httpd" /var/log/syslog
# \b = Wortgrenze (Perl-kompatibel mit -P)
grep -P "\broot\b" /etc/passwd
# Praxisbeispiel: IP-Adressen finden
grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" /var/log/auth.log
ripgrep (rg): Die moderne Alternative
ripgrep ist 5–10× schneller als grep, respektiert automatisch .gitignore, und hat bessere Standardeinstellungen.
Installation
sudo apt install ripgrep # Ubuntu 22.04+
sudo dnf install ripgrep # Fedora
rg --version
# ripgrep 14.1.1
Grundlegende Nutzung
# rg ist standardmäßig rekursiv im aktuellen Verzeichnis
rg "TODO" # alle TODOs im aktuellen Projekt
# .gitignore wird automatisch respektiert (!)
rg "password" # findet nix in .git/, node_modules/, etc.
# In bestimmtem Verzeichnis
rg "error" /var/log/
# In bestimmten Dateitypen
rg "def " --type py # Python-Dateien
rg "class " --type js # JavaScript
rg "listen" --type conf # Config-Dateien
# Alle verfügbaren Typen
rg --type-list
rg vs. grep im Vergleich
# grep:
grep -r --include="*.py" "def " /home/ # 5-10 Sekunden
# rg:
rg "def " --type py /home/ # <1 Sekunde
# Versteckte Dateien einbeziehen
rg --hidden "API_KEY" # .env, .bashrc, etc.
# Alle Dateien (kein .gitignore beachten)
rg --no-ignore "secret"
# Case-insensitive
rg -i "error" /var/log/
# Nur Dateinamen
rg -l "TODO" /home/
# Kontext
rg -C 3 "error" /var/log/nginx/error.log
find + grep kombinieren
Die mächtigsten Suchanfragen entstehen durch Kombination:
# Alle Python-Dateien die "import os" enthalten
find /home -name "*.py" -exec grep -l "import os" {} \;
# Schneller mit xargs:
find /home -name "*.py" | xargs grep -l "import os"
# Noch schneller mit rg:
rg "import os" --type py /home/
# Konfigurationsdateien die "root" enthalten (Sicherheitscheck)
find /etc -name "*.conf" -exec grep -in "password\|secret\|key" {} /dev/null \;
# Ausgabe: dateiname:zeilennummer:inhalt
# Log-Dateien der letzten 24h nach Fehler durchsuchen
find /var/log -name "*.log" -mtime -1 | \
xargs grep -h "ERROR\|CRITICAL" | \
sort | uniq -c | sort -rn | head -20
# Große Konfigurationsdateien ohne Kommentare anzeigen
find /etc -name "*.conf" -size +10k | \
xargs grep -v "^[[:space:]]*#\|^$" | head -50
# PHP-Dateien mit eval() finden (Sicherheitscheck)
find /var/www -name "*.php" | xargs grep -l "eval(" 2>/dev/null
# Dateien die in letzter Woche geändert wurden und bestimmten Code enthalten
find /home -name "*.py" -mtime -7 | \
xargs grep -l "subprocess\|os.system"
Praktische Anwendungsfälle
Sicherheits-Scans
# SUID-Dateien (sollte verwaltet werden)
find / -perm /4000 -type f 2>/dev/null | sort
# World-writable Dateien (Sicherheitsrisiko)
find / -perm -0002 -type f 2>/dev/null | grep -v "/proc/" | sort
# Dateien mit hartcodierten Passwörtern (Sicherheitscheck)
grep -rn --include="*.{py,js,php,rb,java,conf,yaml,env}" \
-iE "(password|passwd|secret|api_key)\s*=\s*['\"][^'\"]{4,}" \
/var/www/ 2>/dev/null
# SSH authorized_keys auf dem gesamten System
find / -name "authorized_keys" 2>/dev/null
Server-Diagnose
# Nginx-Fehler der letzten Stunde
find /var/log/nginx -name "*.log" -mmin -60 | \
xargs grep "error\|crit" | tail -50
# Größte Dateien die kürzlich geändert wurden
find / -type f -mtime -1 -size +50M 2>/dev/null
# Alle Prozesse mit offenen Dateihandles auf /var/log
find /var/log -name "*.log" | \
xargs lsof 2>/dev/null | awk '{print $1}' | sort -u
# Konfigurationen mit ungewöhnlichen Berechtigungen
find /etc -type f -perm /o=w 2>/dev/null # world-writable Config!
Entwicklung
# TODO/FIXME/HACK in Codebase finden
rg -i "TODO|FIXME|HACK|XXX|BUG" --type py .
# Debug-Statements finden (vor Commit entfernen!)
rg "console\.log\|debugger\|print(" --type js .
rg "pp\|pry\|binding\.pry" --type rb .
# Alle Imports in Python-Dateien
rg "^import|^from .* import" --type py . | sort -u
# Längste Zeilen finden (Code-Style)
find . -name "*.py" -exec awk 'length > 100 {print FILENAME ":" NR ": " length " chars"}' {} \;
Häufige Fehler
find: '/proc/xxx': No such file or directory
# Viele Fehlermeldungen aus /proc und /sys:
find / -name "nginx" 2>/dev/null # Fehler ignorieren mit 2>/dev/null
# Bestimmte Verzeichnisse überspringen
find / -path /proc -prune -o -path /sys -prune -o -name "nginx" -print
grep findet nichts trotz vorhandenem Text
# Muster in Anführungszeichen einschließen
grep "text mit leerzeichen" datei.txt
# Sonderzeichen escapen oder -F für feste Zeichenketten
grep -F "text.mit.punkt" datei.txt # kein Regex
grep "text\.mit\.punkt" datei.txt # Punkt escaped
# Binärdatei? grep überprüfen
file datei.txt
grep -a "pattern" binary-file.bin # Binär als Text behandeln
find schlägt bei Leerzeichen in Dateinamen fehl
# Problem:
find /home -name "*.mp3" | xargs rm # kaputt bei "mein song.mp3"
# Lösung: -print0 und -0
find /home -name "*.mp3" -print0 | xargs -0 rm
Fazit
find und grep sind unersetzliche Werkzeuge, die du fast täglich brauchen wirst. Die wichtigsten Punkte:
findfindet Dateien nach Eigenschaften (Name, Größe, Zeit, Rechte) – mit-execwerden Aktionen direkt ausgeführtgrep -rdurchsucht Dateiinhalte rekursiv –-nfür Zeilennummern,-lfür nur Dateinamenripgrep (rg)ist der moderne Ersatz für grep: schneller, .gitignore-aware, bessere Syntax-print0 | xargs -0für Leerzeichen-sichere Dateiverarbeitung2>/dev/nullbei find, um Fehlermeldungen aus /proc, /sys zu unterdrücken