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

# Run commands

> Run scripts, keep shell state between commands, and start background jobs.

Use `sandbox.run()` to execute a command and collect its output. After
[installing LithosBox](/installation), run this example with `lithosbox python`:

```python theme={null}
from lithosbox import LithosBox

box = LithosBox()
sandbox = box.sandboxes.create()

result = sandbox.run(["python3", "-c", "print(6 * 7)"]).check()
print(result.stdout)
```

The result contains `stdout`, `stderr`, and `exit_code`. A nonzero exit code does
not raise an exception unless you call `.check()`.

The examples below continue with the same `sandbox`.

## Choose a command format

Pass a string when you want shell features such as pipes and redirects:

```python theme={null}
sandbox.run("mkdir -p /work && printf 'hello\n' > /work/message.txt").check()
print(sandbox.run("cat /work/message.txt | tr a-z A-Z").check().stdout)
```

Pass a list when arguments contain filenames, user input, or other values that
should be treated literally. Each list item is a separate argument:

```python theme={null}
message = "hello; this is text"
result = sandbox.run(["printf", "%s\n", message]).check()
print(result.stdout)
```

Use `stdin` to send input to a command:

```python theme={null}
result = sandbox.run(["wc", "-c"], stdin=b"hello").check()
print(result.stdout)
```

## Keep shell state

A regular `run()` starts a new shell. Files persist, but changes to the working
directory or environment variables do not carry into the next call.

Use a session for commands that share shell state:

```python theme={null}
with sandbox.session() as shell:
    shell.run("mkdir -p /work && cd /work").check()
    shell.run("export GREETING=hello").check()
    result = shell.run('printf "%s from %s\n" "$GREETING" "$PWD"').check()
    print(result.stdout)
```

Closing a session ends its shell. A session keeps state between commands; it does
not increase the time allowed for an individual command.

## Start a background job

Use `background=True` for a server, worker, or command that may take longer than
about 110 seconds. It accepts a shell string and returns after the job starts.
Redirect output to a file so you can read it later.

```python theme={null}
sandbox.files.write(
    "/work/job.py",
    "import time\ntime.sleep(2)\nprint('Job finished')\n",
)
sandbox.run(
    "python3 /work/job.py > /work/job.log 2>&1; echo $? > /work/job.exit",
    background=True,
).check()
```

Check the result in a later call:

```python theme={null}
if sandbox.files.exists("/work/job.exit"):
    exit_code = int(sandbox.files.read("/work/job.exit").strip())
    print("Exit code:", exit_code)
    print(sandbox.files.read("/work/job.log"))
```

A successful start does not mean the job completed successfully. Check its exit
file or application status before using the result. Active background jobs keep
the sandbox awake; you do not need a keep-alive loop.

`background=True` does not accept `stdin` or return a process ID. Write input to a
file first. If you need to stop the job individually, have it record its process
ID and use that ID in a later command.

## Command limits

Synchronous `run()` and session calls allow about 110 seconds. Each argument can
contain at most 131,071 bytes, and `stdin` can contain up to 4 MiB per call.

Each output stream is limited to 16 MiB. Check `result.truncated` before relying
on a large result; use files for binary output or larger results. See
[Work with files](/guides/files#transfer-larger-files) for transfer options.

When you have collected your results and no longer need the sandbox:

```python theme={null}
sandbox.delete()
box.close()
```
