My goal is to find all files named README.md
in sub-folders, and to copy them in an output
folder, using the name of their original folder as their new name.
Ok that sounds complicated. Let's see a concrete example:
baselines
├── combined_tree_local_conflict_obs
│ ├── README.md
│ └── sparse_small_apex_maxdepth2_spmaxdepth30.yaml
└── global_density_obs
├── README.md
└── sparse_small_apex_expdecay_maxt1000.yaml
I want to copy the README.md
files to the output
folder with the names combined_tree_local_conflict_obs.md
and global_density_obs.md
.
So in the end I'd have:
baselines
├── output
│ ├── combined_tree_local_conflict_obs.md
│ └── global_density_obs.md
├── combined_tree_local_conflict_obs
│ ├── README.md
│ └── sparse_small_apex_maxdepth2_spmaxdepth30.yaml
└── global_density_obs
├── README.md
└── sparse_small_apex_expdecay_maxt1000.yaml
I don't understand why my bash command doesn't work:
$ find baselines -type f -name "README.md" -exec echo output/$(basename $(dirname {})).md \;
output/..md
output/..md
(I'm not copying the files yet but just printing their new path to debug the command.)
The find command does work:
$ find baselines -type f -name "README.md" -exec echo {} \;
baselines/combined_tree_local_conflict_obs/README.md
baselines/global_density_obs/README.md
Extracting the folder name does work:
$ echo $(basename $(dirname "baselines/combined_tree_local_conflict_obs/README.md"))
combined_tree_local_conflict_obs
But! somehow when I put them together it doesn't work.
I'm not so much interested in how to solve this problem in another way, but rather to understand why my command doesn't work.
Like Charles Duffy explain in comments,
$(basename $(dirname {}))
runs before find even starts. It can't possibly operate on the names of the specific files that were found.
I have some better solutions...
First:
cd baselines
Then, like this to re-use your code:
find . -type f -name "README.md" -exec bash -c '
echo cp "$1" "./output/$(dirname "$1").md"
' -- {} \;
or
find . -type f -name "README.md" -exec bash -c '
for file; do
echo cp "$file" "./output/$(dirname "$file").md"
done
' -- {} +
Check https://mywiki.wooledge.org/UsingFind
or
for file in */README.md; do
echo cp "$file" "./output/$(dirname "$file").md"
done
Drop the echo
command when the output looks good for you (don't try to feed bash STDIN
).
cp ./combined_tree_local_conflict_obs/README.md ./output/./combined_tree_local_conflict_obs.md
cp ./global_density_obs/README.md ./output/./global_density_obs.md