Skip to content

Commit 3b76c04

Browse files
Merge pull request #246 from dropbox/pipe-support
Add Unix pipe support for put and get
2 parents 6bd95f3 + aac354b commit 3b76c04

10 files changed

Lines changed: 1028 additions & 2 deletions

File tree

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,21 @@ $ dbxcli get /remote/file.txt ./local-file.txt # download a single file
265265
$ dbxcli get -r /remote/folder ./local-folder # recursively download a folder
266266
```
267267

268+
### Piping with stdin/stdout
269+
270+
Use `-` as the local operand to stream through pipes:
271+
272+
```sh
273+
$ printf 'hello' | dbxcli put - /hello.txt # upload from stdin
274+
$ tar cz ./src | dbxcli put - /backups/src.tgz # pipe archive to Dropbox
275+
$ dbxcli get /backups/src.tgz - | tar tz # download to stdout and list
276+
$ dbxcli get /file.txt - > local-copy.txt # download to stdout, redirect to file
277+
```
278+
279+
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.
280+
281+
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 `./-`.
282+
268283
### Removing files and folders
269284

270285
```sh

cmd/get.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ func get(cmd *cobra.Command, args []string) (err error) {
4747

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

50+
if dst == "-" {
51+
return getStdout(cmd, src, recursive)
52+
}
53+
5054
dbx := filesNewFunc(config)
5155

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

85+
func getStdout(cmd *cobra.Command, src string, recursive bool) error {
86+
if recursive {
87+
return errors.New("`get -` cannot be used with --recursive")
88+
}
89+
90+
dbx := filesNewFunc(config)
91+
92+
meta, err := dbx.GetMetadata(files.NewGetMetadataArg(src))
93+
if err == nil {
94+
if _, ok := meta.(*files.FolderMetadata); ok {
95+
return fmt.Errorf("%s is a folder; cannot download folder to stdout", src)
96+
}
97+
}
98+
99+
return downloadToStdout(dbx, src, cmd.OutOrStdout())
100+
}
101+
81102
func getWithClient(dbx files.Client, args []string) (err error) {
82103
if len(args) == 0 || len(args) > 2 {
83104
return errors.New("`get` requires `src` and/or `dst` arguments")
@@ -229,7 +250,7 @@ func downloadFileOnce(dbx files.Client, arg *files.DownloadArg, dst string) erro
229250
if err != nil {
230251
return err
231252
}
232-
defer contents.Close()
253+
defer func() { _ = contents.Close() }()
233254

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

281311
func init() {

0 commit comments

Comments
 (0)