separate out files based on name
I have a folder named Pictures that contains a bunch of .jpg files. My problem is that they all have randomly numbered names, then there is a duplicate of the file that is random numbers then the letter a right before the .jpg.
for example, there would be 123.jpg and 123a.jpg, where 123a.jpg is just a resized version of 123. What i'd like to do but have NO clue how to, is to have a script or something go through my Pictures folder, then copy the ones that end in a.jpg to a folder called Resized, and ones that dont have that to a folder called Originals. That way my Pictures folder will be in tact, and i'll have copies of them all separated out. I have to do this all through the CLI on a machine, maybe I dont even need a script and can just do it with a slick command? |
Are they all in the Pictures main directory or are they placed in sub-directories?
|
sub-directories, and lots of them
|
Hence you need a command to search recursively inside the Pictures folder. You can try find, using the -regex option to match file names with numbers and w/ or w/o the trailing a. The -exec action might serve to move them. On the other hand, if you want to preserve the original directory structure inside Resized and Originals, you may want to write a more elaborate script.
|
Code:
mv *a.jpg /destination |
Quote:
Code:
find Pictures/ -name '*a.jpg' -exec cp -vi -- '{}' Resized/ ';' Code:
cd Pictures/ |
cool, thanks guys. I'll try out Nominal's suggestions, I never would have been able to come up with that myself haha.
|
I tried the folder structure one, and it says "missing argument to '-exec' "
|
At this point keep it simple and do a loop to achieve your task step-by-step and to have a better control on what happens. For example, suppose you have the following directories:
Code:
/home/rjo98/Originals Code:
while read src Code:
while read src |
Thanks. How do I get it to run all those lines at once, put them in a .sh file then run that?
|
also, i was hoping to preserve the Pictures folder by just doing copies, in case something screwed up, but i guess that's why we echo first...
|
Quote:
Edit: the thread lived, and had to put in the quote to show what I was referring to. |
Quote:
|
Quote:
|
getting somewhere with ramurd's suggestion...
now i get mkdir: invalid option -- i |
Quote:
|
Quote:
1) none of the mkdirs stated by Nominal should give an -- i option 2) Nominal's commands are quoted thoroughly I expect you're not putting all the quotes in there, they're very important, otherwise you can get bad and unpredictable results. Otherwise Nominal's commands are safe and not dangerous at all; in fact very simple as it's all in one command that suits all. To test out the commands you actually get, you can try to put an "echo" in front of them (so mkdir ... becomes echo mkdir ...) and see if you get results that are not so logical... Again, I expect a few missing quotes around {}. |
that's what i do get, the only i that i have after a - is for the cp, maybe something isn't copying and pasting right from the web to my CLI.
|
Quote:
|
does anyone see what I did wrong?
find /Pictures/ -name '*A.jpg' -exec mkdir -p "/Resized/`dirname '{}'`" \&\& cp -vi '{}' "/Resized/`dirname '{}'`" ';' |
while read src
do dst=${src/Pictures/Resized} echo mkdir -p $(dirname $dst) echo mv $src $dst done < <(find /home/rjo98/Pictures -name \*a.jpg) I'm trying to modify this, would i make it like this? I'm so confused right now. My pictures folder is /Pictures and i want them to go to /Resized if they are *A.jpg while read src do dst=${src/Resized} echo mkdir -p $(dirname $dst) echo mv $src $dst done < <(find /Pictures -name \*A.jpg) |
Quote:
Code:
find /Pictures/ -name '*A.jpg' -exec dirname '{}' \; Code:
find /Pictures/ -name '*A.jpg' -exec echo `dirname '{}'` \; Code:
find /Pictures/ -name '*A.jpg' -exec echo `ls -l '{}'` \; |
Quote:
Code:
${src/Pictures/Resized} Code:
while read src Code:
/Pictures/subdir/subsubdir/123A.jpg Code:
dst=/Resized/subdir/subsubdir/123A.jpg |
ok, thanks. I'll give it a shot, even though I dont understand the substitution, like how it knows where to stop
|
A little add-on. In case there are directory or file names with blank spaces, better to use double quotes:
Code:
while read src |
Thanks, i'll try that instead.
but i have a question. so what if my original path was /here/are/the/Pictures and i wanted to move the ones with *a.jpg to /i/want/them/here how would i put that in that dst line? maybe that will help me understand how it works. |
Indeed the substitution assumes that the two directories Pictures and Resized have the same path. Suppose you have a string like this:
Code:
/home/user/Pictures/something/some.jpg Code:
/home/user/Resized/something/some.jpg Code:
${src/Pictures/Resized} Code:
${variable/pattern/replacement} Code:
while read src |
Quote:
|
Quote:
Code:
cd Pictures/ |
How about:
Code:
#!/bin/bash and set it within the script, like: Code:
if (( $# != 1 )) |
Nominal, I dont think your solution is working totally, I think its skipping some files/folders, as when i ran the command on my linux box, it only got 3.4GB of stuff, while if i do a search for *a.jpg on my windows machine connected to it, it's only halfway done copying the files to a windows machine and its already at 5GB.
could it be folder names or something screwing this up? |
I just ran the command for not a's then did a
find ./ -name '*a.jpg' from when i was in that folder which should return no results since it was supposed to only grab the not a.jpg's, and its returning a ton of results. This is so confusing |
But if you are using cp instead of mv then the files are copied and the originals will still be in the same place. Unless you have of course changed that??
Also, how your Windows machine reads sizes could also be affected by the format, ie fat or ntfs. |
Isnt that one find statement looking for all the jpg's that aren't *a.jpg though, so it should be skipping them in that copy?
It was over 12GB off, and the number of files was vastly different. |
Quote:
Let's recap. Start by changing to the folder that contains the Pictures folder. I'll write out each command you need to run following that explicitly. First, remove and recreate the Resized and Originals directories by running Code:
rm -rf Resized Originals Code:
cd Pictures Code:
find . -type f -name '*[Aa].[Jj][Pp][Gg]' -exec cp -vi -- '{}' '../Resized/{}' ';' Code:
find . -type f -name '*[^Aa].[Jj][Pp][Gg]' -exec cp -vi -- '{}' '../Originals/{}' ';' Quote:
The reason it does something else than what you'd expect is that Windows ignores case in file names, but POSIX operating systems do not. In other words, you said you have file names '*a.jpg', but actually you have '*A.jpg', '*a.JPG', '*A.Jpg' etc. For Windows users it is very easy to miss, but everybody else expects case sensitive file names. I'd appreciate if you could confirm that your images have names like that, not just '*a.jpg' in lower case, so I don't feel like an bully pointing this out. |
If you want to find out the actual total size of files in Linux, you can run e.g.
Code:
find Pictures -type f -printf '%s\n' | awk '{ s+=$1 } END { printf("%.3f GB\n", s/1000000000.0) }' Code:
find Pictures -type f -printf '\n' | wc -l Code:
TOTAL=`find Pictures -type f -printf '\n' | wc -l` Code:
find Pictures -type f -name '*[^Aa].[Jj][Pp][Gg]' -printf '%s\n' | awk '{ s+=$1 } END { printf("%16.0f bytes of original images\n", s) }' I personally don't trust Windows further than I can throw it, at least not the status bar or info sidebar stuff. If I remember correctly, the Properties dialog (from the context menu) tells you both the total number of bytes and the number of bytes required to store the files on-disk, though. |
Also, you could use -iname to ignore case in your find.
|
All times are GMT -5. The time now is 12:54 AM. |