batch recursive move files of extension to folder named with that extension - bash

I have files of type mp3 and flac. Lets say my basic directory structure is
/music/artist/album
I have (already) made
/music/artist/album/flac/
/music/artist/album/mp3/
with a recursive batch operation.
I want to loop through all of /music/ and do the following:
If /music/artist/album/ has mp3s, move them to /music/artist/album/mp3/.
If /music/artist/album/ has flacs, move them to /music/artist/album/flac/.
Some folders have mp3 and flac. Looking for either script file or command line solutions

find /music/ -name '*.mp3' -execdir mv {} mp3/ \;
find /music/ -name '*.flac' -execdir mv {} flac/ \;
-execdir runs the specified command in the directory of the current file. This lets you use mp3/ and flac/ directories relative to the current artist/album.

Here you have one way to do it :
find /music -type f -name "*.mp3" | xargs mv $1 /music/artist/album/mp3/
find /music -type f -name "*.flac" | xargs mv $1 /music/artist/album/flac/
Hope it works for you.
Greetings!

Change the current directory to where your music files are, then move mp3s to the mp3 folder and flacs to the flac folder.
cd /music/artist/album/
mv *.mp3 mp3/
mv *.flac flac/

Related

copying files from subfolders via grep shell script

I want to write a shell script to do the following :
I have a folder with many subfolders. Each of these subfolders has a *.gz file and some other files which I don't need. I want to move all .gz files into a new subfolder called needed_files (I have already created this subfolder). So I did the following :
I went to the parent folder with all the subfolder and cp /.gz > needed_files/., but this did not work. Can you suggest what I should be doing?
grep is irrelevant here. Use find:
find . ! \( -type d -name needed_files -prune \) -type f -name '*.gz' \
-exec echo mv -t needed_files {} +
POSIX equivalent of that -exec is
-exec sh -c 'echo mv "$#" needed_files' _ {} +
If its output looks good, remove echo.
Btw I noticed that the title says copy but you also say I want to move, so decide on what you exactly want to do and let me know so I can edit my answer.

Iterate over folders and move files up one level

I have a directory structure that looks like this:
/images
/1
/.tmp
image1.jpg
image2.jpg
/2
.tmp
image1.jpg
image2.jpg
image3.jpg
/3
.tmp
image1.jpg
image2.jpg
What I need is to move all of those files in .tmp up one level, so their paths are images/1/image1.jpg rather than images/1/.tmp/image1.jpg. The issue is that I have hundreds or thousands of these numbered folders, so doing it by hand would take forever.
Is there an OS X or Unix shell command that I could iterate over each /.tmp folder and move the contents up a level, or something like:
mv images/*/.tmp/* images/< the current dir being iterated over>/*
If your find supports the -execdir command (which OSX's find apparently does), then you could do:
find . -iname '*.jpg' -execdir mv {} .. \;
-execdir runs the command from the directory where the file was found, so .. will refer to that file's directory's parent directory.
You can refine this to force matching a .tmp directory:
find . -path '*/.tmp/*.jpg' -execdir mv {} .. \;
However, * in -path also matches /, so this will also match, for example, images/.tmp/foo/image.jpg.
You could do:
find . -type d -name .tmp -print0 | xargs -0I_ find _ -maxdepth 1 -name '*.jpg' -execdir mv {} .. \;
Or, using find's regex support:
find . -regex '.*/\.tmp/[^/]*\.jpg' -execdir mv {} .. \;
From scratch without testing:
cd /images
for i in $(find ./ -name *.jpg)
do
d = $(dirname $i)
d = $(dirname $d)
echo $i $d
# test! before use the next
# mv $i $d
done

Unix script moving files to folders

I have a folder work and the below script searches for .txt or .csv files and moves the files into completed folder. I created one more folder (APEX) inside work folder, but the files from APEX folder are not moving to the completed folder and giving below error. I would like all the .txt or .csv files in my-test-folder/work and my-test-folder/work/APEX files to be moved to my-test-folder/done.I do not have a folder /my-test-folder/completed/APEX/ ,nor I want the files to be moved there.
Error : mv: cannot move ./my-test-folder/work/APEX/test1.txt to ./my-test-folder/completed/APEX/test1.txt: No such file or directory
find . -path "*work*" \( -iname "*.txt" -o -iname "*.csv" \) -exec bash -c "mv {} \`echo {} | sed -e 's/work/completed/g' \` " \;
If you don't want to keep the same directory hierarchy in my-test-folder/completed as in my-test-folder/work, you can simplify your command:
find full/path/to/work -iname "*.txt" -o -iname "*.csv" -exec mv "{}" full/path/to/completed \;
Note that this will not remove empty directories left after moving all the files out. You can do this if you are using GNU find with the following command:
find work -empty -delete

How to copy files recursively, rename them but keep the same extension in Bash?

