事先:这从一个一般问题(我认为每个文件夹都是这种情况)演变为这个特定的极端情况。
由于其他一些人似乎和我一样好奇,我决定不删除这个问题而是重新编写它。
假设我想列出我的主文件夹中直接包含的所有项目,点文件和文件夹除外。恕我直言,下面的 find 命令应该这样做(我明确地写了“点项目”,因为如果你使用一个.hidden
文件,“隐藏项目”可能会有所不同):
find $HOME/ -mindepth 1 -maxdepth 1 -path "$HOME/.*" -prune -o -print
Run Code Online (Sandbox Code Playgroud)
-mindepth 1
确保不包含 $HOME 本身,-maxdepth 1
限制为一个文件夹级别,-path "$HOME/.*" -prune
排除主文件夹中以点开头的所有内容,并-o -print
根据手册页确保输出中没有排除的元素。
到现在为止还挺好。它有点工作(即使存在您没有权限的点文件夹),但它开始窒息,$HOME/.gvfs
尽管由于以下原因根本不应该访问它-path ... -prune
:
/home/user/file a
/home/user/folder b
...
find: '/home/user/.gvfs': Permission denied
/home/user/.gvfs
...
/home/user/file z
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用-perm
atfind
并2> /dev/null
解决它,但真正让我震惊的是,它/home/user/.gvfs
包含在列表中(尽管所有其他点项都被排除在外)!!!
而且我很确定一些不太小心的人很想摆脱错误2> /dev/null
并继续前进。...如果他们完全识别错误,因为在包含 100 行的较长列表中,您必须1> /dev/null
在使用该命令之前使用添加等方式明确检查错误。
为什么要find
尝试访问/home/user/.gvfs
,尽管-maxdepth 1
或至少-prune
应该阻止这种情况?例如从手册页:
'-prune' 动作(只会阻止进一步下降[...])
即使在较旧的手册页(安装在我的系统上)中-path
也指出:
要忽略整个目录树,请使用 -prune 而不是检查树中的每个文件。
如果所有/home/user/.*
这些都真的被忽略了,也许我的问题的第二部分就没有必要了,因为在我看来这是因为一个内部错误:
为什么/home/user/.gvfs
仍然在列表中以及如何防止它?有没有办法不用摆弄-user
/-perm
和2> /dev/null
每个find
命令(至少有一个-prune
动作)?
用-prune
(或至少用-path ... -prune
)真正忽略了什么?
如果-prune
仍然(几乎)所有文件都被检查,我会放弃使用这个复杂的选项,而是使用!
or -not
,特别是因为-prune
显然更容易出错。
这似乎是一个错误在GNU实现的find
。在这里,触发器似乎是这样一个事实,即lstat()
/fstatat()
系统调用(用于检索文件的元数据)在该文件上失败EACCESS
(权限被拒绝).gvfs
。
对于作为基于 FUSE 的文件系统的挂载点的文件,在 Linux 上通常会发生这种情况,而该-o allow-other
选项尚未用于该文件系统。当存在指向不可访问区域的符号链接时,find -L
/也可能发生这种情况find -follow
。
我在这里发现-prune
这些文件返回false,这显然是一个错误,正如-prune
所记录的(并且是 POSIX 要求的)总是返回true。
作为解决该错误之前的解决方法,您可以替换-prune
为'(' -prune -o -true ')'
(请注意,这-true
是一个 GNU 扩展;一个可移植的等效项可以! -name ''
保证是正确的,尽管您也可以这样做'(' -prune -o ! -prune ')'
)
现在,您的代码本身存在一些问题。在:
find $HOME/ -mindepth 1 -maxdepth 1 -path "$HOME/.*" -prune -o -print
Run Code Online (Sandbox Code Playgroud)
$HOME/
应该引用它,否则$HOME
扩展会受到 split+glob 的影响。你也可以写出来~/
。-prune
是告诉find
不要进入目录。在这里它是多余的,因为maxdepth 1
它将停止find
下降到任何目录(除了顶级(深度 0)一个$HOME/
)。-path
需要一个模式。这意味着 的内容$HOME
将被视为一种模式。$HOME
例如/home/[112] me
,如果您是,-path '/home/[112] me/.*'
将匹配 on /home/2 me/.foo
,但不匹配on /home/[112] me/.foo
。此处也不需要匹配完整路径,您可以匹配文件名而不是-name '.*'
.*
with GNUfind
只匹配characters,因此.*
匹配以 开头的文件名,.
并且也由形成有效字符的字节序列组成。因此,您只能使用它来匹配语言环境中的隐藏文件,其中每个字节序列都形成有效字符(例如C
语言环境)。所以在这里,如果重点是列出 HOME 目录中的非隐藏文件及其完整路径,你会这样做:
LC_ALL=C find ~/ -mindepth 1 -maxdepth 1 ! -name '.*'
Run Code Online (Sandbox Code Playgroud)
这也将避免 GNUfind
错误。
或标准等价物(尽管/./
在路径中添加了 a ):
LC_ALL=C find ~/. ! -name . -prune ! -name '.*'
Run Code Online (Sandbox Code Playgroud)
(这里,GNUfind
错误会因文件不以开头.
和不可用而受到攻击lstat()
,但您将在上面的错误描述中看到,是否lstat()
报告不可用文件会因实现而有很大差异)。
在这里,我只使用zsh
's:
print -rC1 ~/*(ND)
Run Code Online (Sandbox Code Playgroud)
或者,如果您不希望它们按以下方式排序find
:
print -rC1 ~/*(NDoN)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
128 次 |
最近记录: |