github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/cmd/lsf/lsf.go (about) 1 package lsf 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "os" 8 9 "github.com/pkg/errors" 10 "github.com/rclone/rclone/cmd" 11 "github.com/rclone/rclone/cmd/ls/lshelp" 12 "github.com/rclone/rclone/fs" 13 "github.com/rclone/rclone/fs/config/flags" 14 "github.com/rclone/rclone/fs/hash" 15 "github.com/rclone/rclone/fs/operations" 16 "github.com/spf13/cobra" 17 ) 18 19 var ( 20 format string 21 separator string 22 dirSlash bool 23 recurse bool 24 hashType = hash.MD5 25 filesOnly bool 26 dirsOnly bool 27 csv bool 28 absolute bool 29 ) 30 31 func init() { 32 cmd.Root.AddCommand(commandDefinition) 33 cmdFlags := commandDefinition.Flags() 34 flags.StringVarP(cmdFlags, &format, "format", "F", "p", "Output format - see help for details") 35 flags.StringVarP(cmdFlags, &separator, "separator", "s", ";", "Separator for the items in the format.") 36 flags.BoolVarP(cmdFlags, &dirSlash, "dir-slash", "d", true, "Append a slash to directory names.") 37 flags.FVarP(cmdFlags, &hashType, "hash", "", "Use this hash when `h` is used in the format MD5|SHA-1|DropboxHash") 38 flags.BoolVarP(cmdFlags, &filesOnly, "files-only", "", false, "Only list files.") 39 flags.BoolVarP(cmdFlags, &dirsOnly, "dirs-only", "", false, "Only list directories.") 40 flags.BoolVarP(cmdFlags, &csv, "csv", "", false, "Output in CSV format.") 41 flags.BoolVarP(cmdFlags, &absolute, "absolute", "", false, "Put a leading / in front of path names.") 42 flags.BoolVarP(cmdFlags, &recurse, "recursive", "R", false, "Recurse into the listing.") 43 } 44 45 var commandDefinition = &cobra.Command{ 46 Use: "lsf remote:path", 47 Short: `List directories and objects in remote:path formatted for parsing`, 48 Long: ` 49 List the contents of the source path (directories and objects) to 50 standard output in a form which is easy to parse by scripts. By 51 default this will just be the names of the objects and directories, 52 one per line. The directories will have a / suffix. 53 54 Eg 55 56 $ rclone lsf swift:bucket 57 bevajer5jef 58 canole 59 diwogej7 60 ferejej3gux/ 61 fubuwic 62 63 Use the --format option to control what gets listed. By default this 64 is just the path, but you can use these parameters to control the 65 output: 66 67 p - path 68 s - size 69 t - modification time 70 h - hash 71 i - ID of object 72 o - Original ID of underlying object 73 m - MimeType of object if known 74 e - encrypted name 75 T - tier of storage if known, eg "Hot" or "Cool" 76 77 So if you wanted the path, size and modification time, you would use 78 --format "pst", or maybe --format "tsp" to put the path last. 79 80 Eg 81 82 $ rclone lsf --format "tsp" swift:bucket 83 2016-06-25 18:55:41;60295;bevajer5jef 84 2016-06-25 18:55:43;90613;canole 85 2016-06-25 18:55:43;94467;diwogej7 86 2018-04-26 08:50:45;0;ferejej3gux/ 87 2016-06-25 18:55:40;37600;fubuwic 88 89 If you specify "h" in the format you will get the MD5 hash by default, 90 use the "--hash" flag to change which hash you want. Note that this 91 can be returned as an empty string if it isn't available on the object 92 (and for directories), "ERROR" if there was an error reading it from 93 the object and "UNSUPPORTED" if that object does not support that hash 94 type. 95 96 For example to emulate the md5sum command you can use 97 98 rclone lsf -R --hash MD5 --format hp --separator " " --files-only . 99 100 Eg 101 102 $ rclone lsf -R --hash MD5 --format hp --separator " " --files-only swift:bucket 103 7908e352297f0f530b84a756f188baa3 bevajer5jef 104 cd65ac234e6fea5925974a51cdd865cc canole 105 03b5341b4f234b9d984d03ad076bae91 diwogej7 106 8fd37c3810dd660778137ac3a66cc06d fubuwic 107 99713e14a4c4ff553acaf1930fad985b gixacuh7ku 108 109 (Though "rclone md5sum ." is an easier way of typing this.) 110 111 By default the separator is ";" this can be changed with the 112 --separator flag. Note that separators aren't escaped in the path so 113 putting it last is a good strategy. 114 115 Eg 116 117 $ rclone lsf --separator "," --format "tshp" swift:bucket 118 2016-06-25 18:55:41,60295,7908e352297f0f530b84a756f188baa3,bevajer5jef 119 2016-06-25 18:55:43,90613,cd65ac234e6fea5925974a51cdd865cc,canole 120 2016-06-25 18:55:43,94467,03b5341b4f234b9d984d03ad076bae91,diwogej7 121 2018-04-26 08:52:53,0,,ferejej3gux/ 122 2016-06-25 18:55:40,37600,8fd37c3810dd660778137ac3a66cc06d,fubuwic 123 124 You can output in CSV standard format. This will escape things in " 125 if they contain , 126 127 Eg 128 129 $ rclone lsf --csv --files-only --format ps remote:path 130 test.log,22355 131 test.sh,449 132 "this file contains a comma, in the file name.txt",6 133 134 Note that the --absolute parameter is useful for making lists of files 135 to pass to an rclone copy with the --files-from flag. 136 137 For example to find all the files modified within one day and copy 138 those only (without traversing the whole directory structure): 139 140 rclone lsf --absolute --files-only --max-age 1d /path/to/local > new_files 141 rclone copy --files-from new_files /path/to/local remote:path 142 143 ` + lshelp.Help, 144 Run: func(command *cobra.Command, args []string) { 145 cmd.CheckArgs(1, 1, command, args) 146 fsrc := cmd.NewFsSrc(args) 147 cmd.Run(false, false, command, func() error { 148 // Work out if the separatorFlag was supplied or not 149 separatorFlag := command.Flags().Lookup("separator") 150 separatorFlagSupplied := separatorFlag != nil && separatorFlag.Changed 151 // Default the separator to , if using CSV 152 if csv && !separatorFlagSupplied { 153 separator = "," 154 } 155 return Lsf(context.Background(), fsrc, os.Stdout) 156 }) 157 }, 158 } 159 160 // Lsf lists all the objects in the path with modification time, size 161 // and path in specific format. 162 func Lsf(ctx context.Context, fsrc fs.Fs, out io.Writer) error { 163 var list operations.ListFormat 164 list.SetSeparator(separator) 165 list.SetCSV(csv) 166 list.SetDirSlash(dirSlash) 167 list.SetAbsolute(absolute) 168 var opt = operations.ListJSONOpt{ 169 NoModTime: true, 170 NoMimeType: true, 171 DirsOnly: dirsOnly, 172 FilesOnly: filesOnly, 173 Recurse: recurse, 174 } 175 176 for _, char := range format { 177 switch char { 178 case 'p': 179 list.AddPath() 180 case 't': 181 list.AddModTime() 182 opt.NoModTime = false 183 case 's': 184 list.AddSize() 185 case 'h': 186 list.AddHash(hashType) 187 opt.ShowHash = true 188 case 'i': 189 list.AddID() 190 case 'm': 191 list.AddMimeType() 192 opt.NoMimeType = false 193 case 'e': 194 list.AddEncrypted() 195 opt.ShowEncrypted = true 196 case 'o': 197 list.AddOrigID() 198 opt.ShowOrigIDs = true 199 case 'T': 200 list.AddTier() 201 default: 202 return errors.Errorf("Unknown format character %q", char) 203 } 204 } 205 206 return operations.ListJSON(ctx, fsrc, "", &opt, func(item *operations.ListJSONItem) error { 207 _, _ = fmt.Fprintln(out, list.Format(item)) 208 return nil 209 }) 210 }