Copy everything except specific files - linux

How can I copy everything (files and directories(even if they are empty)) from one directory to another, except files ".php", and files with name "config.yml".
I need to do this with single command.
I have tried this one
find ./ -type f ! ( -name "*.php" -o -name "config.yml" ) -exec cp --parents -r -t /my/directory/ "{}" +
It works but if the directory have only files ".php", command will skip the directory and do not copy the empty one, but I need the directory even if it will be empty.

Sorry, I haven't enough reputation to put a comment, because I would like to ask you if the use of "find" is a requisite.
If is not, you can do it easily with the rsync command:
rsync -av --exclude=config.yml --exclude="*php" ORIGINFOLDER/ DESTFOLDER
Just change ORIGINFOLDER and DESTFOLDER for your folders name, and take a look at the man to see the meaning of the options.

Related

Linux Move txt files not start with String to Another folder

The situation is
I have a directory A, I have a bunch of files and folders in the foldler.
Such as folder B , foler C , tmp1.txt , Hello.txt , tmp3.txt , okay.txt.
And in folder B,there are also a bunch of files in it.
So I want to move all txt files recrusively to another folder such as /home.
Here is my code.
find . -name "*.txt"| grep -v [\s\S]*tmp[\s\S]* -exec mv {} /home \;
I can only select these files,however it won't execute move operation.
because linux find has path in result.So it annoy me a lot.
To move only regular files, add -type f and exclude the files you don't want with \!:
find . -type f -name '*.txt' \! -name '*tmp*' -exec mv -i -t /home {} +
The -i asks for permission to overwrite a file if it already exists and the + instead of the \; is used to move as many files as possible with one invocation of mv (and thus we need to specify the target directory with the -t option as {} contains more than one file).

Recursive find and copy to other directory

I need to find all files in a directory and it's subdirectories, but I need to keep directory structure. For example there is a file
/media/subdir1/subdir2/file.jpg
and I want to copy it to
/new-media/subdir1/subdir2/file.jpg
and the same to all files inside /media/ directory. And by the way, directories inside /new-media/ must be created if not exist.
if I use
find /media/ -name '*.jpg' -exec cp /new-media/ ????? {} \;
how can I get all subdirectories inside /media/?
The above will get you everything in /media, but to get exactly what you want you probably want to use something like:
Method 1: Copy only what you need recursively, per your requirements:
mkdir ../media2; find . -name "*.jpg" -exec cp -r --parents {} ../media2 \;
I ran this from inside the directory you want to search recursively. It does a couple things:
1 - create the new destination directory
mkdir ../media2
2 - then finds all files ending with ".jpg" recursively.
find . -name "*.jpg"
3 - uses -exec to pass the copy command to each file returned to find as a match, and subs that in as the first argument (which with the syntax of cp, is going to be your source file):
-exec cp -r --parents {} ../media2 \;
the "--parents" flag retains existing directory structure and recursively creates subsequent parent directories. Super useful right?
Method 2: there might be a better way to do this with xargs, but the above ended up being the most simple method imho. That said, if you want to think outside the box, you could simply copy the entire directory over recursively, then remove anything NOT ending with ".jpg" with something like:
cp -r media media2; find ./media '!'-name "*.jpg" -type f | xargs rm
I think this is what you want:
cp -r /media /new-media
-R, -r, --recursive
copy directories recursively
Hope this helps.

Linux: copy ".svn" directories recursively

