Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

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.

share|improve this question
    
What do you get as output with what you have there? –  Saul Ortega Aug 18 at 16:56

4 Answers 4

up vote 0 down vote accepted

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 "{}"' \;
share|improve this answer
    
… nice and easy piece of script, instead of my idea. –  kris Aug 29 at 11:46

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.

share|improve this answer

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.

share|improve this answer
    
That's not going to work if the output of command contains spaces, not just newlines. Use a IFS= read loop, or Bash4 readarray. –  Peter Cordes Aug 18 at 17:13
    
as I said - careful with special chars –  Fiximan Aug 18 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. –  Peter Cordes Aug 18 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. –  Fiximan Aug 18 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. –  Peter Cordes Aug 18 at 17:26

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.

share|improve this answer
    
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. –  Peter Cordes Aug 18 at 18:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.