A abordagem a seguir funciona para esse tipo de árvore de diretórios:
$ tree .
.
├── adir1
│ ├── afile1
│ ├── afile2
│ ├── afile3
│ └── afile4.txt
├── adir2
│ ├── afile1
│ ├── afile2
│ ├── afile3
│ └── afile4.txt
├── adir3
│ ├── afile1
│ ├── afile2
│ ├── afile3
│ └── afile4.txt
├── afile1
├── afile2
├── afile3
├── foo.test
Essa foi a solução que funcionou para esse cenário (que, acredito, é o caso mais geral).
$ find . -type f -not -path '*/\.*' -exec zip -r test.zip {} +
Exemplo
$ find . -type f -not -path '*/\.*' -exec zip -r test.zip {} +
updating: adir1/afile1 (stored 0%)
updating: adir1/afile1.zip (stored 0%)
updating: adir1/afile2 (stored 0%)
updating: adir1/afile3 (stored 0%)
updating: adir1/afile4.txt (stored 0%)
updating: adir2/afile1 (stored 0%)
updating: adir2/afile2 (stored 0%)
updating: adir2/afile3 (stored 0%)
updating: adir2/afile4.txt (stored 0%)
updating: adir3/afile1 (stored 0%)
updating: adir3/afile2 (stored 0%)
updating: adir3/afile3 (stored 0%)
updating: adir3/afile4.txt (stored 0%)
updating: afile1 (stored 0%)
updating: afile2 (stored 0%)
updating: afile3 (stored 0%)
updating: foo.test (deflated 87%)