How to copy files and folders excluding some of them
Topic written in response to a similar one .
The author of the original topic suggests solving the problem head-on - namely, copy all the files and then delete the ones that are not needed. This can be a good solution, if you, of course, do not need to copy the entire home folder to a USB flash drive, except for your video collection.
But the main problem of this approach is different - it does not correspond to the unix ideology: complex tasks are solved by a combination of simple utilities.
Under cat details about methods for solving this class of problems - do not consider this as a ready-made recipe.
The solution to any complex problem begins with its analysis into its component parts. So we need to copy some set of files by filtering it first.
So - getting a list of files, filtering, copying.
Usually we look at the list of files with ls. Her output looks something like this:
Is there such a conclusion? No, because there is not enough information in it - we need to copy files recursively, which means it would be much more convenient for us if the first program in our chain returned file names there along with paths.
The next program that comes to mind is find
Better already, but the directories also got into the output, but we do not need them. Let's try this:
Here is what you need there. List of files.
This list of files needs to be filtered. Redirect the output of our previous command to the grep program.
Well, but in the conditions of the task it is worth excluding files, so let's change our pipeline a little
The first two parts are completed.
From the man page for the cp command, we can find out that the source file must be passed to the cp program as an argument, while for now we can only redirect the list to standard input .
Let's use the xargs utility - it accepts standard input and calls the specified program with parameters from standard input. So:
-n 1 means that only one line from standard input is substituted into the command, and -I% - defines the character that will be replaced in the target command with a line from standard input. In our case, it will be
We can assume that the problem is solved.
I hope that this description will help to correctly approach the solution of both such simple and more complex tasks.
I would like to note that
The author of the original topic suggests solving the problem head-on - namely, copy all the files and then delete the ones that are not needed. This can be a good solution, if you, of course, do not need to copy the entire home folder to a USB flash drive, except for your video collection.
But the main problem of this approach is different - it does not correspond to the unix ideology: complex tasks are solved by a combination of simple utilities.
Under cat details about methods for solving this class of problems - do not consider this as a ready-made recipe.
0. Decomposition
The solution to any complex problem begins with its analysis into its component parts. So we need to copy some set of files by filtering it first.
So - getting a list of files, filtering, copying.
1. Getting a list of files
Usually we look at the list of files with ls. Her output looks something like this:
$ ls-1
dir1
dir2
file1.bin
file2.txt
Is there such a conclusion? No, because there is not enough information in it - we need to copy files recursively, which means it would be much more convenient for us if the first program in our chain returned file names there along with paths.
The next program that comes to mind is find
$ find ./
./
./dir1
./dir1/file7.txt
./dir2
./file1.bin
./file2.txt
Better already, but the directories also got into the output, but we do not need them. Let's try this:
$ find ./ -type'f'
./dir1/file7.txt
./file1.bin
./file2.txt
Here is what you need there. List of files.
2. Filtering
This list of files needs to be filtered. Redirect the output of our previous command to the grep program.
$ find ./ -type'f' | grep 2
./dir2
./file2.txt
Well, but in the conditions of the task it is worth excluding files, so let's change our pipeline a little
$ find ./ -type'f' | grep -v 2
./dir1/file7.txt
./file1.bin
The first two parts are completed.
3. Copy
From the man page for the cp command, we can find out that the source file must be passed to the cp program as an argument, while for now we can only redirect the list to standard input .
Let's use the xargs utility - it accepts standard input and calls the specified program with parameters from standard input. So:
$ find ./ -type'f' | grep -v 2 | xargs -n 1 -I % cp --parents "%" /path/to/dest/dir/
-n 1 means that only one line from standard input is substituted into the command, and -I% - defines the character that will be replaced in the target command with a line from standard input. In our case, it will be
cp --parents "./dir1/file7.txt" /path/to/dest/dir/
cp --parents "./file1.bin" /path/to/dest/dir/
We can assume that the problem is solved.
Instead of a conclusion
I hope that this description will help to correctly approach the solution of both such simple and more complex tasks.
I would like to note that
- This is a topic for solving problems and a little about using a pipeline, not about copying files.
- This method is far from the only and not even the shortest, but the most obvious for demonstrating the solution methodology.
- In the case of this specific task, it will be faster to use
find ./ -type f ! -name "*2*" -exec cp --parents -t /target/dir "{}" \+ - Personally, I would use
tar --exclude=2 -cf - ./ | ( cd /path/to/dest/ && tar -xvf - ) - Because this is my first topic, I will be glad to constructive criticism