Skip to content

Instantly share code, notes, and snippets.

@pwmcintyre
Last active May 13, 2022 05:43
Show Gist options
  • Save pwmcintyre/6f35e1618ae4e8633203495174afdd62 to your computer and use it in GitHub Desktop.
Save pwmcintyre/6f35e1618ae4e8633203495174afdd62 to your computer and use it in GitHub Desktop.
list s3 directory by depth
// usage:
// $ AWS_PROFILE=foo AWS_REGION=us-east-1 go run . example-bucket 3
package main
import (
"context"
"fmt"
"log"
"os"
"strconv"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
type S3Lister interface {
ListObjectsV2(ctx context.Context, params *s3.ListObjectsV2Input, optFns ...func(*s3.Options)) (*s3.ListObjectsV2Output, error)
}
func main() {
// args
args := os.Args[1:]
if len(args) != 2 {
fmt.Println("must give 2 args: BucketName and Depth")
os.Exit(1)
}
Bucket := args[0]
Depth, err := strconv.Atoi(args[1])
if err != nil {
fmt.Println(err)
os.Exit(1)
}
ctx := context.TODO()
// Load the Shared AWS Configuration (~/.aws/config)
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
log.Fatal(err)
}
// begin
if err := step(s3.NewFromConfig(cfg), ctx, Bucket, nil, uint(Depth), func(object string) {
fmt.Println(object)
}); err != nil {
log.Fatal(err)
}
}
func step(
client S3Lister,
ctx context.Context,
Bucket string,
Prefix *string,
depth uint,
fn func(p string),
) error {
// emit if at desired depth
if depth == 0 {
fn(*Prefix)
return nil
}
// list
output, err := client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{
Bucket: &Bucket,
Prefix: Prefix,
Delimiter: aws.String("/"),
})
if err != nil {
return err
}
// recurse
for _, CommonPrefix := range output.CommonPrefixes {
if err := step(client, ctx, Bucket, CommonPrefix.Prefix, depth-1, fn); err != nil {
return err
}
}
return nil
}
@pwmcintyre
Copy link
Author

pwmcintyre commented May 13, 2022

ever wanted to ls an s3 bucket with a directory depth? Now you can!

Known issues:

  • paginate if more than 1000 items exist within a delimiter prefix
  • mix of log.Fatal and fmt.Print + os.Exit (pick one)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment