Recursive copy of a specific file type maintaining the file structure in Unix/Linux? [closed] - linux

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I need to copy all *.jar files from a directory maintaining the folder structure of the parent directories. How can I do it in UNIX/Linux terminal?
The command cp -r *.jar /destination_dir is not what I am looking for.

rsync is useful for local file copying as well as between machines. This will do what you want:
rsync -avm --include='*.jar' -f 'hide,! */' . /destination_dir
The entire directory structure from . is copied to /destination_dir, but only the .jar files are copied. The -a ensures all permissions and times on files are unchanged. The -m will omit empty directories. -v is for verbose output.
For a dry run add a -n, it will tell you what it would do but not actually copy anything.

If you don't need the directory structure only the jar files, you can use:
shopt -s globstar
cp **/*.jar destination_dir
If you want the directory structure you can check cp's --parents option.

If your find has an -exec switch, and cp an -t option:
find . -name "*.jar" -exec cp -t /destination_dir {} +
If you find doesn't provide the "+" for parallel invocation, you can use ";" but then you can omit the -t:
find . -name "*.jar" -exec cp {} /destination_dir ";"

cp --parents `find -name \*.jar` destination/
from man cp:
--parents
use full source file name under DIRECTORY

tar -cf - `find . -name "*.jar" -print` | ( cd /destination_dir && tar xBf - )

If you want to maintain the same directory hierarchy under the destination, you could use
(cd SOURCE && find . -type f -name \*.jar -exec tar cf - {} +) \
| (cd DESTINATION && tar xf -)
This way of doing it, instead of expanding the output of find within back-ticks, has the advantage of being able to handle any number of files.

find . -name \*.jar | xargs cp -t /destination_dir
Assuming your jar filenames do not contain spaces, and your cp has the "-t" option. If cp can't do "-t"
find . -name \*.jar | xargs -I FILE cp FILE /destination_dir

Related

Find and move files to appropriate directories using shell script

I have below setup and I want to find and move files.
I have files /home/backup/abc/123.wav and /home/backup/xyz/456.wav.
Same directories exist at /usr/src/abc and /usr/src/xyz which does not have any files.
I want to find .wav files from home_dir and move them to particular dest_dir.
So 123.wav should move to /usr/src/abc and 456.wav should move to /usr/src/xyz.
I am using below command for that.
home_dir=/home/backup/
dest_dir=/usr/src/
cd $home_dir && find . -iname "*.wav" -exec mv {} $dest_dir \;
But all the .wav files(123.wav and 456.wav) moved to /usr/src and not to its respective directories(/usr/src/abc and /usr/src/xyz).
Is it possible to achieve what I want ?
Please suggest.
Use cp --parents option with find to create parent directories of each file being copied:
home_dir=/home/backup/
dest_dir=/usr/src/
cd "$home_dir"
find . -iname "*.wav" -exec cp --parents {} "$dest_dir" \; -delete
This would be a lot easier if mv had a --parents option, but unfortunately it doesn't. It's best to use mv instead of cp because cp will copy all the data unnecessarily if the source and destination directories are on the same filesystem. if you've got Bash 4 (which supports globstar) you could do it like this:
home_dir=/home/backup/
dest_dir=/usr/src/
shopt -s globstar nullglob dotglob
for src_wav in "$home_dir"/**/*.wav ; do
rel_wav=${src_wav#$home_dir/}
dst_wav=$dest_dir/$rel_wav
dst_parent=${dst_wav%/*}
[[ -d $dst_parent ]] || mkdir -p -- "$dst_parent"
mv -- "$src_wav" "$dst_wav"
done

linux commands to search a given folder

I have a folder in ~/Downloads with lots of
files and folders scattered. This consists of various files of different
extensions. I need to copy only the
.pdf files within various directories to ~/pdfs
Use find:
find ~/Downloads -type f -name "*.pdf" -exec cp {} ~/pdfs \;
if ~/pdfs exists in your system use the following command
cd ~/Downloads ; cp -r *.pdf ~/pdfs
if ~/pdfs does not exists in your system use the following command
cd ~/Downloads ; mkdir ~/pdfs ; cp -r *.pdf ~/pdfs
In order to deal with potential file names with spaces, etc., I would recommend this approach:
find ~/Downloads/. -type f -name "*.pdf" -print0 | xargs -0 -I_ cp _ ~/pdfs/.

How do I use find to copy and remove extensions keeping the same subdirectory structure [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'm trying to copy all the files from one directory to another, removing all file extensions at the same time.
From directory 0001:
0001/a/1.jpg
0001/b/2.txt
To directory 0002:
0002/a/1
0002/b/2
I've tried several find ... | xargs c...p with no luck.
Recursive copies are really easy to to with tar. In your case:
tar -C 0001 -cf - --transform 's/\(.\+\)\.[^.]\+$/\1/' . |
tar -C 0002 -xf -
If you haven't tar with --transform this can works:
TRG=/target/some/where
SRC=/my/source/dir
cd "$SRC"
find . -type f -name \*.\* -printf "mkdir -p '$TRG/%h' && cp '%p' '$TRG/%p'\n" |\
sed 's:/\.::;s:/./:/:' |\
xargs -I% sh -c "%"
No spaces after the \, need simple end of line, or you can join it to one line like:
find . -type f -name \*.\* -printf "mkdir -p '$TRG/%h' && cp '%p' '$TRG/%p'\n" | sed 's:/\.::;s:/./:/:' | xargs -I% sh -c "%"
Explanation:
the find will find all plain files what have extensions in you SRC (source) directory
the find's printf will prepare the needed shell commands:
command for create the needed directory tree at the TRG (target dir)
command for copying
the sed doing some cosmetic path cleaning, (like correcting /some/path/./other/dir)
the xargs will take the whole line
and execute the prepared commands with shell
But, it will be much better:
simply make an exact copy in 1st step
rename files in 2nd step
easier, cleaner and FASTER (don't need checking/creating the target subdirs)!
Here's some find + bash + install that will do the trick:
for src in `find 0001 -type f` # for all files in 0001...
do
dst=${src/#0001/0002} # match and change beginning of string
dst=${dst%.*} # strip extension
install -D $src $dst # copy to dst, creating directories as necessary
done
This will change the permission mode of all copied files to rwxr-xr-x by default, changeable with install's --mode option.
I came up with this ugly duckling:
find 0001 -type d | sed 's/^0001/0002/g' | xargs mkdir
find 0001 -type f | sed 's/^0001//g' | awk -F '.' '{printf "cp -p 0001%s 0002%s\n", $0, $1}' | sh
The first line creates the directory tree, and the second line copies the files. Problems with this are:
There is only handling for directories and regular files (no
symbolic links etc.)
If there are any periods (besides the
extension) or special characters (spaces, etc.) in the filenames
then the second command won't work.

Create file in Linux and replace content

I have a project in Linux. I want to create a file named index.html in all folders.
So I have used the following command:
find . -type d -exec touch {}/index.html \;
It's working! Now I'm trying to copy the existing file from a given location and it to be automatically replaced into all the folders of my project.
This should actually work exactly in the same way:
find . -type d -exec cp $sourcedir/index.html {}/index.html \;
If I understand your question correctly, what you want is to copy a given file in all the directories.
You can use a similar find command :
find . -type d -exec cp -f /tmp/index.html {} \;
where /tmp/index.html is path to the original file (replace it with your own path).
Also, you don't need to create the files if your final objective is to replace them with the original file.
tar -cvzf index.tar.gz `find . -type f -iname 'index.html'` && scp index.tar.gz USER#SERVER:/your/projec/root/on/SERVER && ssh USER#SERVER "tar -xvzf index.tar.gz"
Or if you're in the proper directory localhost, and rsync is available:
rsync -r --exclude='**' --include='**/index.html' . USER#SERVER:/your/projec/root/on/SERVER
HTH

Copy folder structure (without files) from one location to another

I want to create a clone of the structure of our multi-terabyte file server. I know that cp --parents can move a file and it's parent structure, but is there any way to copy the directory structure intact?
I want to copy to a linux system and our file server is CIFS mounted there.
You could do something like:
find . -type d > dirs.txt
to create the list of directories, then
xargs mkdir -p < dirs.txt
to create the directories on the destination.
cd /path/to/directories &&
find . -type d -exec mkdir -p -- /path/to/backup/{} \;
Here is a simple solution using rsync:
rsync -av -f"+ */" -f"- *" "$source" "$target"
one line
no problems with spaces
preserve permissions
I found this solution there
1 line solution:
find . -type d -exec mkdir -p /path/to/copy/directory/tree/{} \;
I dunno if you are looking for a solution on Linux. If so, you can try this:
$ mkdir destdir
$ cd sourcedir
$ find . -type d | cpio -pdvm destdir
This copy the directories and files attributes, but not the files data:
cp -R --attributes-only SOURCE DEST
Then you can delete the files attributes if you are not interested in them:
find DEST -type f -exec rm {} \;
This works:
find ./<SOURCE_DIR>/ -type d | sed 's/\.\/<SOURCE_DIR>//g' | xargs -I {} mkdir -p <DEST_DIR>"/{}"
Just replace SOURCE_DIR and DEST_DIR.
The following solution worked well for me in various environments:
sourceDir="some/directory"
targetDir="any/other/directory"
find "$sourceDir" -type d | sed -e "s?$sourceDir?$targetDir?" | xargs mkdir -p
This solves even the problem with whitespaces:
In the original/source dir:
find . -type d -exec echo "'{}'" \; > dirs2.txt
then recreate it in the newly created dir:
mkdir -p <../<SOURCEDIR>/dirs2.txt
Substitute target_dir and source_dir with the appropriate values:
cd target_dir && (cd source_dir; find . -type d ! -name .) | xargs -i mkdir -p "{}"
Tested on OSX+Ubuntu.
If you can get access from a Windows machine, you can use xcopy with /T and /E to copy just the folder structure (the /E includes empty folders)
http://ss64.com/nt/xcopy.html
[EDIT!]
This one uses rsync to recreate the directory structure but without the files.
http://psung.blogspot.com/2008/05/copying-directory-trees-with-rsync.html
Might actually be better :)
A python script from Sergiy Kolodyazhnyy
posted on Copy only folders not files?:
#!/usr/bin/env python
import os,sys
dirs=[ r for r,s,f in os.walk(".") if r != "."]
for i in dirs:
os.makedirs(os.path.join(sys.argv[1],i))
or from the shell:
python -c 'import os,sys;dirs=[ r for r,s,f in os.walk(".") if r != "."];[os.makedirs(os.path.join(sys.argv[1],i)) for i in dirs]' ~/new_destination
FYI:
Copy top level folder structure without copying files in linux
How do I copy a directory tree but not the files in Linux?
Another approach is use the tree which is pretty handy and navigating directory trees based on its strong options. There are options for directory only, exclude empty directories, exclude names with pattern, include only names with pattern, etc. Check out man tree
Advantage: you can edit or review the list, or if you do a lot of scripting and create a batch of empty directories frequently
Approach: create a list of directories using tree, use that list as an arguments input to mkdir
tree -dfi --noreport > some_dir_file.txt
-dfi lists only directories, prints full path for each name, makes tree not print the indentation lines,
--noreport Omits printing of the file and directory report at the end of the tree listing, just to make the output file not contain any fluff
Then go to the destination where you want the empty directories and execute
xargs mkdir < some_dir_file.txt
find source/ -type f | rsync -a --exclude-from - source/ target/
Copy dir only with associated permission and ownership
Simple way:
for i in `find . -type d`; do mkdir /home/exemplo/$i; done
cd oldlocation
find . -type d -print0 | xargs -0 -I{} mkdir -p newlocation/{}
You can also create top directories only:
cd oldlocation
find . -maxdepth 1 -type d -print0 | xargs -0 -I{} mkdir -p newlocation/{}
Here is a solution in php that:
copies the directories (not recursively, only one level)
preserves permissions
unlike the rsync solution, is fast even with directories containing thousands of files as it does not even go into the folders
has no problems with spaces
should be easy to read and adjust
Create a file like syncDirs.php with this content:
<?php
foreach (new DirectoryIterator($argv[1]) as $f) {
if($f->isDot() || !$f->isDir()) continue;
mkdir($argv[2].'/'.$f->getFilename(), $f->getPerms());
chown($argv[2].'/'.$f->getFilename(), $f->getOwner());
chgrp($argv[2].'/'.$f->getFilename(), $f->getGroup());
}
Run it as user that has enough rights:
sudo php syncDirs.php /var/source /var/destination

Resources