1

My idea is to make a script which gives all subdirectories (in my case ˜/MUSIC but on the mac of my wife is it different –> artist/album). In a later fase I would like convert all .wav extensions to mp4 (if not already exist).

But I have already troubles to get the output of the command in to a string array

#!/bin/bash

extFROM=”.wav”;
extTO=”.mp4”;

dir="˜/music";

tree -d

cnt=1;

array;

echo "  part 1";
find $dir -type d | while read line
#ls -d -1 | while read line
do
   array[ $cnt ] = "$line";
   echo "${cnt} "; # :  ${array[ $cnt ] ";
   let cnt++;
done


echo " part 2";
array=`awk '{print $1}' <find $dir -type d`
for i in array;
do
   echo "${i} ";
done

My apologizes for the delay for my late reaction. Part 1 and part 2 are having the same goal.


Thanks @Peter Cordes for the information about to use 'while' instead 'for-loop' reading lines; http://mywiki.wooledge.org/BashFAQ/001 and http://mywiki.wooledge.org/DontReadLinesWithFor And of course for your other reactions, it is great so many usefull input.

@Matthew Bohnsack … nice and easy piece of script, instead of my idea.

@Saul Ortega, this is my output : (of course the tree)

./test.sh: line 15: array: command not found
part 1
find: ˜/music: No such file or directory
part 2
./test.sh: line 28: find: No such file or directory
array 

So it has something to do with my script, the directory exist.

1
  • What do you get as output with what you have there?
    – VaTo
    Aug 18, 2015 at 16:56

4 Answers 4

3

See http://mywiki.wooledge.org/BashFAQ/001 and http://mywiki.wooledge.org/DontReadLinesWithFor for how to read lines that potentially contain spaces and other special characters.

There is a ton wrong with how you're handling text in your script. It's subject to word-splitting in a lot of cases that you don't want. See the Wooledge FAQ for more details on that.

Audio files often have names with spaces in them, so this will be an issue for you.

One way to do this would be to use Bash's extglob feature to avoid having to parse find output. (find -exec ... {} + would be another way).

shopt -s extglob
for wav in **/*.wav; do
    mp4="${wav%.wav}.mp4"  # strip off the .wav suffix, tack on .mp4
    if ! [[ -e "$mp4" ]]; then
        ffmpeg -i "$wav" -c:a libfdk_aac -b:a 96k "$mp4"
    fi
done

Note that ffmpeg's other AAC encoders still aren't as good as libfdk.

0

A "find" version of Peter's answer to not get subdirs but to actually do all the conversions looks like this:

convert_if_no_mp4 () {
    wav_file=${1}
    mp4_file="${wav_file%.wav}.mp4"

    if [[ ! -e ${mp4_file} ]]; then
        ffmpeg -i "$wav_file" -c:a libfdk_aac -b:a 96k "$mp4_file"
    fi
}
export -f convert_if_no_mp4
dir=~/MUSIC
find ${dir} -type f -name "*.wav" -exec bash -c 'convert_if_no_mp4 "{}"' \;

I suspect that this is what you're actually after (actually doing the conversion), but if you really want to operate on all subdirs for some reason, you can start with something like this:

do_stuff_with_subdir () {
    echo "doing something with \"${1}\""
}
export -f do_stuff_with_subdir
dir=~/MUSIC
find ${dir} -type d -exec bash -c 'do_stuff_with_subdir "{}"' \;
1
  • … nice and easy piece of script, instead of my idea.
    – kris
    Aug 29, 2015 at 11:46
0

for putting the whole output of a command into a BASH array, simply do this:

 array=( $( command ) )

Spare the whole while read part. Be careful with special characters in names though.

7
  • That's not going to work if the output of command contains spaces, not just newlines. Use a IFS= read loop, or Bash4 readarray. Aug 18, 2015 at 17:13
  • as I said - careful with special chars
    – FelixJN
    Aug 18, 2015 at 17:13
  • You can save/restore $IFS around an IFS=; array=( $(cmd) ), like bash-completion does for getting compgen output into the COMPREPLY array. There's literally no way to do this fully safely, though. It's messy enough that you might as well just do IFS= read. Aug 18, 2015 at 17:20
  • Well, I agree. The saver the better. And playing around with the stdout of find to get it working (if even possible) does not make it shorter in the end, either.
    – FelixJN
    Aug 18, 2015 at 17:25
  • Using find, I'd just use find -exec bash 'for i; do cmd "$i";done' placeholder {} + instead of parsing find's output. Then you can even handle filenames that include a newline. Aug 18, 2015 at 17:26
0

Check following code for your 1st part:

#!/bin/bash   
extFROM=”.wav”  
extTO=”.mp4”  
dir="˜/music"  
tree -d  
cnt=1  
array  
echo "  part 1"  

find $dir -type d | while read line  
do  
   array[ $cnt ]="$line"  
   echo ""${cnt}" :  ${array[ $cnt ]}"  
   let cnt++;  
done

For second part, can you please give some more information like what you want to do after getting all subdirectories.

1
  • A more normal way to quote would be dir=~/'music', then find "$dir". Your current version will break if you change it to dir="~/music library". Also, you can append to an array with array+=( "$line" ). Or simply process each directory inside the loop body, instead of building the array first. Aug 18, 2015 at 18:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .