The problem is that globs (the */
is a glob) are expanded by the shell before launching the command. And brace expansions happen before globs. What this means is that */{credits,links,notes}
becomes '*/credits' '*/links' '*/notes'
and then these globs are expanded by the shell, and because the files haven't been created yet, the globs are expanded to themselves.
You can see the same behavior with any glob that doesn't match anything. For example:
$ echo a*j
a*j
While when it does match:
$ touch abj
$ echo a*j
abj
Coming back to your case, because the files don't actually exist, the command you are running becomes:
touch '*/credits' '*/links' '*/notes'
If you create one of them, you can see that things change:
$ touch Psy/credits
$ touch */{credits,links,notes}
touch: cannot touch '*/links': No such file or directory
touch: cannot touch '*/notes': No such file or directory
Since we now have one file that does match the */credits
glob, the file Psy/credits
, that one works but the other two give errors.
The right way to do what you are attempting is something like this:
for d in */; do touch "$d"/{credits,links,notes}; done
Which results in:
$ tree
.
├── abj
├── Eng
│ ├── credits
│ ├── links
│ └── notes
├── IT
│ ├── credits
│ ├── links
│ └── notes
├── IT_workshop
│ ├── credits
│ ├── links
│ └── notes
├── LA
│ ├── credits
│ ├── links
│ └── notes
├── OS
│ ├── credits
│ ├── links
│ └── notes
├── OS_lab
│ ├── credits
│ ├── links
│ └── notes
├── Psy
│ ├── credits
│ ├── links
│ └── notes
├── Python
│ ├── credits
│ ├── links
│ └── notes
└── Python_lab
├── credits
├── links
└── notes