curl-Befehl: Optionen, POST-Anfragen und Dateien herunterladen

TestumgebungRHEL-FamilieAlmaLinux 9.8root-KontoGeprüft am 2026-10-28

Der curl-Befehl ist ein Werkzeug, das vom Terminal aus eine Anfrage an eine Webadresse sendet und die Antwort unverändert ausgibt. Mit einer einzigen Zeile prüfst du den Seiteninhalt, die Header und den Statuscode. Als wir von einem AlmaLinux-9-Server aus curl-Anfragen an eine WordPress-Website schickten, verwies die http-Adresse mit einer 301-Antwort auf die https-Adresse, und eine REST-API-Anfrage ohne Authentifizierung wurde mit 401 abgelehnt.

1️⃣ Grundlegende Verwendung des curl-Befehls und der Antwortinhalt

Hängst du eine Adresse an curl an, sendet curl eine GET-Anfrage an diese Adresse und gibt den Antwortinhalt auf dem Bildschirm aus. Als wir die von WordPress erzeugte robots.txt anfragten, kam der Inhalt der dreizeiligen Datei unverändert zurück.

curl https://example.com/robots.txt
User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php

Man erwartet leicht dieselbe Seite wie nach der Eingabe der Adresse im Browser, doch curl gibt das rohe HTML aus, das der Server geschickt hat. curl führt keine Skripte aus und fordert Bilder und CSS nicht gesondert an. Seiten-HTML ist lang, deshalb leiten wir die Ausgabe bei Webseiten-Adressen per Pipe an head weiter und prüfen nur die ersten Zeilen.

curl -s https://example.com/ | head -n 2
<!DOCTYPE html>
<html lang="ko-KR">

Mit -s wird die Fortschrittsanzeige ausgeblendet, die sich beim Weiterleiten per Pipe sonst in die Ausgabe mischt. Das HTML, das allein von der Adresse der Startseite kam, war 96.679 Byte groß. Bild- und Skriptdateien sind in dieser Größe nicht enthalten.

2️⃣ Header mit curl -I prüfen und Weiterleitungen mit -L folgen

Am Inhalt allein erkennst du nicht, ob die Anfrage erfolgreich war, deshalb prüfst du Statuscode und Header getrennt mit -I. -I sendet eine HEAD-Anfrage und gibt nur die Antwort-Header ohne Inhalt aus. Das ist so, als würdest du nur den Versandschein lesen, ohne das Paket zu öffnen.

curl -I https://example.com/
HTTP/2 200
server: nginx/1.28.0
date: Wed, 28 Oct 2026 05:29:23 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
last-modified: Tue, 27 Oct 2026 21:12:18 GMT
cache-control: max-age=0
expires: Wed, 28 Oct 2026 05:29:23 GMT
accept-ranges: none
alt-svc: h3=":443"; ma=86400

Das [HTTP/2 200] in der ersten Zeile ist der Statuscode. Darunter folgen Servertyp, Inhaltstyp und Cache-Header. Sendest du dieselbe Anfrage an die http-Adresse, erscheint 301 zusammen mit der https-Zieladresse im Header [Location].

curl -I http://example.com/
HTTP/1.1 301 Moved Permanently
Server: nginx/1.28.0
Date: Wed, 28 Oct 2026 05:27:51 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://example.com/

Als wir die http-Adresse ohne Optionen anfragten, fragte curl die Adresse aus [Location] nicht erneut an, sondern gab nur die 7 Zeilen Inhalt der 301-Antwort aus und beendete sich.

curl http://example.com/
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.28.0</center>
</body>
</html>

Mit -L fragt curl die Adresse aus [Location] erneut an. Kombinierst du es mit -I zu -IL, folgen auf die Header der 301-Antwort der Reihe nach die Header der 200-Antwort.

curl -IL http://example.com/
HTTP/1.1 301 Moved Permanently
Server: nginx/1.28.0
Date: Wed, 28 Oct 2026 05:29:23 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://example.com/

HTTP/2 200
server: nginx/1.28.0
date: Wed, 28 Oct 2026 05:29:23 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
last-modified: Tue, 27 Oct 2026 21:12:18 GMT
cache-control: max-age=0
expires: Wed, 28 Oct 2026 05:29:23 GMT
accept-ranges: none
alt-svc: h3=":443"; ma=86400

Im Diagramm unten kannst du Schritt für Schritt vergleichen, wie viele Anfragen je nach Option hinausgehen und was auf dem Bildschirm erscheint.

