LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-06-2017, 03:43 PM   #1
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,742

Rep: Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877
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.

Last edited by BW-userx; 06-06-2017 at 03:55 PM.
 
Old 06-07-2017, 04:12 AM   #2
serafean
Member
 
Registered: Mar 2006
Location: Czech Republic
Distribution: Gentoo, Chakra
Posts: 957
Blog Entries: 14

Rep: Reputation: 135Reputation: 135
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

Last edited by serafean; 06-07-2017 at 04:14 AM. Reason: s/process/subshell
 
1 members found this post helpful.
Old 06-07-2017, 08:39 AM   #3
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,742

Original Poster
Rep: Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877
Quote:
Originally Posted by serafean View Post
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.

Last edited by BW-userx; 06-07-2017 at 08:52 AM.
 
Old 06-07-2017, 09:34 AM   #4
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,742

Original Poster
Rep: Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877
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.
 
Old 06-07-2017, 09:45 AM   #5
pan64
LQ Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 9,874

Rep: Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908
Quote:
Originally Posted by BW-userx View Post
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 View Post
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 View Post
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.
 
Old 06-07-2017, 09:59 AM   #6
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,742

Original Poster
Rep: Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877
Quote:
Originally Posted by pan64 View Post
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.
 
Old 06-07-2017, 10:07 AM   #7
pan64
LQ Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 9,874

Rep: Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908Reputation: 2908
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.
 
Old 06-07-2017, 10:13 AM   #8
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,742

Original Poster
Rep: Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877
Quote:
Originally Posted by pan64 View Post
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.
 
Old 06-08-2017, 12:00 PM   #9
Ramurd
Member
 
Registered: Mar 2009
Location: Rotterdam, the Netherlands
Distribution: Slackwarelinux
Posts: 678

Rep: Reputation: 105Reputation: 105
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.
 
Old 06-08-2017, 12:08 PM   #10
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,742

Original Poster
Rep: Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877
Quote:
Originally Posted by Ramurd View Post
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.
 
Old 06-08-2017, 01:44 PM   #11
MadeInGermany
Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 528

Rep: Reputation: 249Reputation: 249Reputation: 249
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?
 
Old 06-08-2017, 08:30 PM   #12
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 8,673
Blog Entries: 4

Rep: Reputation: 3021Reputation: 3021Reputation: 3021Reputation: 3021Reputation: 3021Reputation: 3021Reputation: 3021Reputation: 3021Reputation: 3021Reputation: 3021Reputation: 3021
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.

Last edited by sundialsvcs; 06-08-2017 at 08:31 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] While loop is finished before doing all of jobs! massy Programming 2 04-07-2014 01:54 PM
[SOLVED] infinite nested while loop wolverene13 Programming 3 11-14-2012 09:32 PM
[SOLVED] Bash - While Loop reading from two lists simultaneously - nested while loop wolverene13 Programming 11 10-01-2011 06:00 PM
[SOLVED] scp is looping without being in a loop blainemiller Linux - Software 1 06-18-2010 01:18 PM
while loop not looping as intended Tarts Programming 7 11-28-2003 03:50 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:07 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration