> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Exécution de commandes

> Exécutez des commandes dans des bacs à sable avec diffusion en continu, contrôle des processus et gestion des erreurs.

Ces exemples utilisent un jeton d’accès à l’API CoreWeave défini dans `CWSANDBOX_API_KEY`. Pour l’authentification par clé API Forge, consultez [Premiers pas](/fr/products/sandboxes/get-started). Pour connaître les exigences relatives à CKS, consultez [Modes de placement](/fr/products/sandboxes/placement).

Ce guide explique comment exécuter des commandes dans des bacs à sable à l’aide de la méthode `exec()`. Utilisez-la pour exécuter des commandes shell, des scripts ou des interpréteurs interactifs dans une sandbox lorsque vous souhaitez capturer leur sortie, la diffuser en temps réel, envoyer des données sur stdin ou contrôler la gestion des codes de sortie non nuls. Ce guide s’adresse aux développeurs qui utilisent déjà le client Python `cwsandbox`.

<h2 id="run-a-basic-command">
  Exécuter une commande de base
</h2>

Commencez par une commande unique qui s’exécute jusqu’à son achèvement et renvoie la sortie capturée. La méthode `exec()` renvoie un handle `Process` :

```python theme={"system"}
from cwsandbox import Sandbox

with Sandbox.run() as sandbox:
    # Exécuter une commande et obtenir le résultat
    result = sandbox.exec(["echo", "Hello, World!"]).result()

    print(result.stdout)      # "Hello, World!\n"
    print(result.returncode)  # 0
```

<h2 id="get-results">
  Obtenir les résultats
</h2>

`exec()` rend la main immédiatement, ce qui vous permet de choisir comment attendre la fin de la commande. Appelez `.result()` sur le handle `Process` pour bloquer jusqu’à l’obtention de la sortie :

```python theme={"system"}
# Renvoie immédiatement un objet Process
process = sandbox.exec(["python", "-c", "print('hello')"])

# Attendre le résultat (appel bloquant)
result = process.result()
print(result.stdout)      # "hello\n"
print(result.stderr)      # ""
print(result.returncode)  # 0

# Variante en une seule ligne
result = sandbox.exec(["ls", "-la"]).result()
```

<h2 id="stream-output">
  Sortie en flux
</h2>

Un appel bloquant à `.result()` attend que la commande se termine avant d’afficher la moindre sortie. Pour suivre la progression en temps réel, itérez sur `process.stdout` avant d’appeler `.result()` :

```python theme={"system"}
# Renvoie immédiatement un objet Process
process = sandbox.exec(["python", "long_script.py"])

# Lire stdout en flux, ligne par ligne
for line in process.stdout:
    print(f"[stdout] {line}", end="")

# Obtenir le résultat final
result = process.result()
print(f"Exit code: {result.returncode}")
```

Utilisez la diffusion en continu lorsque vous devez :

* Surveiller des processus de longue durée.
* Traiter la sortie au fur et à mesure qu’elle arrive.
* Mettre en place des indicateurs de progression.

<h2 id="stream-input-to-stdin">
  Transmettre une entrée en flux vers stdin
</h2>

Certaines commandes ont besoin de recevoir une entrée sur stdin pendant leur exécution, comme les pipelines, les interpréteurs interactifs ou les outils qui lisent jusqu’à EOF. Pour envoyer une entrée à des commandes en cours d’exécution, activez stdin avec `stdin=True` :

```python theme={"system"}
with Sandbox.run() as sandbox:
    process = sandbox.exec(["cat"], stdin=True)

    process.stdin.write(b"hello world\n").result()
    process.stdin.close().result()

    result = process.result()
    print(result.stdout)  # "hello world\n"
```

<h3 id="streamwriter-methods">
  Méthodes de StreamWriter
</h3>

Lorsque `stdin=True`, `process.stdin` est un `StreamWriter` doté de trois méthodes :

* **`write(data: bytes)`** : écrit des octets bruts. Renvoie `OperationRef[None]`.
* **`writeline(text: str)`** : écrit du texte suivi d’un saut de ligne (encodé en UTF-8). Renvoie `OperationRef[None]`.
* **`close()`** : signale la fin de fichier (EOF). Le système finalise d’abord les écritures en attente. Renvoie `OperationRef[None]`.

