Patterns are matched by the shell, not by the command, so what you tried had no chance to work: first the shell expands
* to all files (not just the extensionless ones: you never said anything about the files not having a
. in their name), and
*.md to all files whose name in
.md; then the shell passes the concatenation of the two lists to the
In zsh, run the following command once (put them in your
~/.zshrc for the future):
autoload -U zmv
# you don't need the following two now, but put them also in your .zshrc
alias zcp='zmv -C'
alias zln='zmv -L'
You can then run
zmv to rename files according to a pattern. Both the pattern and the replacement text need to be quoted so that they are passed-as is to the
zmv function which will expand them in due course.
zmv '^*.*' '$f.md'
Note the single quotes around both arguments: the pattern and the replacement expression must be passed literally to the
^*.* means all files except the ones matching
*.*, it's a shortcut for
*~*.* (both are zsh extensions to the traditional pattern syntax). If you want to use this pattern outside
zmv, you need to run
setopt extended_glob first (put that in your
Bash has no such convenient tool, so you have to resort to a loop. First, activate ksh globbing extensions; that's something you should put in yout
shopt -s extglob
Now you can use the
!(PATTERN) operator to match extensionless files.
for x in !(*.*); do
mv -- "$x" "$x.md"
The double quotes arond
$x are necessary in case the file names contain whitespace or globbing characters. The
-- after the command name is necessary in case a file name begins with
In any shell
If you don't have the
!(…) operator, you can loop over all files and test each file name inside the loop.
for x in *; do
case "$x" in
*.*) ;; # skip this file
*) mv -- "$x" "$x.md";;