Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,21 @@ $ dbxcli get /remote/file.txt ./local-file.txt # download a single file
$ dbxcli get -r /remote/folder ./local-folder # recursively download a folder
```

### Piping with stdin/stdout

Use `-` as the local operand to stream through pipes:

```sh
$ printf 'hello' | dbxcli put - /hello.txt # upload from stdin
$ tar cz ./src | dbxcli put - /backups/src.tgz # pipe archive to Dropbox
$ dbxcli get /backups/src.tgz - | tar tz # download to stdout and list
$ dbxcli get /file.txt - > local-copy.txt # download to stdout, redirect to file
```

Stdin uploads are spooled to a temp file before uploading, so disk space up to the full input size is required. Stdout downloads are byte-clean: all progress and diagnostic output goes to stderr.

A bare `-` means stream only when it is the local operand. Dropbox paths named `-` are valid, for example `dbxcli put - /-` and `dbxcli get /- -`. To upload a local file literally named `-`, use `./-`.

### Removing files and folders

```sh
Expand Down
34 changes: 32 additions & 2 deletions cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func get(cmd *cobra.Command, args []string) (err error) {

recursive, _ := cmd.Flags().GetBool("recursive")

if dst == "-" {
return getStdout(cmd, src, recursive)
}

dbx := filesNewFunc(config)

meta, err := dbx.GetMetadata(files.NewGetMetadataArg(src))
Expand Down Expand Up @@ -78,6 +82,23 @@ func get(cmd *cobra.Command, args []string) (err error) {
return downloadFile(dbx, src, dst)
}

func getStdout(cmd *cobra.Command, src string, recursive bool) error {
if recursive {
return errors.New("`get -` cannot be used with --recursive")
}

dbx := filesNewFunc(config)

meta, err := dbx.GetMetadata(files.NewGetMetadataArg(src))
if err == nil {
if _, ok := meta.(*files.FolderMetadata); ok {
return fmt.Errorf("%s is a folder; cannot download folder to stdout", src)
}
}

return downloadToStdout(dbx, src, cmd.OutOrStdout())
}

func getWithClient(dbx files.Client, args []string) (err error) {
if len(args) == 0 || len(args) > 2 {
return errors.New("`get` requires `src` and/or `dst` arguments")
Expand Down Expand Up @@ -229,7 +250,7 @@ func downloadFileOnce(dbx files.Client, arg *files.DownloadArg, dst string) erro
if err != nil {
return err
}
defer contents.Close()
defer func() { _ = contents.Close() }()

finalDst, err := downloadDestinationPath(dst)
if err != nil {
Expand Down Expand Up @@ -275,7 +296,16 @@ func downloadFileOnce(dbx files.Client, arg *files.DownloadArg, dst string) erro
var getCmd = &cobra.Command{
Use: "get [flags] <source> [<target>]",
Short: "Download a file or folder",
RunE: get,
Long: `Download a file or folder from Dropbox.
- Use --recursive (-r) to download entire directories.
- Use - as target to write file bytes to stdout.
Stdout is byte-clean: all progress and errors go to stderr.
`,
Example: ` dbxcli get /remote/file.txt ./local-file.txt
dbxcli get -r /remote/folder ./local-folder
dbxcli get /backups/src.tgz - | tar tz
dbxcli get /file.txt - > local-copy.txt`,
RunE: get,
}

func init() {
Expand Down
Loading