I am aware of using .[!.]*
to refer to all dotfiles in a directory with the exception of ..
, but how might one refer to all dotfiles except for ..
and .git
? I have tried several variations on .[!.||.git]*
and .[!.][!.git]*
and the like, but none refer to the intended files.

- 829,060

- 15,864
4 Answers
You can use find :
find . -type f '!' -iname ".git" -exec cp -rv {} /dest/path \;
It will search all files in current directory and but not include .git
as we used ! -iname
( where !
means not equal to) then it will copy file to destination location
Update
find . -not -path '.' -not -path './.git' -iname '.*'
also we can use -iregex
in find
find . -not -iregex '.\|./.git' -iname '.*'
both example will refer to all dotfiles except for ..
and .git
in current path

- 24,711
-
Thanks. This does not work, and it took me a long time to figure out why. It turns out that
-iname
relates only to the name of the file, not to any of the names of directories in the files' paths. – dotancohen Sep 17 '13 at 10:29 -
-
-not
is a non-standard extension. The standard equivalent is!
which when on its own like that doesn't need to be quoted in any shell.-iname
and-iregex
are also non-standard extensions and the OP said nothing about preserving a.GIT
or.Git
file. Also beware it will still report hidden hidden files in the.git
directory, and.
is a regex operator so the last one will also exclude a./agit
file for instance. – Stéphane Chazelas Dec 17 '23 at 09:02
If you want to find all hidden files (which includes the files whose name starts with .
and those in directories whose name starts with .
recursively) recursively except for .git
and any hidden files within, you can do:
LC_ALL=C find . -path ./.git -prune -o -path '*/.*' -print
To copy those elsewhere, you want to stop find
searching inside those hidden directories:
LC_ALL=C find . -path ./.git -prune -o -name '.?*' -prune -exec sh -c '
exec cp -Rip "$@" /path/to/destination/' {} +
(the -i
option so the user be prompted when both ./foo/.file
and ./bar/.file
end up copied as /path/to/destination/.file
).
With the GNU implementation of cp
, sh
can be avoided with its -t
option:
LC_ALL=C find . -path ./.git -prune -o -name '.?*' -prune \
-exec exec cp -ait /path/to/destination/ {} +
Those only skip the top-level .git
directory/file. To skip any .git
file, even those in sub-directories, replace -path ./.git
with -name .git
.

- 544,893
In zsh like in the Forsyth shell and derivatives (pdksh and derivatives such as mksh), .
and ..
are never included in its glob expansions, so to list .*
files in the current working directory except .git
, also excluding the special .
and ..
navigation entries on one column, you can do:
set -o extendedglob
print -rC1 .^git(N)
.
and ..
also excluded by default in bash
since version 5.2 unless the globskipdots option is turned off. The extended glob syntax there is shaped after that of ksh88, and bash has no builtin command to print
on 1
C
olumn and the N
ullglob option cannot be turned on a per-glob basis with glob qualifiers, so the equivalent would have to be something like:
println() { [ "$#" -eq 0 ] || printf '%s\n' "$@"; }
shopt -s extglob nullglob
println .!(git)
In older versions, .
and ..
can be included in glob expansions, unless the dotglob option is enabled and the .
is not matched explicitly, so in those older versions, you can do:
println() { [ "$#" -eq 0 ] || printf '%s\n' "$@"; }
shopt -s extglob nullglob dotglob
println [.]!(git)
[.]
instead of .
so the match is not explicit.
Or exclude them explicitly with:
println() { [ "$#" -eq 0 ] || printf '%s\n' "$@"; }
shopt -s extglob nullglob
println .!(|.|git)
ksh93 skips .
and ..
by itself since ksh93u+m 2020-08-09. Since ksh93s, it also has ~(N)
as an equivalent to zsh's N
glob qualifier.
function println { [ "$#" -eq 0 ] || printf '%s\n' "$@"; }
println ~(N).!(git)
In older versions, you can do:
function println { [ "$#" -eq 0 ] || printf '%s\n' "$@"; }
FIGNORE=.:..
println ~(N).!(git)
Beware though that setting FIGNORE
means hidden files are no longer excluded from globs, so setting it to .:..
has the same effect as setting the dotglob
option in zsh or bash5.2+.
bash has a GLOBIGNORE
variable as something similar to ksh's FIGNORE
, but its design is pretty broken so I don't recommend using it.
Of course, you can also exclude them explicitly with:
function println { [ "$#" -eq 0 ] || printf '%s\n' "$@"; }
println ~(N).!(git)

- 544,893
cp
to exclude only..
and.git
as OP wants – Rahul Patil Sep 17 '13 at 09:14ls -la .[!(|.|.git)]*
. – dotancohen Sep 17 '13 at 10:36.
? – choroba Sep 17 '13 at 10:44