How to move files including full path to a subfolder? - bash

I've got a public folder that includes .html and non .html files in its root and subfolders. I need to move all non .html files to a subfolder of the public folder, e.g. to public/assets, preserving their full path.
So far I got something like this:
mkdir -p public/assets
find public -type f -not -name "*.html" -print0 | xargs -0I{} mv {} public/assets/
It doesn't work correctly, because it doesn't move files with full path, e.g. if there's a file public/foo/bar.js, it will be moved to public/assets/bar.js and not into public/assets/foo/bar.js.
I also tried another version:
mkdir -p public/assets
find public -type f -not -name "*.html" | sed 's#\(public\)\(.*\)#\1\2 public/assets\2#' | xargs -I% mv %
but it complains about incorrect syntax of mv command. I pass only one parameter to it, but after running sed it consists of 2 paths separated with one space, so I hoped it will treat it as 2 parameters.
It would be also great, if there was a way to remove empty folders after moving all files, but it's not necessary.

I suggest using rsync for this. Also, I would use a folder in a different location as destination. That folder can then be copied back to your public folder.
mkdir /tmp/assets
rsync -r --include="*/" --exclude="*.html" --include="*" --prune-empty-dirs public/* /tmp/assets
mv /tmp/assets public/assets

Related

How to copy all files with the same name into another directory using cp command

I have directory named "Documents". In this directory I have 5 files:
User1.txt
User2.txt
User3.txt
User4.txt
User5.txt
Users-info.zip
index.html
I want to copy only those files in whose names there is a word "user" to another directory. How I can do this with cp command?
cp User* /path/to/dir try this, will be enough.
If you wish unusual way:
find . -type f -name 'User*' -print0 | xargs -0 cp -t /path/to/dir/for/copies/
For your case it is:
cp User[1-9].txt /dst_dir
We copy only files with User in the beginning, than some digit and finally .txt.

Copy files recursively to all sub-domain folders

On my server, I have x number of sub-domains
Their folder names are like this:
example1.mydomain.com , example2.mydomain.com, examplex.mydomain.com
and they all exist in one location.
I am trying to write a simple bash script to copy all folders and files in folder SOURCE for example to all of those sub-domain folders (and replace existing).
In other words, I want to copy my files from source to any folder with the name *.mydomain.com
I tried rsync but couldn't do the *.mydomain part
I suggest:
for i in *.mydomain.com; do rsync -aSv "SOURCE/" "$i"; done
The trailing / after SOURCE is important.
You can use find command to search all files and then use this output to copy them, e.g. assuming you are searching in /home and copying to /target
find /home -name "*.mydomain.com" -exec cp -r {} /target/ \;
But one problem in above solution I see is it might find files / folders with these names and copy them none the less (not sure if it will maintain the same folder hierarchy), perhaps IF you are only looking for folder then try below instead,
find /home -name "*.mydomain.com" -type d -exec cp -r {} /target/ \;

How to delete a file in any of the directories or subdirectories except one subdirectory

I want to delete a file from a directory which contains many subdirectories but the deletion should not happen in one subdiretory(searc) whose name is already predefined but path varies as shown below.So now how to delete a file i am using the below command
find . -type f -name "*.txt" -exec rm -f {} \;
this command deletes all the files in the directory.So How can we delete the file without serching that subdirectory.
The subdirectory file name will be same but the path will different
for eg
Main
|
a--> searc
|
b-->x--->searc
|
c-->y-->x-->searc
now the
the subdirectory not to be searched can be present any where as shown above
I think you want the -prune option. In combination with a successful name match, this prevents descent into the named directories. Example:
% mkdir -p test/{a,b,c}
% touch test/{a,b,c}/foo.txt
% find test -name b -prune -o -name '*.txt' -print
test/a/foo.txt
test/c/foo.txt
I am not completely sure what you're asking, so I can give only somewhat generic advice.
You already know the -name option. This refers to the filename only. You can, however, also use -wholename (a.k.a. -path), which refers to the full path (beginning with the one given as first option to find).
So if you want to delete all *.txt files except in the foo/bar subdirectory, you can do this:
find . -type f -name "*.txt" ! -wholename "./foo/bar/*" -delete
Note the -delete option; it doesn't require a subshell, and is easier to type.
If you would like to exclude a certain directory name regardless of where in the tree it might be, just don't "root" it. In the above example, foo/bar was "rooted" to ./, so only a top-level foo/bar would match. If you write ! -wholename "*/foo/bar/*" instead (allowing anything before or after via the *), you would exclude any files below any directory foo/bar from the operation.
You can use xargs instead of the exec
find .... <without the --exec stuff> | grep -v 'your search' | xargs echo rm -f
Try this first. If it is satisfactory, you can remove the echo.

Problems using find and cp to copy just .jpg files from a LOT of directories to one new path

I tried the search, but couldn't find the answer to my specific problem.
When I use,
find /recovered_files "*.jpg" -type f -exec cp {} /out \;
to copy all .jpg files from directories within the /recovered_files directory, the /out directory gets filled with every single file (jpg, txt, xml etc etc) from within the source directories.
Can anyone please explain wherein my stupidity lies, pleeeeeease???
Many thanks, Mark.
What you're doing at the moment is equivalent to calling cp /dir/dir/dir/file.jpg /out for each file, which will copy the file into /out. Thus, all of the files are being put into the same directory.
rsync allows filters to select only certain files to be copied. Change from and to to the appropriate directories in the following:
rsync -r from/* to --include=*.jpg --filter='-! */' --prune-empty-dirs
Credit to this post for this solution.
Edit: changed to rsync solution. Original as follows:
find from -name "*.jpg" -type f -exec mkdir -p to/$(dirname {}) \; -exec cp --parents {} to \;
You should replace from and to with the appropriate locations, and this form won't quite work if from begins with /. Just cd to / first if you need to. Also, you'll end up with all the files inside to underneath the entire directory structure of from, but you can just move them back out again.