🧭 Anfragen und Ausgabe je curl-Option: die 301 der http-Adresse
Erklär-Diagramm
⚙️ Option
$ curl -I -L -IL http://example.com/
① GETHEAD Anfragehttp://example.com/
➜
301 Moved PermanentlyLocation: https://example.com/
② GETHEAD Anfragehttps://example.com/Keine Anfrage
➜
200Keine Antwort
🖥️ Was auf dem Bildschirm erscheint
Inhalt der 301-Antwort (7 Zeilen HTML)
Header der 301-Antwort, 7 Zeilen
Inhalt der 200-Antwort (HTML der Startseite, 96.679 Byte)
301-Header, 7 Zeilen → 200-Header, 10 Zeilen
Ohne Optionen fragt curl die https-Adresse aus [Location] nicht erneut an und gibt nur den Inhalt der 301-Antwort aus.
-I holt mit einer HEAD-Anfrage nur die Header und gibt, ohne die neue Adresse anzufragen, den Status 301 und den Header [Location] aus.
-L sendet eine weitere Anfrage an die https-Adresse aus [Location] und gibt den Inhalt der letzten 200-Antwort aus.
-IL gibt die Header beider Antworten der Reihe nach aus. Auf die 301 folgt die 200.

3️⃣ Dateien mit dem curl-Befehl herunterladen (-o, -O)

-O speichert die Datei unter dem letzten Dateinamen der Adresse im aktuellen Ordner. Während des Speicherns zeigt der Bildschirm statt des Inhalts eine Fortschrittsanzeige.

curl -O https://example.com/wp-includes/images/w-logo-blue.png
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  3113  100  3113    0     0   178k      0 --:--:-- --:--:-- --:--:--  190k
ls -l w-logo-blue.png
-rw-r--r-- 1 root root 3113 Oct 28 14:29 w-logo-blue.png

Nach dem Herunterladen zeigten [Total] und [Received] in der Fortschrittsanzeige beide 3113, und die mit ls -l geprüfte Dateigröße stimmte mit 3.113 Byte überein.

Willst du den Dateinamen selbst festlegen, schreibst du ihn hinter -o. Unten siehst du das Ergebnis, wenn die Adresse der Startseite als home.html gespeichert wird.

curl -o home.html https://example.com/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 96679    0 96679    0     0  4291k      0 --:--:-- --:--:-- --:--:-- 4291k
ls -l home.html
-rw-r--r-- 1 root root 96679 Oct 28 14:29 home.html

-O übernimmt den Dateinamen am Ende der Adresse unverändert und passt daher nicht zu Seitenadressen, die mit einem Schrägstrich enden. Hängst du -O an die Adresse der Startseite, findet curl keinen Dateinamen und bricht mit dem Fehler unten ab.

curl -O https://example.com/
curl: Remote file name has no length!
curl: (23) Failed writing received data to disk/application

4️⃣ POST-Anfragen mit curl und JSON-Daten senden

Um mit einer Anfrage, die bisher nur gelesen hat, Daten mitzuschicken, verwendest du -d, und mit -H gibst du das Datenformat an. -d sendet die dahinter geschriebenen Daten als POST-Inhalt. Ohne weitere Angabe ist der [Content-Type] [application/x-www-form-urlencoded].

Mit -d wird die Anfragemethode zu POST, deshalb kannst du [-X POST] weglassen. Auch die offizielle Dokumentation erklärt, dass -X meist nicht nötig ist.

Wenn du JSON sendest, änderst du mit -H den [Content-Type] auf [application/json]. Unten siehst du das Ergebnis einer Anfrage zum Erstellen eines Beitrags an die WordPress-REST-API ohne Authentifizierung.

curl -s -X POST -H 'Content-Type: application/json' -d '{"title":"curl test"}' https://example.com/wp-json/wp/v2/posts
{"code":"rest_authentication_error","message":"\uc8c4\uc1a1\ud569\ub2c8\ub2e4. REST API \uc694\uccad\uc744 \ud560 \uc218 \uc788\ub294 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4.","data":{"status":401}}

Die angefragte Website blockiert REST-API-Anfragen von nicht angemeldeten Nutzern und daher kam bei code [rest_authentication_error] zurück, der Status war 401. Wegen derselben Einstellung kam auch bei einer GET-Anfrage nach der Beitragsliste an derselben Adresse 401 zurück. Der Wert von message ist eine Fehlermeldung in der Sprache der Website, die in die Unicode-Schreibweise von JSON umgewandelt wurde.

Um nur den Statuscode zu prüfen, verwirfst du den Inhalt mit [-o /dev/null] und gibst mit -w nur http_code aus.

curl -s -o /dev/null -w '%{http_code}\n' -X POST -H 'Content-Type: application/json' -d '{"title":"curl test"}' https://example.com/wp-json/wp/v2/posts
401

5️⃣ Antwortzeit mit dem curl-Befehl messen (-w)

