LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 11-04-2019, 03:00 AM   #1
ericlindellnyc
Member
 
Registered: Jun 2017
Posts: 181

Rep: Reputation: Disabled
compare 2 filenames & move one to other's directory


I have code that compares two files, & if equal, touches one with the other, so it has the same date.

This time, I'd like to compare the file names only, without the extension, and if equal, move one to the other's subdirectory.

This process makes the comparison for all files in two directories, iterating through one directory to find a match for each in the other directory, which it also iterates through, for a nested loop.

FILES=$( find ./nu/Mrj -type f ); for f in $FILES; do for g in ./ol/Mrj/*; do echo "f is $f g is $g"; if cmp "$f" "$g"; then echo "match"; touch -r $g $f; else echo "no match"; fi; done; done

Thanks in advance
 
Old 11-04-2019, 05:07 AM   #2
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 7,308
Blog Entries: 3

Rep: Reputation: 3721Reputation: 3721Reputation: 3721Reputation: 3721Reputation: 3721Reputation: 3721Reputation: 3721Reputation: 3721Reputation: 3721Reputation: 3721Reputation: 3721
test is probably what is needed.

Code:
FILES=$( find ./nu/Mrj -type f ); 
for f in $FILES; do 
        for g in ./ol/Mrj/*; do 
                echo "f is $f g is $g"; 
                if test "$f" = "$g"; then 
                        echo "match"; 
                        touch -r $g $f; 
                else echo "no match"; 
                fi; 
         done; 
done
See "man test"
 
Old 11-04-2019, 09:01 PM   #3
ericlindellnyc
Member
 
Registered: Jun 2017
Posts: 181

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by Turbocapitalist View Post
test is probably what is needed.

Code:
FILES=$( find ./nu/Mrj -type f ); 
for f in $FILES; do 
        for g in ./ol/Mrj/*; do 
                echo "f is $f g is $g"; 
                if test "$f" = "$g"; then 
                        echo "match"; 
                        touch -r $g $f; 
                else echo "no match"; 
                fi; 
         done; 
done
See "man test"
Great.
Now I need to extract the filename independent of the extension to make the comparison.
If the FN's match (regardless of extension),
then move (or copy, doesn't matter) one file to the same directory as the other.

This code separates FN from EXT.
Code:
Code:
NAME=`echo "$FILE" | cut -d'.' -f1`
EXTENSION=`echo "$FILE" | cut -d'.' -f2`
I can try to extract one file's path so I can move the other file to its directory,
which seems cumbersome.
I could try a simple mv, but I need to keep both files.

Got it !! .. Duplicate the directory, then use mv to overwrite the (let's say) TXT files in one directory with MP3 files in the other.
Then MERGE the directory of TXT files with the directory of MP3 files !!
Perfect, thank you.
 
Old 11-04-2019, 09:07 PM   #4
BW-userx
LQ Guru
 
Registered: Sep 2013
Location: Somewhere in my head.
Distribution: Slackware (15 current), Slack15, Ubuntu studio, MX Linux, FreeBSD 13.1, WIn10
Posts: 10,342

Rep: Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242
another way to get extension using bash internals
Code:
$ filename=hommer.txt

$ ext=${filename##*.} ; echo $ext
txt
so yours would be
Code:
ext=${FILE##*.}
or
ext=${f##*.}
depending on when you grab the extension.
to get file name w/o ext
Code:
$ filename=/path/to/file/hommer.txt

$ fname=$(basename $filename) ; echo $fname
hommer.txt

$ prefix=${fname%.*} ; echo $prefix
hommer

Last edited by BW-userx; 11-04-2019 at 09:12 PM.
 
Old 11-05-2019, 08:47 PM   #5
ericlindellnyc
Member
 
Registered: Jun 2017
Posts: 181

Original Poster
Rep: Reputation: Disabled
THIS WORKS PERFECTLY, EXCEPT FOR THE LINE
Code:
mv $g $f;
Code:
#!/bin/bash
FILES=$( find ./txtMp3s/txts -type f ); 
for f in $FILES; do 
    for g in ./txtMp3s/mp3s/*; do 
        echo "f is $f g is $g"; 
        fPrefix=${f%.*} ; echo $fPrefix;
        gPrefix=${g%.*} ; echo $gPrefix;
        if test "$fPrefix” = "$gPrefix”; then 
                echo "match"; 
                mv $g $f;
        else echo "no match"; 
        fi; 
    done;
done
If I don't have that line there, everything works perfectly, all files are properly echoed, and match is printed, perfectly.
But then I add the
Code:
"mv $g $f;"
and it says
Code:
mv: ./txtMp3s/mp3s/*: No such file or directory
And when I check the original directories, the one that had the mp3 file (called g) is empty, and nothing new has been moved to directory containing txt file (called f), though at least f is still there.

Thoughts much appreciated !!
 
Old 11-05-2019, 09:36 PM   #6
Firerat
Senior Member
 
Registered: Oct 2008
Distribution: Debian sid
Posts: 2,683

Rep: Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783
Code:
FILES=$( find ./txtMp3s/txts -type f )
is bad!
https://mywiki.wooledge.org/BashGuide/Arrays
that explains why

Code:
mv $g $f
since you are not wrapping the vars with " you are subject to splitting if the path/filename has spaces in it

do you really need xPrefix vars?

Code:
#!/bin/bash
while read f; do 
    for g in ./txtMp3s/mp3s/*; do 
        printf "f is %s g is %s\n%s\n%s\n" $f $g ${f%.*} ${g%.*}  
        # do you really need that ?
        filename="${f##*/}" # strips path
        [[ ${g%.*} =~ /${filename%.*}$ ]] \
            && mv -v "$g" "${f%/*}/" \
            || echo "no match"
    done
