The topic is written in response to
similar .
The author of the original topic offers to solve the problem in the forehead - namely, copy
all the files and then delete unnecessary ones. This may be a good solution if you, of course, do not need to copy your entire home folder to a USB flash drive, with the exception of 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 the cat details about the methods of solving this class of problems - do not consider this as a ready-made recipe.
0. Decomposition
The solution of any complex task begins with parsing it into its component parts. So we need to copy some set of files by filtering it beforehand.
So - getting a list of files, filtering, copying.
1. Getting a list of files
Usually we review the file list with the ls program. Its output looks 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 produced the names of the files there along with the paths.
The next program that comes to mind is find
$ find ./ ./ ./dir1 ./dir1/file7.txt ./dir2 ./file1.bin ./file2.txt
Already better, but the directories were also included in the output, but we don’t 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 file list needs to be filtered.
Redirect the output of our previous command to the grep program.
$ find ./ -type 'f' | grep 2 ./dir2 ./file2.txt
Good, but under the conditions of the task it is worth
excluding the files, so a little change our
pipeline $ find ./ -type 'f' | grep -v 2 ./dir1/file7.txt ./file1.bin
The first two parts are completed.
3. Copying
From the
man page for the
cp command, we can find out that the source file needs to be passed to the cp program as an argument, but 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 the 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 the standard input is inserted into the command, and -I% defines the character that will be replaced in the target command by the line from the 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 conclusion
I hope that this description will help to properly approach the solution of such simple as well as more complex tasks.
It should be noted that
- This is a topic on how to solve problems and a little about the use of the pipeline, and not about copying files.
- This method is far from being the only or even the shortest, but the most obvious to demonstrate the methodology of the solution.
- In the case of this particular task, it will be faster to use
find ./ -type f ! -name "*2*" -exec cp --parents -t /target/dir "{}" \+
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 - )
tar --exclude=2 -cf - ./ | ( cd /path/to/dest/ && tar -xvf - )
- Because This is my first topic, I will be glad to constructive criticism