Automatically move folders based on file name? - shell

I have about 1500 folders that I need to organize automatically via command line.
I'm looking for a way to search for all folders that contain /lib/file.php - if file.php does exist in the lib folder, I need the root folder (one level above lib) move into a new directory.
I know how to search for all folders containing /lib/file.php but can't figure out how to move them automatically into a new folder. For example, if /test123/lib/file.php exists, then the test123 folder should be moved into a new folder...

Try using pipe chain of find, sed, xargs and mv
find -type f -wholename '*/lib/file.php' | sed 's:/lib/file\.php$::' | xargs -I dirs mv dirs /path/to/new/dir/

Something like this, maybe:
for d in *
do
if [[ -r "${d}/lib/file.php" ]]
then
mv "${d}" "/some/new/place/."
fi
done

Related

Mv files contained in directories to directories/new path

I'm working with macOS Sierra.
I have ~ 1000+ directories with lots of files in it. Word, Excel and Zipped documents in it. Only one sub level. Important : there is spaces in the filenames and in the folder names.
We decided to change the arborescence of the files ; all the files in each directory need to be moved to a subdirectory in it called "Word & Excel" before merging with another directory tree.
I managed to create the Word & Excel directory with this command :
for dir in */; do mkdir -- "$dir/Word & Excel"; done
Basically, I just want to do
for dir in */; do mv $dir/* "./Word & Excel"; done
It is not going to work. I even do not understand if the problem is with the $dir — I need the double quote to avoid the space problem, but the asterisk is not going to work if I work with the double quote... — or with the asterisk.
I tried to get a cleaner version by following a previous answer found on the web to a similar problem, clearing the subfolder of the results (and trying basically to avoid my wildcard problem) :
for dir in */; do mv `ls -A "$dir" | grep -v "Word & Excel"` ./"Word & Excel" | cd ../ ; done
I am completely stuck.
Any idea how to handle this?
This should make it, even on Mac OS X. And yes, find sometimes needs the anchor directory.
while read dir; do
mkdir -p "$dir/Word & Excel"
find "$dir" -maxdepth 1 -type f -exec mv {} "$dir/Word & Excel" \;
done < <(find . -mindepth 1 -maxdepth 1 -type d)
This loops over the sub-directories of the current directory (one sub-level only), for each of them (dir), creates the dir/Word & Excel sub-sub-directory if it does not already exist, finds all regular files immediately inside dir and moves them in the dir/Word & Excel. And it should work even with crazy directory and file names.
This being said, if you could convince your boss not to use unusual file or directory names, you life with bash and the Command Line Interface (CLI) would probably be much easier.
Okay, I will use "subfolder" as my subfolder name.
First, creating subfolder within all the dirs
for dir in $(find -type d | grep "/");do mkdir $dir/subfolder; done
I each of one of those, I created a file. I order to move all files within the dirs to the subfolder, I will do something like:
for dir in $(find -type d | grep -vE 'subfolder' | grep '/');do for file in $(find $dir -type f);do mv $file $dir/subfolder;done ;done
You might want to experiment with --exec in find, but just creating a nested loop was the fastest solution for me.
Let me break it down for you. Here, I try to find all the directories in my path, excluding the subfolder directory and the current one. I could've used -maxdepth 0 with find but since I only had these dirs, it wasnt necessary
for dir in $(find -type d | grep -vE 'subfolder' | grep '/')
Now, in each of those dirs, we try to find all the files (in your case, the zip files and what now).
do for file in $(find $dir -type f)
Now, we just move the found files into the directories from the first loop with the name of the subfolder appended.
do mv $file $dir/subfolder;done ;done
Keep in mind that since the first loop is closed at the very end, it will do the move operation for 1 directory at a time, and for all files in only that directory. Nested loops can be a bit trickier to understand, especially when someone else does them their own way, I know :(

batch renaming of multiple files of same extension

I need to rename multiple files without knowing the filename(basename/string name ) of the file.
i tried with:
for i in $(ls /Users/Destiny/Desktop/Index/*.ebwt);
do
mv -v "$i" "${i/hsa/hsa.genome.V86C}"; ## works when i know the string to replace
done
but what if dont know the filename(string name)?
Before rename: hsa.1.ebwt hsa.2.ebwt hsa.3.ebwt hsa.4.ebwt
After rename: hsa.genome.V86C.1.ebwt hsa.genome.V86C.2.ebwt hsa.genome.V86C.3.ebwt hsa.genome.V86C.4.ebwt
You could do something with a find in your directory. And if they all have the same extension then it could be something like below with your move that you currently have:
find /Users/Destiny/Desktop/Index -type f -name "*.ebwt" | while read file;
do
mv -v "$file" "${file/hsa/hsa.genome.V86C}";
done
This will rename it inside of the current directory, and if you want to move it to a different directory later down the line, you could surround second argument like this with basename to make moving easier:
"/SomeDirectory/$(basename ${file/hsa/hsa.genome.V86C})"
You could also put a -maxdepth 1 after the directory you want to find if you dont want it to be recursive in the find

Do actions in each folder from current directory via terminal

I'm trying to run a series of commands on a list of files in multiple directories located directly under the current branch.
An example hierarchy is as follows:
/tmp
|-1
| |-a.txt
| |-b.txt
| |-c.txt
|-2
| |-a.txt
| |-b.txt
| |-c.txt
From the /tmp directory I'm sitting at my prompt and I'm trying to run a command against the a.txt file by renaming it to d.txt.
How do I get it to go into each directory and rename the file? I've tried the following and it won't work:
for i in ./*; do
mv "$i" $"(echo $i | sed -e 's/a.txt/d.txt/')"
done
It just doesn't jump into each directory. I've also tried to get it to create files for me, or folders under each hierarchy from the current directory just 1 folder deep, but it won't work using this:
for x in ./; do
mkdir -p cats
done
OR
for x in ./; do
touch $x/cats.txt
done
Any ideas ?
Place the below script in your base directory
#!/bin/bash
# Move 'a.txt's to 'd.txt's recursively
mover()
{
CUR_DIR=$(dirname "$1")
mv "$1" "$CUR_DIR/d.txt"
}
export -f mover
find . -type f -name "a.txt" -exec bash -c 'mover "$0"' {} \;
and execute it.
Note:
If you wish be a bit more innovative and generalize the script, you could accept directory name to search for as a parameter to the script and pass the directory name to find
> for i in ./*; do
As per your own description, this will assign ./1 and then ./2 to i. Neither of those matches any of the actual files. You want
for i in ./*/*; do
As a further aside, the shell is perfectly capable of replacing simple strings using glob patterns. This also coincidentally fixes the problem with not quoting $i when you echo it.
mv "$i" "${i%/a.txt}/d.txt"

unix command to copy all .h file with modified directory-structure

Suppose I have a folder structure like:
Libraries\
UIToolkit\
files\
toolkit.h
toolkit.c
toolkit.resource
NetworkLayer\
files\
network.h
network-info.txt
...
I need a command so that I can input the Libraries folder and specify a Output folder then in the Output folder I have:
Output\
UIToolkit\
toolkit.h
NetworkLayer\
network.h
Basically it:
copies all .h file and preserves the folder structure
also move all the headers to its sub-libraries' root folders no matter how deep they are in the sub-libraries sub-folders.
I was using rsync but it does not do 2nd step, so I guess I need some quick and dirty modification?
Thanks a lot!
A bit modified answer based on devnull's:
idir=$1
odir=$2
while read -r f; do
subdir=${f#$idir}
subdir=${subdir%%/*}
mkdir -p $odir/$subdir
cp -a $f $odir/$subdir
done < <(find $idir -type f -name "*.h")
call something like
./thisscript.sh Libraries Output
shall be able to work with absolute or relative directories, IMHO; but won't handle if .h file is right under Libraries (must be at least one subdir level down..).
You can say:
cd /path/to/Libraries
while read -r file; do
odir=$(cut -d'/' -f2 <<< ${file});
fname=$(basename ${file});
cp "$file" "/path/to/Output/${odir}/${fname}";
done < <(find . -type f -name "*.h")
This would copy all the *.h files to the Output folder as per the desired directory structure.

Moving files to a directory

I want to move all files matching a certain pattern in the current directory to another directory.
For example, how would I move all the files starting with nz to a directory called foobar? I tried using mv for that, but it didn't work out well.
find . | grep "your_pattern" | xargs mv destination_directory
Does the following:
Finds all files in the current directory
Filters them according to your pattern
Moves all resulting files to the destination directory
mv nz* foobar should do it.
mv nz* foobar/
Try to use "mmv", which is installed on most Linux distros.
This will do it, though if you have any directories beginning with nz it will move those too.
for files in nz*
do
mv $files foobar
done
Edit: As shown above this totally over the top. However, for more complex pattern matches you might do something like:
for files in `ls | grep [regexp]`
do
mv $files foobar
done
mv nz* foobar/
mv - will move or rename file
nz - will get all the items that start with the "nz"
foobar/ - is the directory where all items will go into

Resources