I have a folder with tens of thousands of different file types. Id like to copy them all to a new folder (Copy1) but also rename them all to $RANDOM but keep the extension intact. I realize I can write a line specifying which extension to find and how to name it, but there is got to be a way to do it dynamically, because there are at least 100 file types and may be more in the future.
I have the following so far:
find ./ -name '*.*' -type f -exec bash -c 'cp "$1" "${1/\/123_//_$RANDOM}"' -- {} \;
but that puts the random number after the extension, and also it puts the all in the same folder. I cant figure out how to do the following 2 things:
1 - Keep all paths intact, but in a new root folder (Copy1)
2 - How to have name be $RANDOM.extension, instead of .extension.$RANDOM
PS - by $RANDOM i mean actual randomly generated number. I am interested in keeping folder structure, so we are dealing with a few hundred files at most per directory, but all directories/files need to be renamed to $RANDOM. Another way to look at what I need to do. Copy all contents or Folder1 with all subdirectories and files to Folder2 (where Fodler2 is a $RANDOM name), then rename all folders and files to random names but keep all extensions.
EDIT: Ok i figured out how to rename and keep extension. But I have a problem where its dumping all of the files into the root directory where script is run from. How do I keep them in their respective folders? Command Im using is:
find ./ -name '*.*' -type f -exec bash -c 'mv "$1" $RANDOM.${1##*.}' -- {} \;
Thanks!
Ok i figured out how to rename and keep extension. But I have a
problem where its dumping all of the files into the root directory
where script is run from. How do I keep them in their respective
folders? Command Im using is:
find ./ -name '*.*' -type f -exec bash -c 'mv "$1" $RANDOM.${1##*.}' -- {} \;
Change your command to:
PATH=/bin:/usr/bin find . -name '*.*' -type f -execdir bash -c 'mv "$1" $RANDOM.${1##*.}' -- {} \;
Or alternatively using uuids instead of random numbers:
PATH=/bin:/usr/bin find . -name '*.*' -type f -execdir bash -c 'mv "$1" $(uuidgen).${1##*.}' -- {} \;
Here's what I came up with :
i=1
random="whatever"
find . -name "*.*" -type f | while read f
do
newbase=${f/*./$random$i.} //added counter to filename
cp $f /Path/Name/"$newbase"
((i++))
done
I had to add a counter to random (i), otherwise, if the extensions are similar, your files would overwrite themselves when copied.
In your new folder, your files should look like this :
whatever1.txt
whatever2.txt
etc etc
I hope this is what you were looking for.
Here is the command that worked for me.
find . -name '*.pdf' -type f -exec bash -c 'echo "{}" && cp "$1" ./$RANDOM.${1##*.}' -- {} \;

Move only files recursively from multiple directories into one directory with mv

I currently have ~40k RAW images that are in a nested directory structure. (Some folders have as many as 100 subfolders filled with files.) I would like to move them all into one master directory, with no subfolders. How could this be accomplished using mv? I know the -r switch will copy recursively, but this copies folders as well, and I do not wish to have subdirectories in the master folder.
If your photos are in /path/to/photos/ and its subdirectories, and you want to move then in /path/to/master/, and you want to select them by extension .jpg, .JPG, .png, .PNG, etc.:
find /path/to/photos \( -iname '*.jpg' -o -iname '*.png' \) -type f -exec mv -nv -t '/path/to/master' -- {} +
If you don't want to filter by extension, and just move everything (i.e., all the files):
find /path/to/photos -type f -exec mv -nv -t '/path/to/master' -- {} +
The -n option so as to not overwrite existing files (optional if you don't care) and -v option so that mv shows what it's doing (very optional).
The -t option to mv is to specify the target directory, so that we can stack all the files to be moved at the end of the command (see the + delimiter of -exec). If your mv doesn't support -t:
find /path/to/photos \( -iname '*.jpg' -o -iname '*.png' \) -type f -exec mv -nv -- {} '/path/to/master' \;
but this will be less efficient, as one instance of mv will be created for each file.
Btw, this moves the files, it doesn't copy them.
Remarks.
The directory /path/to/master must already exist (it will not be created by this command).
Make sure the directory /path/to/master is not in /path/to/photos. It would make the thing awkward!
Make use of -execdir option of find:
find /path/of/images -type f -execdir mv '{}' /master-dir \;
As per man find:
-execdir utility [argument ...] ;
The -execdir primary is identical to the -exec primary with the exception that
utility will be executed from the directory that holds the current
file. The filename substituted for the string ``{}'' is not qualified.
Since -execdir makes find execute given command from each directory therefore only base filename is moved without any parent path of the file.
find <base location of files> -type -f -name \*\.raw -exec mv {} master \;
If your hierachy is only one level deep, here is another way using the automated tools of StringSolver:
mv -a firstfolder/firstfile.raw firstfile.raw
The -a options immediately applies the similar transformation to all similar files at a nesting level 1 (i.e. for all other subfolders).
If you do not trust the system, you can use other options such as -e to explain the transformation or -t to test it on all files.
DISCLAIMER: I am a co-author of this work for academic purposes, and working on a bash script renderer. But the system is already available for testing purposes.

Resources