我试图理解 Linux、它的命令行和这句话:
您可能会遇到全局问题,因为
.*
匹配.
and..
(当前目录和父目录)。您可能希望使用诸如.[^.]*
或 之类的模式.??*
来获取所有点文件 除了当前目录和父目录。
来源:Linux 的工作原理:每个超级用户都应该知道什么 作者:布莱恩·沃德,第二版,
第 2.7 节“点文件”,第 23 页 (需要注册/登录)
或 Linux 的工作原理:每个超级用户都应该知道什么 作者:布莱恩·沃德,第三版,
第 2.7 节“点文件”,第 22 页
您究竟何时(在什么命令中)使用.[^.]*
or .??*
?
答案1
这是为了解决除zsh
,fish
以及 Forsyth shell 的后代(包括pdksh
和 衍生物)之外的 shell 中的错误/错误功能,其中 glob 的扩展.*
包括.
和..
(在系统上(不幸的是,在readdir()
返回它们的系统上)
有了这些贝壳,
chmod -R og-rwx .*
例如,将递归地删除当前 ( .
) 和父 ( ..
) 目录的 rwx 权限,而不仅仅是当前目录中的隐藏文件和目录。
ls .*
对于递归执行操作或作用于、chown -R .*
、等目录的命令来说find .*
,这尤其糟糕,grep -r blah .*
但对于大多数其他命令来说,它仍然很烦人,而且我想不出任何您希望拥有这些命令.
并..
包含在文件列表中的命令传递给他们。
必须在rm
实用程序中添加保障措施解决这个错误,因为太多人被绊倒了rm -rf .*
。
添加后*
,它还用于将所有文件(隐藏或不隐藏)作为参数传递给命令 ( cmd -- .[!.]* ..?* *
),其中根据 shell,您会找到其他解决方法。
glob .[^.]*
(.[!.]*
在 Bourne/POSIX shell 中)排除.
(因为它匹配至少有两个字符的文件名) 和..
(因为第二个字符是.
不匹配的[^.]
),但也排除像 之类的文件..foo
,您需要第二个 glob ..?*
。
这些.
和..
是目录遍历的工具,将它们像普通文件一样列出是错误的。 POSIX 要求它们在路径组件中被理解(如在open(".")
,中stat("foo/../bar")
),但不一定被实现为目录条目,也不一定包含在 中readdir()
。
尽管如此,大多数系统仍然像早期的 Unices 那样实现硬链接,并且大多数不这样做的系统仍然会在getdents()
/的输出中为它们伪造条目readdir()
。
对于bash
,另一种方法是打开该dotglob
选项并使用:
chmod -R og-rwx [.]*
(但请注意,如果没有非隐藏文件,它可能会更改[.]*
文件的权限,除非您可以选择模仿/failglob
的行为)。zsh
fish
作为历史记录,以.
隐藏文件开头的文件名是诞生于某人试图跳过的编码错误.
,并且..
首先。具有讽刺意味的是,当尝试使用隐藏文件执行操作时,我们会遇到同样的问题。
¹ 另请参阅globskipdots
bash 5.2+ 中的选项
答案2
当您想要将所有具有隐藏名称(以点开头)的文件和目录移动到另一个位置时:
mv .[^.]* old-dot-files/
或者,每当您想对目录中的所有点文件或点目录执行任何操作时:
for name in .[^.]*; do
# process "$name"
done
请注意,该模式.??*
要求匹配的名称至少包含三个字符,因此.a
不会选取类似的名称。 .[^.]*
另一方面,将跳过名称开头带有双点的任何内容。
显式测试匹配的名称可能会更好:
for name in .*; do
# expecting a regular file
if [ -f "$name" ]; then
# process "$name"
fi
done
for name in .*; do
# expecting a directory other than . and ..
if [ -d "$name" ] && [ "$name" != '.' ] && [ "$name != '..' ]; then
# process "$name"
fi
done
根据我的经验,想要对目录中的所有点文件或点目录执行某些操作的情况很少发生。