问题
I'm trying to sort all mp3 files by artist and name. At the moment, they're in 1 giant file name. E.g Artist - Song name.mp3 I want to convert this to Artist/Song name.mp3
Here's what I've tried so far. In this case, I was using a test file named "hi\ -\ hey":
#!/bin/bash
# filters by all .mp3 extensions in the current working directory
for f in *.mp3; do
# extract artist and song name and remove spaces
artist=${f% -*}
song=${f#*- }
#make directory with the extracted artist name and move + rename the file into the directory
mkdir -p $artist
mv $f $artist/$song;
done
For some reason, it's creating a directory with the song name instead of the artist in addition to a load of errors:
mv: cannot move 'hey.mp3' to a subdirectory of itself, 'hey.mp3/hey.mp3'
mv: cannot stat 'hi': No such file or directory
mv: cannot stat '-': No such file or directory
mv: 'hey.mp3/hi' and 'hey.mp3/hi' are the same file
mv: cannot stat '-': No such file or directory
回答1:
By far the simplest way of doing this is to use rename
a.k.a. Perl rename
.
Basically, you want to replace the sequence SPACE-DASH-SPACE with a forward slash directory separator, so the command is:
rename --dry-run -p 's| - |/|' *mp3
Sample Output
'Artist - Song name.mp3' would be renamed to 'Artist/Song name.mp3'
'Artist B - Song name 2.mp3' would be renamed to 'Artist B/Song name 2.mp3'
If that looks correct, just remove --dry-run
and run it again for real. The benefits of using rename
are:
- it can do a dry-run to test before you run for real
- it will create all necessary directories with the
-p
option - it will not clobber (overwrite) files without warning
- you have the full power of Perl available to you and can make your renaming as sophisticated as you wish.
Note that you can install on macOS with homebrew:
brew install rename
回答2:
Assuming there are many files, it's probably much faster to do this using pipes instead of a for loop. This has the additional advantage of avoiding complicated bash
-specific syntax and using core unix/linux command line programs instead.
find *-*.mp3 |
sed 's,\([^-]\+\)\s*-\s*\(.*\),mkdir -p "\1"; mv "&" "\1"/"\2",' |
bash
Explanation:
This find
to find all the files matching -.mp3 in the current directory.
This sed
command changes each line to a command string, e.g.:
aaa - bbb.mp3
->
mkdir -p "aaa"; mv "aaa - bbb.mp3" "aaa"/"bbb.mp3"
The bash
command runs each of those command strings.
回答3:
you can try this.
#!/usr/local/bin/bash
for f in *.mp3
do
artist=`echo $f | awk '{print $1}' FS=-`
song=`echo $f | awk '{print $2}' FS=-`
mkdir -p $artist
mv $artist-$song $song
mv $song ./$artist
done
here I am using two variable artist and song. as your test file name is "hi\ -\ hey" so I change the awk delimiter to "-" to store variable according to it.
we don't need to use awk..by using bash parameter expansion.... it is working.
#!/usr/local/bin/bash
for f in *.mp3
do
artist=`echo ${f%-*}`
song=`echo ${f#*-}`
mkdir -p $artist
mv $artist-$song $song
mv $song ./$artist
done
来源:https://stackoverflow.com/questions/58372435/how-do-i-extract-a-file-name-into-2-parts-making-one-into-directory-and-the-oth