Attachments
The attachments command (aliases attachment, a) surfaces Redmine’s Attachments API so you can inspect an attachment’s metadata and download its bytes. Downloads reuse the active profile’s server and API key, streaming straight to disk - no curl, no manually extracted key.
redmine attachments get <id> [flags]Aliases: show, view, metadata. Fetches the attachment’s ID, filename, size, content type, description, author, and creation time via GET /attachments/:id.json. Table output also shows the download URL (when present); json returns every field, including content_url.
| Flag | Description |
|---|---|
-o, --output |
Output format: table, json |
redmine attachments get 42redmine attachments get 42 -o jsondownload
Section titled “download”redmine attachments download <id> [flags]Aliases: dl, get-file. Streams the attachment’s raw bytes to disk (or stdout), authenticating with the active profile. The response is streamed, never buffered entirely in memory, so large files are safe.
| Flag | Description |
|---|---|
-d, --dir |
Directory to save into, using the attachment’s real filename (created if missing) |
--path |
Exact destination file path. Use - to stream to stdout |
--clobber |
Overwrite an existing file at the destination |
--allow-hidden |
Allow saving under a server-supplied filename that starts with . (with --dir or the default destination) |
-o, --output |
Confirmation format: json prints a result object; otherwise a human line is written to stderr |
With no destination flag, the file is saved as ./<filename> in the current directory.
Existing files and --clobber
Section titled “Existing files and --clobber”Downloads never overwrite an existing file unless you pass --clobber. This applies to --path, --dir, and the default current directory. Without it, the command fails before downloading and names the path:
failed to download attachment 42: logo.png already exists; use --clobber to overwrite itThe bytes are first streamed into a temporary file in the destination directory and moved into place only once the download has completed. As a result:
- A failed or interrupted download leaves any existing file untouched and leaves no partial file at the destination. Pressing Ctrl-C once stops the download and removes its temporary file. If the process is killed outright (a second Ctrl-C,
kill -9), a hidden.redmine-download-*.tmpfile may remain in the destination directory; it is safe to delete. - A symlink at the destination is never followed. Without
--clobberit counts as an existing file (even when it is dangling); with--clobberthe link itself is replaced by the downloaded file, and whatever it pointed to is left alone. - A directory at the destination is always an error, even with
--clobber. So is any other non-regular file, except that a--paththat is (or links to) a character device or a named pipe, such as/dev/nullor a FIFO, is written into directly, without--clobber. (/dev/stdoutcounts when stdout is a terminal or a pipe; to write to stdout, prefer--path -.) With--diror the default destination such an entry is refused like a directory. - A new file gets the same permissions as any other file you create (
0644with the usual umask022). With--clobber, a replaced regular file keeps its previous permissions.
Without --clobber, the final step uses a hard link, which fails atomically if a file appeared at the destination while the download was running. On filesystems without hard-link support the CLI falls back to re-checking the destination and then renaming, which leaves a small window between the check and the rename.
With --dir or the default destination the filename comes from the server. It is reduced to its base name, so it can never escape the directory. A name that starts with . (such as .bashrc, .envrc or .npmrc) is refused, because it could plant or shadow a configuration file, unless you pass --allow-hidden:
failed to download attachment 42: refusing to save the hidden filename ".bashrc" as downloads/.bashrc; pass --allow-hidden to save it anywayChoosing the name yourself with --path is not affected, and neither is --path - (stdout).
If the server redirects the download (or any other request), the redirect is followed only when it stays on the configured server (the same host and port, or the https:// upgrade of an http:// server, port 80 becoming 443), or goes to a public address (for example presigned object-storage URLs such as S3). Credentials are only sent to the configured server, never to the redirect target. Redirects from https:// to http://, or to loopback, private, link-local, multicast, unspecified (0.0.0.0/8), carrier-grade NAT (100.64.0.0/10), or benchmarking (198.18.0.0/15) addresses are refused, including IPv6 addresses that embed one of them (IPv4-mapped, NAT64 64:ff9b::/96, 6to4 2002::/16); host names are re-checked against the address actually connected to. When the redirect goes through an HTTP(S) proxy, the CLI never connects to the target itself, so it resolves the host name locally and refuses it if it points at one of these addresses; a name only the proxy can resolve is left to the proxy. Another port on the configured server’s host gets the same checks as any other host. A redirect to a public http:// URL is followed as long as it does not come from an https:// URL.
# Saves ./<filename>redmine attachments download 42redmine attachments download 42 --dir ./downloadsredmine attachments download 42 --path ./logo.png# Replace a copy left over from an earlier downloadredmine attachments download 42 --dir ./downloads --clobberredmine attachments download 42 --path - | file -redmine attachments download 42 --dir ./downloads -o json