如何在bash中使用。*通配符但排除父目录(..)?

How to use the .* wildcard in bash but exclude the parent directory (..)?

有时我希望对目录中的所有文件(包括隐藏文件)执行命令。当我尝试使用

1
chmod g+w * .*

它更改了我想要的所有文件(在目录中)和父目录中的所有文件(我想单独使用)的权限。

是否有一个通配符可以执行正确的操作,或者我需要开始使用find?


您需要两个glob模式来覆盖所有潜在的"点文件":.[^.]*..?*

第一个字符将所有目录条目与两个或多个字符匹配,其中第一个字符是点,第二个字符不是点。第二个选择以..开头的三个或更多字符的条目(这不包括..,因为它只有两个字符,以.开头,但包括(不太可能)像..foo这样的条目)。

1
chmod g+w .[^.]* ..?*

这在大多数shell中都能很好地工作,并且适用于脚本。

对于常规的交互式使用,模式可能太难记住。对于这些情况,您的shell可能有一个更方便的方法来跳过...。zsh总是将....*这样的模式中排除。对于bash,必须使用globalignore shell变量。

1
2
3
# bash
GLOBIGNORE=.:..
echo .*

您可以考虑在一个bash定制文件中设置globalignore(例如.bash_profile/.bash_login.bashrc)。但是,如果您经常使用其他环境,请注意习惯于这种定制。如果您在缺少自定义的环境中运行类似于chmod g+w .*的命令,那么您将意外地在命令中包括...

此外,您可以将shell配置为在模式中包含不以显式点开头的"点文件"(例如*)。

1
2
3
4
5
6
7
8
9
# zsh
setopt glob_dots

# bash
shopt -s dotglob


# show all files, even"dot files"
echo *


我所做的是

1
tar --directory my_directory --file my_directory.tar --create `ls -A mydirectory/`

很好,ls -A my_directory扩展到目录中除...以外的所有内容。没有wierd globs,在一条线上。

附:也许有人会告诉我为什么这不是个好主意。P


通常我只使用. .[a-zA-Z0-9]*,因为我的文件名倾向于遵循某些规则,但这并不能捕获所有可能的情况。

你可以使用:

1
chmod g+w $(ls -1a | grep -v '^..$')

它基本上会列出所有的文件和目录,去掉父目录,然后处理其余的。但是要注意文件名中的空格,它会将它们视为单独的文件。

当然,如果您只想做文件,可以使用:

1
find . -maxdepth 0 -type f -exec chmod g+w {} ';'

或者,另一个解决方案,它应该处理除..之外的所有文件和目录:

1
for i in * .* ; do if [[ ${i} !=".." ]] ; then chmod g+w"$i"; fi done

但是现在你进入了一个需要脚本或别名的领域。


由于您可能不想为bash会话的其余部分设置dotglob,因此可以通过在这样的子进程中运行来为单个命令集设置它:

1
$ (shopt -s dotglob; chmod g+w ./*)

怎么样:

1
2
shopt -s dotglob
chmod g+w ./*

如果您确定永远不会使用两个字符的隐藏文件名,那么最简单的选择就是:

1
chmod g+w * ...*