shell entering each folder and zip content

So I have some folder
|-Folder1
||-SubFolder1
||-SubFolder2
|-Folder2
||-SubFolder3
||-SubFolder4
Each subfolder contains several jpg I want to zip to the root folder...
I'm a little bit stuck on "How to enter each folder"
Here is my code:
find ./ -type f -name '*.jpg' | while IFS= read i
do
foldName=${PWD##*/}
zip ../../foldName *
done
The better would be to store FolderName+SubFolderName and give it to the zip command as name...
Zipping JPEGs (for Compression) is Usually Wasted Effort
First of all, attempting to compress already-compressed formats like JPEG files is usually a waste of time, and can sometimes result in archives that are larger than the original files. However, it is sometimes useful to do so for the convenience of having a bunch of files in a single package.
Just something to keep in mind. YMMV.
Use Find's -execdir Flag
What you need is the find utility's -execdir flag. The GNU find man page says:
-execdir command {} +
Like -exec, but the specified command is run from the subdirec‐
tory containing the matched file, which is not normally the
directory in which you started find.
For example, given the following test corpus:
cd /tmp
mkdir -p foo/bar/baz
touch foo/bar/1.jpg
touch foo/bar/baz/2.jpg
you can zip the entire set of files with find while excluding the path information with a single invocation. For example:
find /tmp/foo -name \*jpg -execdir zip /tmp/my.zip {} +
Use Zip's --junk-paths Flag
The zip utility on many systems supports a --junk-paths flag. The man page for zip says:
--junk-paths
Store just the name of a saved file (junk the path), and do not
store directory names.
So, if your find utility doesn't support -execdir, but you do have a zip that supports junking paths, you could do this instead:
find /tmp/foo -name \*jpg -print0 | xargs -0 zip --junk-paths /tmp/my.zip
You can use dirname to get the directory name of a file/directory it is located in.
You can also simplify the find command to search only for directories by using -type d. Then you should use basename to get only the name of the subdirs:
find ./*/* -type d | while read line; do
zip --junk-paths "$(basename $line)" $line/*.jpg
done
Explanation
find ./*/* -type d
will print out all directories located in ./*/* which will result in all subdirs of directories located in the current dir
while read line reads each line from the stream and stores it in the variable "line". Thus $line will be the relative path to the subdir, e.g. "Folder1/Subdir2"
"$(basename $line)" returns the only the name of the subdir, e.g. "Subdir2"
Update: add --junk-paths to the zip command if you do not want the directy paths to be stored in the zip filde
So a little check, I finally got something working:
find ./*/* -type d | while read line; do
#printf '%s\n' "$line"
zip ./"$line" "$line"/*.jpg
done
But this create un archive containing:
Subfolder.zip
Folder
|-Subfolder
||-File1.jpg
||-File2.jpg
||-File3.jpg
Instead I fold like it to be:
Subfolder.zip
|-File1.jpg
|-File2.jpg
|-File3.jpg
So I tried using basename and dirname in differnet combination...Always got some error...
And just to learn how to: what if I would like the new archive to be created in the same root directory as "Folder"?
Ok finally got it!
find ./* -name \*.zip -type f -print0 | xargs -0 rm -rf
find ./*/* -type d | while read line; do
#printf '%s\n' "$line"
zip --junk-paths ./"$line" "$line"/*.jpg
done
find . -name \*.zip -type f -mindepth 2 -exec mv -- '{}' . \;
In first row I simply remove all .zip files,
Then I zip all and in the final row I move all zip to the root directory!
Thanks everbody for your help!

Resources