done < <( find ./txtMp3s/txts -type f )
https://mywiki.wooledge.org/BashGuid...ndConditionals

https://mywiki.wooledge.org/BashGuid...eter_Expansion
see that page to understand the ${f%.*} and ${f%/*}/


# Edit, Doh, this will never match, since path is different
#[[ ${f%.*} == ${g%.*} ]] \

filename="${f##*/}" # strips path
# Edit2, this is not great either
#[[ ${g%.*} =~ ${filename%.*}$ ]]
it is only checking the end matches
tune_1.mp3 remix_tune_1.mp3
tune_1 could overwrite the remix version
adding a leading slash should fix it
[[ ${g%.*} =~ /${filename%.*}$ ]]

see the section on Regular Expressions
https://mywiki.wooledge.org/BashGuide/Patterns
to understand the =~ bit

Last edited by Firerat; 11-05-2019 at 09:57 PM.
 
Old 11-06-2019, 07:33 AM   #7
BW-userx
LQ Guru
 
Registered: Sep 2013
Location: Somewhere in my head.
Distribution: Slackware (15 current), Slack15, Ubuntu studio, MX Linux, FreeBSD 13.1, WIn10
Posts: 10,342

Rep: Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242
It strips files down to just the name, then compares the two, then creates subdir within the same place the file is found, then moves dup file into same dir match in the subdir of the path. keeps a running total of match, no match, and a running list to where each individual file was moved to.

Even though you do not specify between dirs what goes where and from where. Not good programing logic. It is an incomplete thought.
"This time, I'd like to compare the file names only, without the extension, and if equal, move one to the other's subdirectory."
which one goes where??????

Code:
#!/usr/bin/env bash
#set -xv 

#allows script to be ran outside
#of working directory
noMatch=0
match=0
#Keep is control loop, or outside loop
#move or delete file is the inner loop
SAVEFILEARRAY=()
#Set path to base directory's
KeepFile=/home/userx/linux
MoveFile=/home/userx/test2

#Name of the place to put
#dup filenames
SubDirName=Dups

