Welcome to the Power Users community on Codidact!
Power Users is a Q&A site for questions about the usage of computer software and hardware. We are still a small site and would like to grow, so please consider joining our community. We are looking forward to your questions and answers; they are the building blocks of a repository of knowledge we are building together.
How to copy files preserving one directory up
Have
mkdir -p d1/d1_sd1/ d2/d2_sd1/
touch d1/d1_sd1/f1.txt d2/d2_sd1/f1.txt
.
├── d1
│ └── d1_sd1
│ └── f1.txt
└── d2
└── d2_sd1
└── f1.txt
4 directories, 2 files
Want
.
├── d1
│ └── d1_sd1
│ └── f1.txt
├── d1_sd1
│ └── f1.txt
├── d2
│ └── d2_sd1
│ └── f1.txt
└── d2_sd1
└── f1.txt
6 directories, 4 files
Question
How do I cp files with a pattern preserving one directory up from the match?
I'd expect a modification to this call:
cp -r d*/*/f1.txt .
Tried
cp -r --parents d*/*/f1.txt .
1 answer
The following users marked this post as Works for me:
User | Comment | Date |
---|---|---|
mcp | (no comment) | Oct 28, 2022 at 16:38 |
Assuming innermost directories are not empty, in any POSIX compliant system,
find . -type d -links 2 -exec cp -r {} . \;
In a GNU Linux system, a more performant alternative is
find . -type d -links 2 -exec cp -rt . {} +
since it only spawns an optimal number of cp
process (a single one if the size of the argument list is not large).
How does it work?
Leaf directories have only two hard links
Every directory in a Linux system is indexed with at least two hard links.
A leaf directory, by definition a directory without any sub-directory, has only two hard links, path/to/dir
and path/to/dir/.
.
On the other hand, a directory with one sub-directory would have an additional hard link, namely path/to/dir/subdir/..
.
Conclusion: The number h of hard links of a directory is h=s+2
, being s the number of sub-directories.
The -exec option
The -exec
option executes the corresponding command for each found file if ;
terminated or for the maximum number of files if +
terminated. So, for example, the first will spawn
cp -r d1_sd1 .
cp -r d3_sd2 .
while the latter will spawn
cp -rt . d1_sd1 d3_sd2
See that the latter is only possible because the -t
option, available in cp
from GNU coreutils, allows the target to be specified before the files to be copied. (-exec cp -r {} . +
is not valid!)
Before
$ tree
./
├── d1/
│ └── d1_sd1/
│ └── f1.txt
└── d3/
└── d3_sd1/
└── d3_sd2/
└── f1.txt
5 directories, 2 files
After
$ tree
./
├── d1/
│ └── d1_sd1/
│ └── f1.txt
├── d1_sd1/
│ └── f1.txt
├── d3/
│ └── d3_sd1/
│ └── d3_sd2/
│ └── f1.txt
└── d3_sd2/
└── f1.txt
7 directories, 4 files
2 comment threads