Recently I had a little mishap caused by a shell pattern that expanded in an unexpected way.  I wanted to change the owner of a bunch of dot files in the /root directory, so I didchown -R root .*Naturally, the .* expanded to .. which was a bit of a disaster.I know in bash this behaviour can be changed by tweaking some shell option, but with the default settings is there any pattern that would expand to every dot file in the directory but not to . and ..?
Shell filename pattern that expands to dot files but not to `..`?
shell;filenames;wildcards;dot files
Bash, ksh and zsh have better solutions, but in this answer I assume a POSIX shell.The pattern .[!.]* matches all files that begin with a dot followed by a non-dot character. (Note that [^.] is supported by some shells but not all, the portable syntax for character set complement in wildcard patterns is [!.].) It therefore excludes . and .., but also files that begin with two dots. The pattern ..?* handles files that begin with two dots and aren't just ...chown -R root .[!.]* ..?*This is the classical pattern set to match all files:* .[!.]* ..?*A limitation of this approach is that if one of the patterns matches nothing, it's passed to the command. In a script, when you want to match all files in a directory except . and .., there are several solutions, all of them cumbersome:Use * .* to enumerate all entries, and exclude . and .. in a loop. One or both of the patterns may match nothing, so the loop needs to check for the existence of each file. You have the opportunity to filter on other criteria; for example, remove the -h test if you want to skip dangling symbolic links.for x in * .*; do  case $x in .|..) continue;; esac  [ -e $x ] || [ -h $x ] || continue  somecommand $xdoneA more complex variant where the command is run only once. Note that the positional parameters are clobbered (POSIX shells don't have arrays); put this in a separate function if this is an issue.set --for x in * .[!.]* ..?*; do  case $x in .|..) continue;; esac  [ -e $x ] || [ -h $x ] || continue  set -- $@ $xdonesomecommand $@Use the * .[!.]* ..?* triptych. Again, one or more of the patterns may match nothing, so we need to check for existing files (including dangling symbolic links).for x in * .[!.]* ..?*; do  [ -e $x ] || [ -h $x ] || continue  somecommand $xdoneUse the * .[!.]* ..?* tryptich, and run the command once per pattern but only if it matched something. This runs the command only once. Note that the positional parameters are clobbered (POSIX shells don't have arrays), put this in a separate function if this is an issue.set -- *[ -e $1 ] || [ -h $1 ] || shiftset -- .[!.]* $@[ -e $1 ] || [ -h $1 ] || shiftset -- ..?* $@[ -e $1 ] || [ -h $1 ] || shiftsomecommand $@Use find. With GNU or BSD find, avoiding recursion is easy with the options -mindepth and -maxdepth. With POSIX find, it's a little trickier, but can be done. This form has the advantage of easily allowing to run the command a single time instead of once per file (but this is not guaranteed: if the resulting command is too long, the command will be run in several batches).find . -name . -o -exec somecommand {} + -o -type d -prune