Bei langsamen Antworten schaut man leicht nur auf total, aber ob die Zeit beim Verbindungsaufbau oder bei der Verarbeitung auf dem Server verloren ging, siehst du erst, wenn du die Zeiten der einzelnen Abschnitte getrennt ausgibst. -w gibt nach Ende der Anfrage die Messwerte im angegebenen Format aus. Die Werte werden an den Stellen [%{Variablenname}] im Format eingesetzt.

Den Inhalt verwirfst du mit [-o /dev/null], die Fortschrittsanzeige blendest du mit -s aus.

curl -o /dev/null -s -w 'code: %{http_code}\nconnect: %{time_connect}\ntls: %{time_appconnect}\nttfb: %{time_starttransfer}\ntotal: %{time_total}\n' https://example.com/
code: 200
connect: 0.001507
tls: 0.017728
ttfb: 0.021912
total: 0.022825

connect ist der TCP-Verbindungsaufbau, tls die TLS-Aushandlung, ttfb die Zeit bis kurz vor der Übertragung des ersten Bytes und total die Zeit bis zum Ende der Übertragung. Alle vier Werte sind in Sekunden ab dem Start der Anfrage aufsummiert.

Da der Server, auf dem curl lief, und die angefragte Website auf demselben Server lagen, dauerte der Verbindungsaufbau nur 0,0015 Sekunden, bis zum Ende der TLS-Aushandlung vergingen 0,0177 Sekunden und bis zum ersten Byte 0,0219 Sekunden. Vom Ende der TLS-Aushandlung bis zum Eintreffen des ersten Bytes waren es etwa 0,004 Sekunden. Laut offizieller Dokumentation enthält dieser Abschnitt die Zeit, die der Server zum Erzeugen des Ergebnisses braucht.

Als wir denselben Befehl noch dreimal ausführten, lag total zwischen 0,0219 und 0,0226 Sekunden.

🔲 Simulator für den curl-Befehl

Im Simulator unten kannst du die bisherigen Befehle selbst eingeben und prüfen, wie sich die Ausgabe je nach Option ändert.

Simulator für den curl-Befehlcurl 7.76.1
[root@server work]#
Mit den Tasten ↑↓ holst du zuvor eingegebene Befehle zurück.

🔢 FAQ & empfohlene Inhalte

-s blendet sowohl die Fortschrittsanzeige als auch Fehlermeldungen aus. Als wir eine nicht vorhandene Adresse anfragten, wurde nichts ausgegeben, nur der Exit-Code 6 blieb. Gibst du -sS zusammen an, bleibt die Fortschrittsanzeige ausgeblendet, Fehler wie [curl: (6) Could not resolve host] erscheinen aber weiterhin.

-k überspringt den Schritt, der prüft, ob die Verbindung sicher ist. curl sendet dann, ohne zu prüfen, ob der erreichte Server wirklich zu dieser Domain gehört. curl prüft, ob das Serverzertifikat den Domainnamen enthält, mit dem du dich verbunden hast, und ob es sich über den Zertifikatsspeicher verifizieren lässt. Tritt dieser Fehler auf, prüfe zuerst den Domainnamen und den Aussteller des Zertifikats.

Laut offizieller Dokumentation wandelt curl die nächste Anfrage in GET um, wenn eine 301-, 302- oder 303-Antwort kommt. Um POST beizubehalten, verwendest du eigene Optionen wie [--post301]. Eine mit -X festgelegte Methode hat Vorrang vor dieser Umwandlung.

🧭 Empfohlene Artikel zu Netzwerkbefehlen 9 Beiträge · 2 Referenzen
🗂️ Netzwerkbefehle
📄 SSH-Befehl 📄 rsync-Befehl 📄 wget-Befehl 📄 rz- und sz-Befehle 📄 curl-Befehl
📄 host-Befehl 📄 nslookup-Befehl
📄 ip-Befehl 📄 netstat- und ifconfig-Befehle

ℹ️ Affiliate-Hinweis
Die Inhalte dieser Website enthalten Affiliate-Links. Kauft ein Besucher über einen dieser Links ein Produkt oder eine Dienstleistung, erhält die Website vom Verkäufer eine Provision. Der Betrag, den der Käufer zahlt(bei Aktionsrabatten sinkt er ↓), steigt dadurch nicht. Angegebene Preise, Rabatte und Lagerbestände entsprechen dem Stand bei Erstellung und können abweichen; prüfe sie daher vor dem Kauf beim Verkäufer. Produkte werden nach eigenen Kriterien ausgewählt und bewertet, und Provisionen beeinflussen weder die Reihenfolge noch den Inhalt der Bewertungen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Beweisen Sie, dass Sie ein Mensch sind: 2   +   8   =