script_dir="$HOME/scripts"
#keep loop
while read KFile 
	do
	#chop off both ends to get just the filename w/o extension
	  KeepFileName=${KFile##*/}
	  KeepFileName=${KeepFileName%.*}
		
	 while read MFile
		do
			#chop off both ends to get just the filename w/o extension
			MoveFileName=${MFile##*/}
			MoveFileName=${MoveFileName%.*}
			if [[ "${KeepFileName}"  = "${MoveFileName}" ]] ; then
				#prepare path to move the file to
				
				MFileP=${MFile%/*}
				Mv2Dir="$MFileP"/"$SubDirName"
				mkdir -p "$Mv2Dir"
				
			echo "	mv -v "$MFile" "$Mv2Dir"  "
			
			#keep track of where they went to
				SAVEFILEARRAY+=( "$Mv2Dir"/"${MFile##*/}" )
				
				#keep a count?????
				((match++))
			else
				((noMatch++))
			 fi
			 
	done < <(find "$MoveFile" -type f -name "*.*")
			#clear the var to prevent 
			#adding on to the string
	        unset Mv2Dir
done < <(find "$KeepFile" -type f -name "*.*" )

echo "
Files Matched is $match, Not matched $noMatch
Files where moved to.
"

printf "%s\n" "${SAVEFILEARRAY[@]}"
Just swap out the MFileP=${MFile%/*} to MFileP=${KFile%/*} to get a reverse save/move to path.

for loops vs while loops:
So between you, Firerat and mine you see that there is more than one way to get this done. But it is all still the same basic logical flow.

If you have more than one dup of the "same file" then as suggest just add a number to the end of the file. Though you'd have to check save dir for a match to that file before moving it into the same dir, if match, then add a number to the file, then move the file into the same save dir to prevent over writing of the two files. Which would also require that you get last number saved so you do not over write that part of the file in the process. Instead increment one more than last number of same file saved.

This way you can then run diff on the matching files to see if contents within the files are too dups or not to determine what to then do with them.

output sample
Code:
Files Matched is 98, Not matched 36914
Files where moved to.

/home/userx/test2/scripts/Dups/schema.pl
/home/userx/test2/scripts/Dups/schema.pl
/home/userx/test2/scripts/Dups/HandBreakCLI.3
/home/userx/test2/scripts/Dups/HandBreakCLI.2
/home/userx/test2/scripts/Dups/HandBreakCLI.1
/home/userx/test2/scripts/perl/Dups/changeFileNames.pl
/home/userx/test2/scripts/perl/Dups/perl-find-missing-numbers.pl
/home/userx/test2/scripts/perl/Dups/perl-Dir-number-list.pl
if you wanted to put all dups in one central location, then I do suppose you'd already know how to redirect path -> ../sameDir/subdir/dupfile or ../saveDir/dups/DupFile or ../saveDir/DupFile

Last edited by BW-userx; 11-06-2019 at 09:50 AM.
 
Old 11-06-2019, 03:25 PM   #8
ericlindellnyc
Member
 
Registered: Jun 2017
Posts: 181

Original Poster
Rep: Reputation: Disabled
reply to BW-userx

Thanks, Firerat & BW-userx, for detailed comments,
which will take me some time to work through.
I like the back-to-basics bootcamp approach.

Some of my results are just bizarre. I end up with a target directory
whose size doesn't add up to its contents.
Directory has only TXT files with kilobyte-range sizes,
but the total directory size seems to reflect the presence of megabyte-size MP3's,
which I tried to MV there but that do not show up when I look at directory contents.

Moreover, these MP3s are not in their original directory, in the recycle bin,
or anywhere in the entire system, wtf, as far as I can tell.

Last edited by ericlindellnyc; 11-06-2019 at 03:41 PM. Reason: spelling
 
Old 11-06-2019, 03:45 PM   #9
BW-userx
LQ Guru
 
Registered: Sep 2013
Location: Somewhere in my head.
Distribution: Slackware (15 current), Slack15, Ubuntu studio, MX Linux, FreeBSD 13.1, WIn10
Posts: 10,342

Rep: Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242Reputation: 2242
I do not fully understand your situation in what now are you saying, mp3 size files everywhere including the recyle bin. are your find compare paths the entire system?

you show two dirs
Code:
/txtMp3s/mp3s/
which indicates it has mp3 in it.

/txtMp3s/txts
which indicates it has txt files in it.
I merely created a script that looks at the filename without an extension if match put it into a subdir of one of the files base directory.

which would in your case either be in
/txtMp3s/mp3s/subdir
/txtMp3s/txts/subdir

what relationship does the txt files have with the mp3 files?

did you know you can get meta data off of mp3s and sort them out using that?
providing they have the metadata written to them.
artist,title,album etc...
 
  


Reply

Tags
compare



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] Script to compare filenames in a directory, sort and delete OutsiderFilms Linux - Newbie 10 05-03-2012 12:20 AM
[Bash] Rename filenames with corresponding filenames Power2All Linux - Software 4 12-02-2009 04:15 AM
compare filenames without extentions amnesiavivace Programming 5 01-03-2009 08:10 PM
Ph&#7909;c h&#7891;i d&#7919; li&#7879;u b&#7883; m&#7845;t???, c&#7913; pollsite General 1 06-27-2005 12:39 PM
Gotta love those &#1649;&#1649;&#1649;&#1649;&#1649;&#1649;&#1649;&# iLLuSionZ Linux - General 5 11-18-2003 07:14 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 11:58 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
Open Source Consulting | Domain Registration