find
is probably the tool you're looking for. You can use it to find each directory that is named hooks
and resides under your ~/repos/
folder. For each such directory that find
locates, you tell it to copy your file there.
This will cause one error message for the myrepo
repo when it tries to copy a file to itself, but that error can be ignored.
cd ~/repos/myrepo/.git/hooks
find ~/repos/ -type d -name hooks -exec cp -vp prepare-commit-msg {} \;
This command can be improved to handle cases of odd characters in directories or filenames, but that's the gist of it.
As for why your original cp
command doesn't work, there's probably a question that explains it better, but it's because the shell expands your command to become:
cp prepare-commit-msg ~/repos/repo_A/.git/hooks ~/repos/repo_B/.git/hooks ~/repos/repo_C/.git/hooks ~/repos/repo_D/.git/hooks ~/repos/repo_E/.git/hooks
and given that syntax, cp
thinks that you want it to copy the file prepare-commit-msg
and four directories ~/repos/repo_A/.git/hooks
through ~/repos/repo_D/.git/hooks
and place all of the copied files/directories in ~/repos/repo_E/.git/hooks
. That is NOT what you want to do, of course, but cp
is telling you that it won't copy directories recursively unless you use the -r
option.
If you want to structure your solution somewhat like your original syntax, you could use:
cd ~/repos/myrepo/.git/hooks
dirs=( ~/repos/*/.git/hooks )
for d in "${dirs[@]}"
do
cp -vp prepare-commit-msg "$d/"
done
Methods which involve parsing the output of ls
are not recommended.