Lorsque `stdin=False` (valeur par défaut), `process.stdin` vaut `None`.

<h3 id="send-multiple-writes">
  Effectuer plusieurs écritures
</h3>

Envoyez les données de manière incrémentielle avant de fermer le flux :

```python theme={"system"}
process = sandbox.exec(["cat"], stdin=True)

process.stdin.writeline("line 1").result()
process.stdin.writeline("line 2").result()
process.stdin.writeline("line 3").result()
process.stdin.close().result()

result = process.result()
print(result.stdout)  # "line 1\nline 2\nline 3\n"
```

<h3 id="run-interactive-python-through-stdin">
  Exécuter du code Python en mode interactif via stdin
</h3>

Transmettez du code Python à un interpréteur interactif :

```python theme={"system"}
process = sandbox.exec(["python3"], stdin=True)

process.stdin.writeline("x = 40 + 2").result()
process.stdin.writeline("print(f'answer: {x}')").result()
process.stdin.close().result()

result = process.result()
print(result.stdout)  # "answer: 42\n"
```

<h3 id="combine-stdin-and-stdout-streaming">
  Combiner la diffusion en continu sur stdin et stdout
</h3>

Diffusez la sortie en continu tout en envoyant des entrées :

```python theme={"system"}
process = sandbox.exec(["cat"], stdin=True)

# Envoyer l’entrée
process.stdin.writeline("hello").result()
process.stdin.writeline("world").result()
process.stdin.close().result()

# Lire la sortie en flux au fur et à mesure
for line in process.stdout:
    print(f"[out] {line}", end="")

result = process.result()
```

<h3 id="handle-eof-dependent-commands">
  Gérer les commandes qui dépendent d’EOF
</h3>

Certaines commandes (comme `sort`) lisent l’intégralité de l’entrée avant de produire une sortie. Fermez stdin pour signaler la fin de fichier (EOF) :

```python theme={"system"}
process = sandbox.exec(["sort"], stdin=True)

process.stdin.writeline("banana").result()
process.stdin.writeline("apple").result()
process.stdin.writeline("cherry").result()
process.stdin.close().result()  # sort attend EOF avant de produire sa sortie

result = process.result()
print(result.stdout)  # "apple\nbanana\ncherry\n"
```

<h3 id="use-stdin-in-async-contexts">
  Utiliser stdin dans un contexte asynchrone
</h3>

Dans un contexte asynchrone, appliquez directement `await` à chaque `OperationRef` :

```python theme={"system"}
async with Sandbox.run() as sandbox:
    process = sandbox.exec(["cat"], stdin=True)

    await process.stdin.write(b"async hello\n")
    await process.stdin.close()

    result = await process
    print(result.stdout)  # "async hello\n"
```

<h3 id="when-to-use-stdintrue-compared-with-stdinfalse">
  Quand utiliser stdin=True ou stdin=False
</h3>

| Scénario | stdin | Raison |
| - | - | - |
| Exécuter une commande avec des arguments | `False` | L’entrée provient des arguments, et non de stdin |
| Transmettre des données à une commande via un pipe | `True` | La commande lit depuis stdin |
| Interpréteur interactif | `True` | L’interpréteur lit les commandes depuis stdin |
| Processus qui lit jusqu’à EOF | `True` | Nécessite `close()` pour signaler EOF |
| Commande fire-and-forget | `False` | Aucune entrée requise |

<h2 id="set-the-working-directory">
  Définir le répertoire de travail
</h2>

Par défaut, les commandes s'exécutent dans le répertoire de travail par défaut de la sandbox. Pour en utiliser un autre, remplacez-le avec `cwd` :

```python theme={"system"}
result = sandbox.exec(
    ["ls", "-la"],
    cwd="/app/data",
).result()
```

Le chemin doit être absolu.

<h2 id="set-a-timeout">
  Définir un délai d’expiration
</h2>

Pour arrêter une commande susceptible de se bloquer ou de s’exécuter plus longtemps que prévu, définissez un délai d’expiration avec `timeout_seconds` :

```python theme={"system"}
from cwsandbox import SandboxTimeoutError

try:
    result = sandbox.exec(
        ["sleep", "60"],
        timeout_seconds=5.0,
    ).result()
except SandboxTimeoutError:
    print("Command timed out")
```

