1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
| package main
import (
"fmt"
"github.com/spf13/cobra"
"os"
"path/filepath"
"strconv"
"strings"
)
type RenameConfig struct {
Debug bool
DoTry bool
Format string
Recursive bool
Move bool
OutputDir string
Template string
StartIndex int
}
func main() {
rootCmd := &cobra.Command{
Use: "bookImporter",
Short: "Import books into your library",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("bookImporter v0.1")
},
}
renameCmd := &cobra.Command{
Use: "rename",
Short: "Rename or move files according to a template",
Long: `Rename or move files according to a template.
The rename command will rename or move files according to a template that you
specify. The template can include the file extension, so if you want to keep
the original extension, you can include it in the template. You can also use
a sequence number in the template to number the files sequentially.`,
Run: func(cmd *cobra.Command, args []string) {
config := RenameConfig{
Debug: cmd.Flag("debug").Value.String() == "true",
DoTry: cmd.Flag("do-try").Value.String() == "true",
Format: cmd.Flag("format").Value.String(),
Recursive: cmd.Flag("recursive").Value.String() == "true",
Move: cmd.Flag("move").Value.String() == "true",
OutputDir: cmd.Flag("output").Value.String(),
Template: cmd.Flag("template").Value.String(),
StartIndex: parseIntFlag(cmd, "start-num"),
}
if config.Debug {
fmt.Println("Debugging information:")
fmt.Printf(" - Format: %s\n", config.Format)
fmt.Printf(" - Recursive: %v\n", config.Recursive)
fmt.Printf(" - Move: %v\n", config.Move)
fmt.Printf(" - OutputDir: %s\n", config.OutputDir)
fmt.Printf(" - Template: %s\n", config.Template)
fmt.Printf(" - StartIndex: %d\n", config.StartIndex)
}
files, err := findFiles(config.Format, config.Recursive)
if err != nil {
fmt.Printf("Error: %s\n", err)
os.Exit(1)
}
if len(files) == 0 {
fmt.Println("No files found.")
return
}
var (
renamedFiles []string
movedFiles []string
)
for i, file := range files {
newName := buildNewName(config.Template, config.StartIndex+i, file)
if config.Move {
outputDir := config.OutputDir
if outputDir == "" {
outputDir = filepath.Dir(file)
}
outputPath := filepath.Join(outputDir, newName)
if !config.DoTry {
err = os.Rename(file, outputPath)
if err != nil {
fmt.Printf("Error: %s\n", err)
os.Exit(1)
}
}
movedFiles = append(movedFiles, file+" -> "+outputPath)
} else {
outputPath := filepath.Join(filepath.Dir(file), newName)
if !config.DoTry {
err = os.Rename(file, outputPath)
if err != nil {
fmt.Printf("Error: %s\n", err)
os.Exit(1)
}
}
renamedFiles = append(renamedFiles, file+" -> "+outputPath)
}
}
fmt.Printf("%d files found.\n", len(files)),
if config.Move {
fmt.Printf("%d files moved:\n", len(movedFiles))
for _, file := range movedFiles {
fmt.Printf(" - %s\n", file)
}
} else {
fmt.Printf("%d files renamed:\n", len(renamedFiles))
for _, file := range renamedFiles {
fmt.Printf(" - %s\n", file)
}
}
},
}
renameCmd.Flags().Bool("debug", false, "Enable debugging information")
renameCmd.Flags().Bool("do-try", false, "Only print out actions that would be performed")
renameCmd.Flags().String("format", "*", "File format to match (e.g. '*.txt')")
renameCmd.Flags().Bool("recursive", false, "Recursively search for files")
renameCmd.Flags().Bool("move", false, "Move files instead of renaming them")
renameCmd.Flags().String("output", "", "Output directory for moved files")
renameCmd.Flags().String("template", "file-$n", "Template for new filename")
renameCmd.Flags().Int("start-num", 1, "Starting number for sequence")
rootCmd.AddCommand(renameCmd)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func findFiles(format string, recursive bool) ([]string, error) {
var files []string
matches, err := filepath.Glob(format)
if err != nil {
return nil, err
}
for _, match := range matches {
info, err := os.Stat(match)
if err != nil {
return nil, err
}
if !info.IsDir() {
files = append(files, match)
} else if recursive {
subFiles, err := findFiles(filepath.Join(match, format), true)
if err != nil {
return nil, err
}
files = append(files, subFiles...)
}
}
return files, nil
}
func buildNewName(template string, index int, file string) string {
ext := filepath.Ext(file)
newName := strings.Replace(template, "$n", strconv.Itoa(index), -1)
newName = strings.Replace(newName, "$e", ext, -1)
if ext != "" && !strings.Contains(newName, "$e") {
newName += ext
}
return newName
}
func parseIntFlag(cmd *cobra.Command, name string) int {
val, _ := cmd.Flags().GetInt(name)
return val
}
|