I know there are dozen of questions about similar topcis but I still can't beat this up.
I need to copy all .svn directories recursively from /var/foo to /var/foo2 on a Debian machine:
/var/www/foo/.svn
/var/www/foo/bar/.svn
...
I tried these two commands without success:
find /var/foo -name ".svn" -type f -exec cp {} ./var/foo2 \;
find /var/foo -name ".svn" -type d -exec cp {} /var/foo2 \;
Once only the svn directory right inside foo is copied, while another time nothing is copied.
Given following file structure:
./
./a/
./a/test/
./a/test/2
./b/
./b/3
./test/
./test/1
Running following script in the directory to be copied:
find -type d -iname test -exec sh -c 'mkdir -p "$(dirname ~/tmp2/{})"; cp -r {}/ ~/tmp2/{}' \;
Should copy all test directories to ~/tmp2/.
Points of interest:
Directories are copied to the destination on a one-by-one basis
Parent directories are created in advance so that cp doesn't complain about target not existing
Rather than just cp, cp -r is used
The whole command is wrapped with sh -c so that operations on {} such as dirname can be performed (so that the shell expands it for each directory separately, rather than expanding it once during calling the find)
Resulting structure in ~/tmp2:
./
./a/
./a/test/
./a/test/2
./test/
./test/1
So all you should need to do is to replace test with .svn and ~/tmp2 with directory of choice. Just remember about running it in the source directory, instead of using absolute paths.
I find that using tar for such operations makes the code often much more readable:
$ mkdir /var/www/foo2
$ cd /var/www/foo2
$ find ../foo/ -type d -name .svn -exec tar c \{\} \+ | \
tar x --strip-components=1
find will list all directories named .svn, and call tar to create (c) an archive file (that is sent to stdout) with all these directories. the archive on stdout is then extracted (x) by another tar instance in the target directory. the relative path portion (../) is automatically removed by the archiving tar, but since we also want to remove the first path component (foo/) we need to add --strip-components.
Note: This will only work if you do not have very many .svn directories you want to copy (more than $(getconf ARG_MAX)-2, which on my system is more than 200000).

Howto replace a file in several sub-folders

I've a series of directories containing a set of files. There is a new copy of this file which I would like to replace all instances with. How can do this with find command?
Latest file is in /var/www/html is called update_user.php
There are 125 directories with several other files including a copy of update_user.php. I want to replace these with the one in update_user.php excluding itself.
This should do the job:
find /path/to/old/files -type f -name update_user.php -exec cp /path/to/new/update_user.php {} \;
You should check if the new file is not inside /path/to/old and if so than first copy it outside and use that copy but.. it'll not harm if you don't - one cp will fail with are the same file error.
You can use
cp -v to see what it does
cp -u to update only when source file is newer
echo cp to perform dry run
I would suggest to check first if all dest. files are the same with:
find /path/to/old/files -type f -name update_user.php -exec md5sum {} \;|awk '{print $1}'|sort|uniq

How to change all occurrences of a word in all files in a directory

I was in the process of creating a User class where one of the methods was get_privileges();.
After hours of slamming my head into the keyboard, I finally discovered that the previous coder who I inherited this particular database spelled the word "privileges" as "privelages" in the MySQL database, and thus also everywhere in the hundreds of files that access these "privelages" it is spelled that way.
Is there a way in Linux (Ubuntu Server) that I can go through every place in the /var/www folder and replace "privelages" with "privileges", so that I don't have to deal with this typo and code around it?
A variation that takes into account subdirectories (untested):
find /var/www -type f -exec sed -i 's/privelages/privileges/g' {} \;
This will find all files (not directories, specified by -type f) under /var/www, and perform a sed command to replace "privelages" with "privileges" on each file it finds.
Check this out: http://www.cyberciti.biz/faq/unix-linux-replace-string-words-in-many-files/
cd /var/www
sed -i 's/privelages/privileges/g' *
I generally use this short script, which will rename a string in all files and all directory names and filenames. To use it, you can copy the text below into a file called replace_string, run sudo chmod u+x replace_string and then move it into your sudo mv replace_string /usr/local/bin folder to be able to execute it in any directory.
NOTE: this only works on linux (tested on ubuntu), and fails on MacOS. Also be careful with this because it can mess up things like git files. I haven't tested it on binaries either.
#!/usr/bin/env bash
# This will replace all instances of a string in folder names, filenames,
# and within files. Sometimes you have to run it twice, if directory names change.
# Example usage:
# replace_string apple banana
echo $1
echo $2
find ./ -type f -exec sed -i -e "s/$1/$2/g" {} \; # rename within files
find ./ -type d -exec rename "s/$1/$2/g" {} \; # rename directories
find ./ -type f -exec rename "s/$1/$2/g" {} \; # rename files

Resources