ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I am trying to work out how to get all of the information off one just one pass of exiftool, instead of having to call exiftool for each 'field' of information I need.
like this:
I want to only make one pass on the file then extract all of the needed information and place it into its own variable to later use.
the problem is strings that contain spaces are counted as separate fields.
exiftool displays the range of information contained on a mp3 file, extracting only '/Title/ || /Artist/ || /Track/ || /Album/ || /Genre/ the out put can be something like this:
Code:
userx@slackOlatern:~/Music$ exiftool Areosmith-Last-Child.mp3 | awk '/Title/ || /Artist/ || /Track/ || /Album/ || /Genre/'
Title : Last child
Artist : Aerosmith
Track : 14
Album : Classics live complete
Genre : Live
needing only what is on the right of the : (colon) there are spaces within the string for each which constitutes another field. I need to get each pattern, title, artist,track,album,genre etc into a separate variable for later use. Just the value and not anything else, being what is on the right side of the : (colon)
so for example Album value is 'Classics live complete' where that is 3 separate fields within one string. The string value is of course unknown, so the amount of fields needed for each separate string is an issue.
Code:
#!/bin/bash
working_dir=/home/userx/Music
script_dir=""$HOME"/scripts"
while read f ;
do
#put into an array
fields=($(exiftool "$f" | awk '/Title/ || /Artist/ || /Track/ || /Album/ || /Genre/ {print $3,$4,$5,$6}'))
echo $fields
echo ${fields[@]}
echo ${#fields[@]}
echo
for i in ${!fields[@]}
do
echo ${fields[$i]}
done
done <<<$(find "$working_dir" -type f -iname "*.mp3")
gives me this output
Code:
$ ./awkMP3
Last
Last child Aerosmith 14 Classics live complete Live
8
Last
child
Aerosmith
14
Classics
live
complete
Live
where giving the actual strings should be
Code:
Last child
Aerosmith
14
Classics live complete
Live
in respective variables
Code:
title="Last child"
artist="Aerosmith"
track="14"
album="Classics live complete"
genre="Live"
is the desired results,
I do not know what program to use, awk at the moment, to extract the output then place it into separate variables for later use.
Not tested but why don't you use a special field separator in awk (other than space) and distinguish values in your array accordingly?
For example, you could use awk OFS="|" and set IFS accoringly for your fields array. Of course, you need to choose something else than "|" if your fields can contain this character, so maybe you could take something exotic...
Not tested but why don't you use a special field separator in awk (other than space) and distinguish values in your array accordingly?
For example, you could use awk OFS="|" and set IFS accoringly for your fields array. Of course, you need to choose something else than "|" if your fields can contain this character, so maybe you could take something exotic...
awk is not my strong point, don't use it much, if ever. you wouldn't happen to know a good web page to use the ones I've looked at are too basic. or not the right search string to find what I am looking to do. I'll look up the OFS and IFS ..
I tried that print $2 without the -F ':' and haha all I needed was that -F part basically. that just does what I did in a different manner, I see and understand what you did, but it is then getting that into a separate variable for each complete string spaces and words together.
awk is not my strong point, don't use it much, if ever. you wouldn't happen to know a good web page to use the ones I've looked at are too basic. or not the right search string to find what I am looking to do. I'll look up the OFS and IFS ..
OK it is now howto get them shoved into separate variables?
@lougavulin , this gives me
Code:
exiftool "$f" | awk -F ':' '/Title/ || /Artist/ || /Track/ || /Album/ || /Genre/ {print $2}'
Last child
Aerosmith
14
Classics live complete
Live
@pan64 , this gives me
Code:
exiftool "$f" | awk -F ':' '/Title/ { f1=$2 } /Artist/ {f2=$2 } /Track/ {f3=$2} /Album/ {f4=$2} /Genre/ {f5=$2};
END {print f1 f2 f3 f4 f5}'
Last child Aerosmith 14 Classics live complete Live
putting it into an array and I am back to where I started,
Code:
fields=($(exiftool "$f" | awk -F ':' '/Title/ { f1=$2 } /Artist/ {f2=$2 } /Track/ {f3=$2} /Album/ {f4=$2} /Genre/ {f5=$2};
END {print f1 f2 f3 f4 f5}'))
for i in ${!fields[@]}
do
echo ${fields[$i]}
done
Last
child
Aerosmith
14
Classics
live
so for each var or element if array is used
Code:
for i in ??
do
field[$i]=??
done
I need to contain the string that has spaces within it as a whole , getting the information I got, as posted, it is the next step that I need, the getting it into another , separate variables is the issue.
#array1[0]=Title, array1[1]=Artist and so on.
line=$(exiftool -p '$Title' -p '$Artist' file.mp3)
echo "$line"
readarray -t array1 <<< "$line"
echo "${array1[0]}"
For < bash 4 you can split a string into an array based on newline character too
Code:
IFS=$'\n' read -rd '' -a array1 <<<"$line"
I'll give that a look see but what I am trying to mimic is this'
Code:
# when assigning in the array a string with spaces as awk output has some strings with spaces, therefore
#it is seen as a separate filed so it gets another $1 $2 etc... seperating the string prior to adding
# it to the array when it needs to be kept together as one string what has spaces in it like this
go=("hello world" "go")
for i in ${!go[@]}
do
echo ${go[$i]}
done
hello world
go
having to be called for each type artist, title etc. where as exiftool gives everything on one pass, get that off the one pass , therefore eliminating having to keep calling exiftool for each one I need. for every one file it has to call exiftool 4 to 7 times depending on information needed before moving on to the next step in the process.
At least with my version of exiftool -p '$Title' -p '$Artist' file.mp3 will put each extracted value on a new line and assigning it to a variable will be just one string including new lines. Your splitting the string on a new line character which should preserve spaces.
I am doing the same thing but as one command which is one pass as requested. I just didn't expand it.
I didn't know readarray provided by michaelk, I should play with it.
But I would do something like this :
Code:
# Associative array
declare -A ARRAY
exiftool "$f" | awk -F ':' '/Title/ || /Artist/ || /Track/ || /Album/ || /Genre/ {gsub(/ *$/, "", $1); print $1 $2}' | while read META VALUE
do
ARRAY[${META}]=${VALUE}
echo "${META} = ${ARRAY[${META}]}"
done
that looks like where my brain was starting to lean towards, so I can hopefully get $2 that in some are strings with spaces in them into the element as one element. let me work this on out and see what i get.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.