LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   nested while loop keep looping when finished (https://www.linuxquestions.org/questions/programming-9/nested-while-loop-keep-looping-when-finished-4175607415/)

BW-userx 06-06-2017 02:43 PM

nested while loop keep looping when finished
 
I have a nested while loop (2). so this will go through a parent dir and get the children dirs one at a time then (basically) moving files somewhere else then when finished moving the files, delete prior dir and sub-dir without removing the parent dir before moving on to the next child dir and doing the same. But it just keeps looping until it gets tired then moves on to the next one.

it is at "big" script. do not let that confuse you. as stated it is after processing the files it is just moving them somewhere else then deleting the prior dir structure, leaving the parent.

quick break down: it reads from one dir, process files, copies file to one dir then moves the original file to another dir to have a back up copy. then deletes the dirs they use to be in. then it just keeps looping until "it gets tried or dizzy" before moving on.

script
Code:

#!/bin/bash
#Jun 06, 2017
#all in one

count=0 max=0

working_dir=/media/data/TESTING-MUSIC
move_old_flac=/run/media/userx/3TB-External/OldFlac
move_to=/media/data/MOVED-TESTING-MUSIC
copy_to=/run/media/userx/3TB-External/Copied-Music
final_move=/media/data/Final-move
script_dir=/home/userx/scripts/production

max="$(find "$working_dir" -type f \( -name "*.mp3" -o -name "*.MP3" -o -name "*.flac" \) | wc -l)"

while read FILENAME
do
f=$FILENAME
path=${f%/*}
xfile=${f##*/}
title=${xfile%.*}
ext=${xfile##*.}


while read FILENAME
do
f=$FILENAME
path=${f%/*}
xfile=${f##*/}
title=${xfile%.*}
ext=${xfile##*.}

ARTIST="`exiftool -Artist "$FILENAME" -p '$Artist'`"
TITLE="`exiftool  -Title  "$FILENAME" -p '$Title'`"
ALBUM="`exiftool  -Album  "$FILENAME" -p '$Album'`"
GENRE="`exiftool  -Genre  "$FILENAME" -p '$Genre'`"
TRACK="`exiftool -Track "$FILENAME" -p '$Track'`"

NewFile="$ARTIST-$TITLE.mp3"

#first move to different dir
Moving=${path/$working_dir/$move_to}

mkdir -pv "$Moving"


if [[ "$ext" = 'mp3' ]] ; then
mv -v "$FILENAME" "$Moving/$NewFile"
else
mv -v "$FILENAME" "$Moving"
fi

#to Retag new MP3
retagdir="$script_dir/$NewFile"

if [[ "$ext" == 'flac' ]] ; then
{ #reestablish path to flac and name after move
FLACNAME="$Moving/$title.$ext"

flac -cd "$FLACNAME" | lame -b 320 - "$NewFile"
id3v2 -A "$ALBUM" "$retagdir"
id3v2 -a "$ARTIST" "$retagdir"
id3v2 -t "$TITLE" "$retagdir"
id3v2 -g "$GENRE" "$retagdir"
id3v2 -T "$TRACK" "$retagdir"

#put new mp3 back
path=${FLACNAME%/*}
mv -v "$retagdir" "$path"
OldFlac2Dir=${path/$move_to/$move_old_flac}
mkdir -p "$OldFlac2Dir"
mv -v "$FLACNAME" "$OldFlac2Dir"
}
fi

FILENAME1="$Moving/$NewFile"

  if [[ "$ext" = 'mp3' ]] ; then
  {
    echo "id3v2 start"
    #writes name to mp3 tag info
   
    id3v2 -D "$FILENAME1"
    id3v2 -a "$ARTIST" "$FILENAME1"
    id3v2 -A "$ALBUM" "$FILENAME1"
    id3v2 -t "$TITLE" "$FILENAME1"
    id3v2 -g "$GENRE" "$FILENAME1"
    id3v2 -T "$TRACK" "$FILENAME1"
    echo "id3v2 stop"
  }
  fi
 
 
  if [[ "$ARTIST" && ! -n "$ALBUM" ]] ; then
    {
      Catagory="$final_move/$ARTIST"
      coping="$copy_to/$ARTIST"
      mkdir -pv "$Catagory"
      mkdir -pv "$coping"
      cp -v "$FILENAME1" "$coping"
      mv -v "$FILENAME1" "$Catagory"
    }
    else
    {
      Catagory="$final_move/$ARTIST/$ALBUM"
      coping="$copy_to/$ARTIST/$ALBUM"
      mkdir -pv "$Catagory"
      mkdir -pv "$coping"
      cp -v "$FILENAME1" "$coping"
      mv -v "$FILENAME1" "$Catagory"
    }
  fi
   


echo "
                        MAX    is $max
                        Done  is $((++count))
                                --------
                        Left          $((max - count))
                       
               
                "
        [[ $max = $count ]] && break
       
done< <(find "$path" -type f \( -name "*.mp3" -o -name "*.MP3" -o -name "*.flac" \))

echo;echo
echo "outside Loop1"
echo "path: $path"
echo

#outside Loop1
#path: /media/data/MOVED-TESTING-MUSIC/America/[2004] America - Horse with No Name and Other Hits, A


#gets the parent and plus one dir down.
#should be a better way but brains is not functioning at 100% at this time.

delete1=${path#*/*/*/*/}
delete1=${delete1%%/*}
delete1="$move_to/$delete1"

delete2=${path/$move_to/$working_dir}
delete2=${delete2#*/*/*/*/}
delete2=${delete2%%/*}
delete2="$working_dir/$delete2"

 
[[ -d "$delete1" ]] && ( rm -rv "$delete1" ; exit)
[[ -d "$delete2" ]] && ( rm -rv "$delete2" ; exit)

 
                               
done< <(find "$working_dir" -type f \( -name "*.mp3" -o -name "*.MP3" -o -name "*.flac" \))

echo "outside loop"

feedback off of CLI
Code:



'/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS/07_i_cant_give_everything_away.mp3' -> '/media/data/MOVED-TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David
_Bowie_-_Blackstar-2016-DDS/David Bowie-I Can'\''t Give Everything Away.mp3'
id3v2 start
Stripping id3 tag in "/media/data/MOVED-TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS/David Bowie-I Can't Give Everything Away.mp3"...id3v1 and v2 stripped.
id3v2 stop
'/media/data/MOVED-TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS/David Bowie-I Can'\''t Give Everything Away.mp3' -> "/run/media/userx/3TB-External/Copied-Music/David Bowie/Blacksta
r/David Bowie-I Can't Give Everything Away.mp3"
'/media/data/MOVED-TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS/David Bowie-I Can'\''t Give Everything Away.mp3' -> "/media/data/Final-move/David Bowie/Blackstar/David Bowie-I Can'
t Give Everything Away.mp3"

                        MAX    is 10
                        Done  is 10
                                --------
                        Left      0





outside Loop1
path: /media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS

removed directory '/media/data/MOVED-TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS'
removed directory '/media/data/MOVED-TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar'
removed directory '/media/data/MOVED-TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP'
removed '/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS/00_david_bowie_-_blackstar-2016-proof.jpg'
removed '/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS/00_david_bowie_-_blackstar-2016.m3u'
removed '/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS/00_david_bowie_-_blackstar-2016.nfo'
removed '/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS/00_david_bowie_-_blackstar-2016.sfv'
removed directory '/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS'
removed directory '/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar'
removed '/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/★.jpg'
removed directory '/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP'

find: ‘/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS’: No such file or directory


outside Loop1
path: /media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS

find: ‘/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS’: No such file or directory


outside Loop1
path: /media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS

find: ‘/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS’: No such file or directory


outside Loop1
path: /media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS

find: ‘/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS’: No such file or directory


outside Loop1
path: /media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS

find: ‘/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS’: No such file or directory


outside Loop1
path: /media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS

find: ‘/media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS’: No such file or directory


outside Loop1
path: /media/data/TESTING-MUSIC/David Bowie Blackstar [2016] CDRIP/blackstar/David_Bowie_-_Blackstar-2016-DDS

outside loop
userx%voider ⚡ production ⚡>

I've tried the break, and exit as seen in the script but as you can see it just keeps looking.
Code:


[[ -d "$delete1" ]] && ( rm -rv "$delete1" ; break)
[[ -d "$delete2" ]] && ( rm -rv "$delete2" ; break)

dir will be there on 1st check, so delete it, then break out of loop, move on, but it just keeps going ..

How do I get that to stop after it deletes the dir just have it move on to the next.

serafean 06-07-2017 03:12 AM

Hi,

First off, I only quickly glimpsed at your script, and this is what stood out...
your issue is that parenthesis create a subshell, meaning that your "break" statement gets executed in a completely different shell (same issue with exit, it exits a completely different process than you think). I think that replacing the parenthesis around the break with curly braces will fix your issue.
In any case, the following works :
Code:

i=0
while true;do
    [[ $i -eq 4 ]] && (echo "not breaking"; exit )
    [[ $i -eq 5 ]] && { echo "breaking"; break; }
    i=$((i+1))
    echo "$i"
done


BW-userx 06-07-2017 07:39 AM

Quote:

Originally Posted by serafean (Post 5719989)
Hi,

First off, I only quickly glimpsed at your script, and this is what stood out...
your issue is that parenthesis create a subshell, meaning that your "break" statement gets executed in a completely different shell (same issue with exit, it exits a completely different process than you think). I think that replacing the parenthesis around the break with curly braces will fix your issue.
In any case, the following works :
Code:

i=0
while true;do
    [[ $i -eq 4 ]] && (echo "not breaking"; exit )
    [[ $i -eq 5 ]] && { echo "breaking"; break; }
    i=$((i+1))
    echo "$i"
done


from what I read that { } curly brackets are the one that creates another sub shell and these do not ( )

It should not even need a break in that loop, I've changed it to a basic if statement and am getting the same results. Next to try is the mindepth and maxdepth trial.

because this is making no since to me. When find is done with one directory it is suppose to move on to the next one. Not keep looking inside of it, especially when it is not there.

I could just run it and not worry about it, because it works in what it is suppose to be doing. Tough it is slightly bugging me as to why it is not doing what I expect it to when finished and dir is deleted.

BW-userx 06-07-2017 08:34 AM

moved code to outside of both loops so it will just delete everything within the dir when finished completely running. Instead of one at a time.
Code:

done< <(find "$path" -type f \( -name "*.mp3" -o -name "*.MP3" -o -name "*.flac" \))
done< <(find "$working_dir" -type f \( -name "*.mp3" -o -name "*.MP3" -o -name "*.flac" \))

rm -rv "$move_to"/*
rm -rv "$working_dir"/*

I still don't like it though.

pan64 06-07-2017 08:45 AM

Quote:

Originally Posted by BW-userx (Post 5720068)
from what I read that { } curly brackets are the one that creates another sub shell and these do not ( )

I do not know where did you read that. The truth is: () makes subshell, {} just a scope - or something like that.
see man bash:
Code:

      (list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below).
      { list; } list is simply executed in the current shell environment.

Exception: if ( ) is inside an expression and used for grouping.
Quote:

Originally Posted by BW-userx (Post 5720068)
It should not even need a break in that loop, I've changed it to a basic if statement and am getting the same results.

I have no idea what did you really try and what is the result. You gave no enough information.


Quote:

Originally Posted by BW-userx (Post 5720068)
I could just run it and not worry about it, because it works in what it is suppose to be doing. Tough it is slightly bugging me as to why it is not doing what I expect it to when finished and dir is deleted.

because what you suppose is not how it really works. Remember, a program will never do what you wish, but what was implemented.

you posted incomplete scripts, hard to say anything about that, but: you may use -iname in find, probably a bit better.

BW-userx 06-07-2017 08:59 AM

Quote:

Originally Posted by pan64 (Post 5720094)
I do not know where did you read that. The truth is: () makes subshell, {} just a scope - or something like that.
see man bash:
Code:

      (list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below).
      { list; } list is simply executed in the current shell environment.

Exception: if ( ) is inside an expression and used for grouping.

yeah I might have gotten that backwards.

Quote:


I have no idea what did you really try and what is the result. You gave no enough information.

because what you suppose is not how it really works. Remember, a program will never do what you wish, but what was implemented.
yeah I know. hence this post requesting help in trying to figure out why the inner loop keeps looping after the dir is deleted.

it has to be something within the find function that it must be keeping a list within itself, and then using that to still search the dir and sub dir until it sees they are not there.
hence it goes though them one at a time if sub directories are present within its search list.

Quote:

you posted incomplete scripts,
no, that is a complete script. the only thing changed is the code outside of the inner loop, besides that it is a complete working script. I posted just two separate ways I tried the delete directory code, in lue of posting the entire script more than once, which is overkill.

Quote:

hard to say anything about that, but: you may use -iname in find, probably a bit better.
iname yeah that will eliminate the MP3 and mp3 needing only one of them. but has nothing to do with this loop question.

pan64 06-07-2017 09:07 AM

find collects the information before starting the loop and did not recognize you removed something during execution. probably -depth can help on this, but not really sure.

BW-userx 06-07-2017 09:13 AM

Quote:

Originally Posted by pan64 (Post 5720109)
find collects the information before starting the loop and did not recognize you removed something during execution. probably -depth can help on this, but not really sure.

yeah that is what I am figuring too, something like that mindepth maxdepth, still tinkering away on it, as I am doing 3 things at once. ;)
Like I stated it works, only that find will keep running not finding anything, so it has nothing to act on, so all that is really taking place is time going by until it gets to the next directory that it can work on is all.

Ramurd 06-08-2017 11:00 AM

Both loops are fed from a redirected stdout to stdin:

Code:

while
do
  while
  do
  done < $(command2)
done < $(command1)

might be that this causes the confusion? ( I have not known of any scripts that grow tired ;) or dizzy for that matter, and I tried! ;) )

Or... it's the variables that get overwritten; you read into FILENAME variable in both loops; As far as I could tell in the glimpse I took, they are both in the same (sub)shell; hence in the same scope: hence they're overwritten.

BW-userx 06-08-2017 11:08 AM

Quote:

Originally Posted by Ramurd (Post 5720542)
Both loops are fed from a redirected stdout to stdin:

Code:

while
do
  while
  do
  done < $(command2)
done < $(command1)

might be that this causes the confusion? ( I have not known of any scripts that grow tired ;) or dizzy for that matter, and I tried! ;) )

Or... it's the variables that get overwritten; you read into FILENAME variable in both loops; As far as I could tell in the glimpse I took, they are both in the same (sub)shell; hence in the same scope: hence they're overwritten.

Yeah now that you mention it, I suppose I'd need to pull the current dir off the outer loop then run it in the inner loop, then delete it when it gets done moving everything out of it, then the other loop should go to next dir. repeat.

I'll give that a try.
thanks.

MadeInGermany 06-08-2017 12:44 PM

Yes, the FILENAME variable is shared.
This is because each while loop is not fed from a pipe find ... | while read ... that would force a sub shell.
Looks risky, but should work here nevertheless, because it is set at the beginning of the loop to the correct value (from the loop's dedicated input stream).
But the whole structure is fishy somehow.
Certainly needs some cleanup.
Why two nested loops at all? find does a recursion already - shouldn't a simple loop go through the hierarchy?

sundialsvcs 06-08-2017 07:30 PM

Here's a couple of suggestions:

(1) "Use a real programming language." Pick any one you like, then use Bash's #!"shebang" feature to specify which language Bash should invoke to run your script.

(2) In general, I do not recommend altering any directory structure while you are also in the process of running it. Run it first, placing a list of all matching entries into an array. Then, process the array content. Alternate between "building that list" and "consuming it."

(2a) Most "real" programming languages have a ready-to-use directory runner.


All times are GMT -5. The time now is 02:55 AM.