Skip to content

Commit

Permalink
feature: edit with editor, processor
Browse files Browse the repository at this point in the history
  • Loading branch information
abenz1267 committed Mar 2, 2024
1 parent 6073e6a commit 9ffa785
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 22 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# Bulk-Rename files/folders

Simple cli-tool to bulk rename files. Piped from stdin.
Simple cli-tool to bulk rename files. Piped from stdin, with a processor or simply edit with your editor.

## Install

Arch: `yay -S bmv-bin`

## Usage Example

### From Stdin

```
donttouchme.txt // will be ignored, no destination.
somefile.txt 1.txt // will be moved
Expand All @@ -16,6 +18,18 @@ moveme.txt 1.txt // error, file '1.txt' already exists
idontexist.txt bla.txt // error, file doesn't exist
```

### From Stdin with processor

```
ls | bmv sed 's/.txt$/\.md/'`
```

### From Stdin with editor

```
ls | bmv -e
```

## Tip

You can easily bulk rename files with vim/nvim this way. Simply do f.e. `ls | nvim -` and you'll get a buffer with cwd's content. You can of course also use ":r!ls" inside vim to fill the buffer with the output of the command.
Expand Down
Binary file added bmv
Binary file not shown.
171 changes: 150 additions & 21 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package main
import (
"bufio"
"errors"
"fmt"
"io"
"log"
"os"
"os/exec"
Expand All @@ -11,10 +13,137 @@ import (
)

func main() {
scanner := bufio.NewScanner(os.Stdin)
fi, _ := os.Stdin.Stat()

if (fi.Mode() & os.ModeCharDevice) == 0 {
if len(os.Args) > 1 {
processor := os.Args[1]

if processor == "-e" {
withEditor(getFiles())

return
}

_, err := exec.LookPath(processor)
if err != nil {
panic(err)
}

withProcessor(os.Args[1:])

return
}

fromStdin()
} else {
cmd := exec.Command("ls")
out, err := cmd.CombinedOutput()
if err != nil {
panic(string(out))
}

withEditor(strings.Fields(string(out)))
}
}

func getFiles() []string {
files := []string{}

scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
paths := strings.Fields(scanner.Text())
if scanner.Err() != nil {
log.Panic(scanner.Err())
}

files = append(files, scanner.Text())
}

return files
}

func withEditor(files []string) {
editor, ok := os.LookupEnv("EDITOR")
if !ok {
fmt.Println("env var 'EDITOR' not set.")
os.Exit(1)
}

dest, err := os.CreateTemp("", "*")
if err != nil {
panic(err)
}

_, err = dest.WriteString(strings.Join(files, "\n"))
if err != nil {
panic(err)
}

cmd := exec.Command(editor, dest.Name())
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout

err = cmd.Run()
if err != nil {
panic(err)
}

n, err := os.ReadFile(dest.Name())
if err != nil {
panic(err)
}

toMove := strings.Fields(string(n))

if len(toMove) != len(files) {
panic(fmt.Sprintf("expected %d files, got %d", len(files), len(toMove)))
}

for k, v := range files {
if toMove[k] != v {
move(v, toMove[k])
}
}
}

func withProcessor(args []string) {
files := getFiles()

cmd := exec.Command(args[0], args[1:]...)

pipe, err := cmd.StdinPipe()
if err != nil {
panic(err)
}

go func() {
defer pipe.Close()
io.WriteString(pipe, strings.Join(files, "\n"))
}()

out, err := cmd.CombinedOutput()
if err != nil {
panic(string(out))
}

n := strings.Fields(string(out))

if len(n) != len(files) {
panic(fmt.Sprintf("expected %d files, got %d", len(files), len(n)))
}

for k, v := range files {
move(v, n[k])
}
}

func fromStdin() {
scanner := bufio.NewScanner(os.Stdin)

files := getFiles()

for _, v := range files {
paths := strings.Fields(v)

if len(paths) < 2 {
log.Printf("skipping: %s", scanner.Text())
Expand All @@ -26,29 +155,29 @@ func main() {
continue
}

if _, err := os.Stat(paths[1]); !errors.Is(err, os.ErrNotExist) {
log.Printf("cant move '%s' to '%s', as it already exists.", paths[0], paths[1])
continue
}

destDir := filepath.Dir(paths[1])
move(paths[0], paths[1])
}
}

err := os.MkdirAll(destDir, 0755)
if err != nil {
log.Println(err)
continue
}
func move(src, dest string) {
if _, err := os.Stat(dest); !errors.Is(err, os.ErrNotExist) {
log.Printf("cant move '%s' to '%s', as it already exists.", src, dest)
return
}

cmd := exec.Command("mv", paths[0], paths[1])
out, err := cmd.CombinedOutput()
if err != nil {
log.Println(string(out))
}
destDir := filepath.Dir(dest)

log.Printf("moved '%s' to '%s'", paths[0], paths[1])
err := os.MkdirAll(destDir, 0755)
if err != nil {
log.Println(err)
return
}

if scanner.Err() != nil {
log.Panic(scanner.Err())
cmd := exec.Command("mv", src, dest)
out, err := cmd.CombinedOutput()
if err != nil {
log.Println(string(out))
}

log.Printf("moved '%s' to '%s'", src, dest)
}

0 comments on commit 9ffa785

Please sign in to comment.