0

I got a bunch of mp3 files with random names and numbers like:

  • 01_fileabc.mp3
  • 01.filecdc.mp3
  • fileabc.mp3
  • 929-audio.mp3

For sorting purposes, I need to add a sequential number in front of the file name like:

  • 001_01_fileabc.mp3
  • 002_01.filecdc.mp3
  • 003_fileabc.mp3
  • 004_929-audio.mp3

I checked some of the solutions I found here. One of the first solutions worked kind of but replaced the filename instead of adding to it.

num=0; for i in *; do mv "$i" "$(printf '%04d' $num).${i#*.}"; ((num++)); done

How can I modify this command to add to the filename instead? I am sorry, but whatever I try I can't find a solution myself here.

Severus15
  • 127
  • 9

3 Answers3

2

Just replace ${i#*.} (which stands for "Remove from $i from the left up to the first dot) with $i, which is the original name of the file (I'd probably use $filename, $oldfile, or at least $f instead of $i as the variable's name).

You can also replace the . before it with _, otherwise the files will be named

0001.01_fileabc.mp3

etc.

choroba
  • 231,213
  • 25
  • 204
  • 289
  • ...and replace the glob `*` with `*.mp3` to rename only the files with a `.mp3` file extension. Complete revised command as follows: `num=1; for filename in *.mp3; do mv "$filename" "$(printf '%04d' $num)_$filename"; ((num++)); done` – RobC Nov 05 '18 at 14:02
1

UPDATE: As RobC commented about this answer, existing whitespace or newline characters can cause problems listing files because of using ls command with bash arrays. So the above code can be improved in this way

#!/bin/bash
i=0
for file in *.mp3; do
    i=$((i+1))
    mv "$file" "$(printf "%03d_%s" "$i" "$file")"
done

ORIGINAL ANSWER: You can try this code in a bash script. Remember to make it executable with $ chmod +x script.sh.

#!/bin/bash
contents_dir=($(ls *.mp3))
for file in ${!contents_dir[*]}; do
    new=$(awk -v i="$file" -v cd="${contents_dir[$file]}" 'BEGIN {printf("%03d_%s", i+1, cd)}')
mv ${contents_dir[$file]} $new
done

It will add a consecutive 0-leaded tree digits number as you wanted to all mp3 files found in the dir where the script is executed.

miimote
  • 373
  • 2
  • 12
  • Thank you. That worked perfectly. I really need to find a place on how to learn bash. – Severus15 Nov 05 '18 at 10:17
  • 2
    Whilst this solution works given the filenames in the OP, it will fail if a filename contains a space or newline character. Further info regarding _"Why you shouldn't parse the output of ls"_ can be found [here](https://mywiki.wooledge.org/ParsingLs). – RobC Nov 05 '18 at 13:20
0

You could try this …

$ ls -l
total 4
-rw-r--r-- 1 plankton None 5 Nov  4 13:35 01.filecdc.mp3
-rw-r--r-- 1 plankton None 5 Nov  4 13:35 01_fileabc.mp3
-rw-r--r-- 1 plankton None 5 Nov  4 13:35 929-audio.mp3
-rw-r--r-- 1 plankton None 5 Nov  4 13:35 fileabc.mp3

$ t=0
$ for i in *mp3
> do
>     # Use the seq command to get a formatted zero filled string.
>     prefix=$(seq -f "%04g" $t $t)
>
>     # Move $i to new file name.
>     mv $i ${prefix}_${i}
>
>     # Increment our counter, t.
>     t=$(expr $t + 1)
> done


$ ls -l
total 4
-rw-r--r-- 1 plankton None 5 Nov  4 13:35 0000_01.filecdc.mp3
-rw-r--r-- 1 plankton None 5 Nov  4 13:35 0001_01_fileabc.mp3
-rw-r--r-- 1 plankton None 5 Nov  4 13:35 0002_929-audio.mp3
-rw-r--r-- 1 plankton None 5 Nov  4 13:35 0003_fileabc.mp3
Red Cricket
  • 9,762
  • 21
  • 81
  • 166