bash mass rename files in folders and subfolders with sequential number

孤街浪徒 提交于 2019-12-24 00:37:45

问题


I need a bash script which does the following: for every file of a certain type present in a folder and in its sub folders it prepends a sequential number (4 digits) followed by a separator (-)

So for example I have:

  /Queen/(1986) A Kind of Magic/01.One vision.mp3
  /Queen/(1986) A Kind of Magic/02.A kind of magic.mp3
  /Queen/(1986) A Kind of Magic/cover.jpg
  /Queen/(1991) Innuendo/01.Innuendo.mp3
  /Queen/(1991) Innuendo/02.Headlong.mp3
  /Queen/(1991) Innuendo/cover.jpg
  /Queen/(1991) Innuendo/booklet.pdf

I want that at the of the script the following:

  /Queen/(1986) A Kind of Magic/0001-01.One vision.mp3
  /Queen/(1986) A Kind of Magic/0002-02.A kind of magic.mp3
  /Queen/(1986) A Kind of Magic/cover.jpg
  /Queen/(1991) Innuendo/0003-01.Innuendo.mp3
  /Queen/(1991) Innuendo/0004-02.Headlong.mp3
  /Queen/(1991) Innuendo/cover.jpg
  /Queen/(1991) Innuendo/booklet.pdf

Please note I have spaces in the filenames and parenthesis in the folder names! How can I do that? I tried with mac automator but no success! :(

Thank you


回答1:


Create the following bash script and execute it at the base directory of your music collection. It will work with file and directory names containing spaces, parentheses, single and double quotes, other weird characters, but not with names containing newlines or really weird characters. You can customize it giving a different value for start_dir, or changing the format specification %s/%04u-%s, which presently contains %s (the directory name) %04u (the numbering index, formatted as a zero-padded four-digit integer), and %s (the file name), separated by / and -.

#!/bin/bash
start_dir="."
find "$start_dir" -name '*.mp3' -type f \
  |sort \
  |while read name; do 
     ((i++))
     mv -i "$name" \
       "$(printf '%s/%04u-%s' "$(dirname "$name")" $((i)) "$(basename "$name")")"
   done

Remarks:

Socowi’s answer is very similar to mine. The differences are (1) He requires bash 4.0, which is not installed on Macs by default. I don’t. (2) His script will work with filenames containing newlines (a very rare occasion). Mine won’t. (3) His script will fail if the total length of the names of all your mp3 files (including subdirectories) is more than 262144 bytes; I’d say this would happen if you have more than approximately 6000 files. Mine will work with any number of files.

(Note for mapfile-loving bash practitioners: I know that using mapfile might be a smart way to generate the indexes without explicitly creating $i, but (i) there is no need for the huge array mapfile would create and (ii) I would need a variable anyway when parsing the command line passed to the mv callback.)




回答2:


The following script prefixes all mp3 files under the current directory with a four digit number and should work for absolutely every possible file name.

#! /bin/bash
shopt -s globstar nullglob
n=0
for f in **/*.mp3; do
        (( ++n ))
        b="$(basename "$f")"
        mv -i "$f" "${f%"$b"}/$(printf '%04d' "$n")-$b"
done

The globstar ** requires bash > 4.0 which is not pre-installed on macs as far as I know (check with bash --version). But I heard there are ways to install newer bash versions.

The order in which the files are numbered depends on your locale settings. Bash expands **/* in a sorted way according to LC_COLLATE. At least with LC_COLLATE=en_US.UTF-8 files are numbered in the alphabetical order and we don't have to worry about name collisions – the order gurantees that no overwrites occur.



来源:https://stackoverflow.com/questions/42607819/bash-mass-rename-files-in-folders-and-subfolders-with-sequential-number

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!