Bash wildcard not expanding
A wildcard always expands to existing names.
Your command mkdir *
fails because the names that *
expands to already exists.
Your command mkdir *.d
"fails" because the *.d
does not match any existing names. The pattern is therefore left unexpanded by default1 and a directory called *.d
is created. You may remove this with rmdir '*.d'
.
To create a directory for each regular file in the current directory, so that the new directories have the same name as the files, but with a .d
suffix:
for name in ./*; do
if [ -f "$name" ]; then
# this is a regular file (or a symlink to one), create directory
mkdir "$name.d"
fi
done
or, for people that like "one-liners",
for n in ./*; do [ -f "$n" ] && mkdir "$n.d"; done
In bash
, you could also do
names=( ./* )
mkdir "${names[@]/%/.d}"
but this makes no checks for whether the things that the glob expands to are regular files or something else.
The initial ./
in the commands above are to protect against filenames that contain an initial dash (-
) in their filenames. The dash and the characters following it would otherwise be interpreted as options to mkdir
.
1 Some shells have a nullglob
shell option that causes non-matched shell wildcards to be expanded to an empty string. In bash
this is enabled using shopt -s nullglob
.
*.d
expands to the files whose name end in .d
.
With zsh
, you could do:
files=(*)
mkdir -- $^files.d
Or with an anonymous function:
() { mkdir -- $^argv.d; } *
Or adding the suffix via the e
glob qualifier:
mkdir -- *(e{REPLY+=.d})
Or the :s
history modifier applied to globs (with histsubstpattern
for %
to mean end):
set -o histsubstpattern
mkdir -- *(:s/%/.d)
You may also want not to do that for files that are already directories or symlinks to directories, by adding a ^-/
glob qualifier:
files=(*(^-/))
mkdir -- $^files.d
(note that zsh
doesn't have that misfeature of other Bourne-like shells where patterns that don't match are passed as-is, so mkdir *.d
would not create a *.d
directory if there was no file matching *.d
in the current directory, it would abort the command with an error instead)
Instead of for foo in bar; do baz; done
solution I would propose:
find . -maxdepth 1 -type f -print0|xargs -0 -I file mkdir file.d