What I am doing is converting mp3’s with LAME. I already have an old script I wrote that works but I want to add to it this ability–to no longer delete the file but instead save it in a new root folder with sub-directories that match the using the path that it is already in.
This is the code I got off the Internet that I am using in my script to get the path:
c=$FILENAME
xpath=${c%/*}
xbase=${c##*/}
xfext=${xbase##*.}
xpref=${xbase%.*}
path=${xpath}
pref=${xpref}
ext=${xfext}
The xpath and path give me the directory structure /home/user/working-root-directory/band-folder/album-name/
Using that technique, how do I script this to get just the band-folder into a separate variable and the album-folder into a separate variable?
Then I can use them to create new folders keeping all the mp3s in band album order to put them into a different root folder; this would eliminate me from having to move them myself so the next time I run my script I will not re-sample them again because they will no longer be in the working directoy path/folders and still have a back up copy of my files just in case.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
When referring to $c if by filename you mean full-path to file then this job is really very easy. There are a few ways to do it.
Using just POSIX shell globs and parameter expansion you can do:
c='/home/user/working-root-directory/band-folder/album-name/music-file.mp3'
file=${c##*/}
album=${c#*"${c%/*/"$file"}"/}
band=${c#*"${c%/*/"$album"}"/}
band=${band%%/*} album=${album%%/*}
Basically it works by trimming a string from the tail of the variable and then trimming the results from the head of the variable. In the last line any unwanted remains from the tail are stripped away. It is perhaps easier to understand with real-world data. If you were to wrap the above snippet in a shell with set -x enabled, you’d see something along these lines printed to stderr:
+ c=/home/user/working-root-directory/band-folder/album-name/music-file.mp3 + file=music-file.mp3 + album=album-name/music-file.mp3 + band=band-folder/album-name/music-file.mp3 + band=band-folder + album=album-name
Another way you might do this is to use the shell’s internal field separator to split the pathname on / boundaries.
set -f; IFS=/ #disable globbing so as not to gen more filenames set -- $c #set the shell's arg array to split path shift "$(($#-3))" #remove all but relevant fields band=$1 album=$2 file=$3 #assign values
Here is some more set -x output:
+ c=/home/user/working-root-directory/band-folder/album-name/music-file.mp3 + set -f + IFS=/ + set -- '' home user working-root-directory band-folder album-name music-file.mp3 + shift 4 + band=band-folder + album=album-name + file=music-file.mp3
Method 2
I would hire zsh for this job:
$ c='/home/user/working-root-directory/band-folder/album-name/filename.mp3' $ echo $c:h /home/user/working-root-directory/band-folder/album-name $ echo $c:h:h /home/user/working-root-directory/band-folder $ echo $c:h:h:h /home/user/working-root-directory (...) $ echo $c:t filename.mp3 $ echo $c:h:t album-name $ echo $c:h:h:t band-folder (...)
If you have to use bash life is harder, you need to use temporary variables:
$ c='/home/user/working-root-directory/band-folder/album-name/filename.mp3'
$ x1=${c%/*}
$ echo $x1
/home/user/working-root-directory/band-folder/album-name
$ x2=${x1%/*}
$ echo $x2
/home/user/working-root-directory/band-folder
(...)
$ y1=${c##*/}
$ echo $y1
filename.mp3
$ y2=${x1##*/}
$ echo $y2
album-name
$ y3=${x2##*/}
$ echo $y3
band-folder
(...)
Method 3
The previous solutions seem overly complicated to me. The following seems to me to be the simpliest solution.
To get the directory name of a filename strings in bash
dirname "$varcontainingfilename"
To get the ONLY the filename from a filename string in bash use
basename "$varcontainingfilename"
From this base you should be able to easily do what you want.
Example executing this shell script as script /a/b/c would serve as an example
#!/bin/sh set -u PATH='/bin:/usr/bin' export PATH filestring="$1" fn=`basename "$filestring"` dn=`dirname "$filestring"` echo Original File String "$filestring" echo Filename is "$fn" echo directory is "$dn" exit 0
Method 4
To make “playing” with variables a little shorter
c=/home/user/working-root-directory/band-folder/album-name/music-file.mp3
for var in file album band
do
eval "$var=${c##*/}"
c=${c%/${!var}}
done
echo $file $album $band
music-file.mp3 album-name band-folder
Other way is to use read command
IFS=/ read -r band album file <<< ${c#"${c%/*/*/*}"/}
Method 5
Zsh is a much more elegant solution, but if it is not your shell, you can useawk:
printf "%sn" "$path"
/home/user/working-root-directory/band-folder/album-name/music-file.mp3
band=$(awk -F/ '{print $(NF-2)}' <(printf "%s" "$path"))
printf "%sn" "$band"
band-folder
album=$(awk -F/ '{print $(NF-1)}' <(printf "%s" "$path"))
printf "%sn" "$album"
album-name
file=$(awk -F/ '{print $NF}' <(printf "%s" "$path"))
printf "%sn" "$file"
music-file.mp3
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0