<h2 id="handle-errors-with-check">
  Gérer les erreurs avec check
</h2>

Le paramètre `check` détermine le comportement à adopter lorsque le code de sortie est non nul :

<h3 id="default-behavior-with-checkfalse">
  Comportement par défaut avec check=False
</h3>

Renvoie le résultat, quel que soit le code de sortie :

```python theme={"system"}
result = sandbox.exec(["false"]).result()
print(result.returncode)  # 1 (aucune exception levée)
```

<h3 id="raise-on-failure-with-checktrue">
  Lever une exception en cas d’échec avec check=True
</h3>

Lève une exception `SandboxExecutionError` si le code de sortie est non nul :

```python theme={"system"}
from cwsandbox import SandboxExecutionError

try:
    result = sandbox.exec(
        ["python", "-c", "raise ValueError('oops')"],
        check=True,
    ).result()
except SandboxExecutionError as e:
    print(f"Command failed: {e.exec_result.returncode}")
    print(f"stderr: {e.exec_result.stderr}")
```

<h2 id="run-python-code">
  Exécuter du code Python
</h2>

Les bacs à sable servent couramment à exécuter du code Python, qu’il s’agisse de courtes commandes d’une seule ligne ou de scripts plus longs transmis directement en ligne :

```python theme={"system"}
# Commande en une ligne
result = sandbox.exec(
    ["python", "-c", "import sys; print(sys.version)"],
).result()

# Script à partir d’une chaîne de caractères
code = '''
import json
data = {"result": 42}
print(json.dumps(data))
'''
result = sandbox.exec(["python", "-c", code]).result()
output = json.loads(result.stdout)
```

<h2 id="sequential-compared-with-parallel-execution">
  Exécution séquentielle ou exécution parallèle
</h2>

Choisissez l’exécution séquentielle lorsque des commandes dépendent de commandes précédentes, et l’exécution parallèle lorsque les commandes sont indépendantes et que vous souhaitez les exécuter simultanément sur plusieurs bacs à sable.

<h3 id="run-commands-sequentially-when-order-matters">
  Exécuter les commandes séquentiellement lorsque l’ordre est important
</h3>

```python theme={"system"}
# Les dépendances nécessitent une exécution séquentielle
sandbox.exec(["pip", "install", "requests"]).result()
sandbox.exec(["python", "script_using_requests.py"]).result()
```

<h3 id="run-independent-commands-in-parallel">
  Exécuter des commandes indépendantes en parallèle
</h3>

```python theme={"system"}
# Démarrer plusieurs bacs à sable
sandboxes = [Sandbox.run() for _ in range(3)]

# Lancer des commandes dans chacun d’eux
processes = [
    sb.exec(["python", "-c", f"print({i})"])
    for i, sb in enumerate(sandboxes)
]

# Récupérer tous les résultats
results = [p.result() for p in processes]
for r in results:
    print(r.stdout)
```

<h3 id="wait-for-n-of-m-processes-to-complete">
  Attendre la fin de N processus sur M
</h3>

Utilisez `cwsandbox.wait()` pour attendre qu’un sous-ensemble de processus se termine :

```python theme={"system"}
import cwsandbox

processes = [sb.exec(["python", "task.py"]) for sb in sandboxes]

# Attendre la fin des 2 premiers processus
done, pending = cwsandbox.wait(processes, num_returns=2)

# Traiter immédiatement les processus terminés
for p in done:
    print(p.result().stdout)

# Attendre les processus restants
for p in pending:
    print(p.result().stdout)
```

<h2 id="control-processes">
  Contrôler les processus
</h2>

Lorsqu’une commande continue de s’exécuter une fois que l’appel `exec()` a rendu la main, vous pouvez vérifier son état sans bloquer, ou attendre qu’elle se termine au moment qui vous convient. Le handle `Process` fournit des méthodes de surveillance et de contrôle :

```python theme={"system"}
process = sandbox.exec(["python", "server.py"])

# Vérifier si le processus est toujours en cours d'exécution (non-blocking)
if process.poll() is None:
    print("Still running")

# Attendre l'achèvement du processus
exit_code = process.wait()
print(f"Exited with code: {exit_code}")
```
