Bash Shell显示当前目录下的隐藏文件

Bash Shell显示当前目录下的所有隐藏文件,你只想查看目录下的隐藏(点号)文件,然后编辑其中一个已经忘记名字的文件,或者删除一些废弃文件。ls -a 可以显示出包括隐藏文件在内的所有文件,但这种输出往往包含了过多干扰项,而ls -a .* 的结果也比你想象或需要的更多。

解决方案

使用 ls -d 配合筛选条件。例如:

ls -d .*
ls -d .b*
ls -d .[!.]*
ls -d .*/

因为每个正常的目录中都包含 ...,所以就没必要再显示了。你可以用 ls -A 列出目录中除这两个文件外的其余所有文件。对于可以利用通配符(也就是模式)列出文件的命令,下面给出了能够将... 排除在外的通配符写法:

$ grep -l 'PATH' ~/.[!.]*
/home/jp/.bash_history
/home/jp/.bash_profile
$

讨论

鉴于 shell 处理文件通配符的方式,.* 的行为并不符合你的预期。文件名扩展或通配符匹配(globbing)1 的工作方式如下:任何包含字符 *、?[ 的字符串均被视为模式,会被依字母排序的、匹配该模式的文件名列表所替换。* 可以匹配包括空串在内的任意字符串,?可以匹配任意单个字符。[] 内出现的字符形成了一个字符列表或范围,可以匹配其中的任意字符。还有其他各种扩展模式匹配操作符,我们就不在此展开细说了。因此,*.txt表示以.txt 结尾的所有文件,*txt表示以 txt 结尾的所有文件(模式中没有点号)。f?o可以匹配 foo 或 fao,但无法匹配 fooo。有鉴于此,你可能认为.*会匹配以点号开头的所有文件。

这里特别说明一下 globbing 和 wildcard 的区别:globbing 是对 wildcard 进行扩展的过程。在贝尔实验室诞生的 Unix 中,有一个名为 glob(global 的简写)的独立程序(/etc/glob)。早期 Unix 版本(第 1~6 版,1969—1975 年)的命令解释器(也就是 shell)都要依赖于该程序扩展命令中未被引用的 wildcard,然后将扩展后的结果提供给命令执行。因此,本文将 globbing 译为通配符匹配,将 wildcard 译为通配符。另外,正文中的“扩展模式匹配”是指,如果使用内建命令 shopt 启用了 shell 选项 extglob,那么 shell 就能够识别一些扩展模式匹配操作符,如?(pattern-list)、*(pattern-list)、+(pattern-list)等。——译者注

问题在于.*还可以匹配目录...(存在于每个目录中),它们会和其他以点号开头的文件名一同显示出来。如果 ls 的参数是目录名,那么除了目录名之外,它还会列出该目录中的内容。因此,当你使用ls .* 时,得到的可不仅仅是当前目录下的点号文件,还包括当前目录(.)下的所有文件和子目录、父目录(..)下的所有文件和子目录、当前目录下以点号开头的子目录名及其内容。这种结果可以说非常杂乱,而且通常也用不着这么多输出。

你可以用同样的 ls 命令实验一下,看看加上 -d 选项和没有 -d 选项的区别,然后试试echo .*。echo 命令只会简单地显示出扩展.*后的结果,这些结果就是 ls 命令的参数。

接着还可以试试echo .[!.]*.[!.]*是文件名扩展模式,其中[]指定了要匹配的字符列表,但是开头的! 对该列表做了求反操作。因此我们要找的是一个点号,然后是除点号外的任意字符,接着是任意数量的任意字符。^也可以实现相同的求反效果,但 ! 是 POSIX 标准中规定的,可移植性更好。

ls 命令中的一种特殊情况也能帮上忙。如果指定了 -d 选项,同时文件名模式以斜线结尾,那么 ls 命令只显示匹配模式的目录,匹配的文件名一概不显示。例如:

$ ls -d .v*
.vim  .viminfo  .vimrc
$ ls -d .v*/
.vim
$

第一条命令显示出以.v开头的 3 个文件名,如果其中有目录,也不会列出其内容(因为使用了 -d 选项)。第二条命令在模式结尾加上了斜线(.v*/),因此 ls 命令只显示匹配该模式的目录,在这种情况下,符合条件的只有目录.vim
 如果你在命令ls -d .v*/ 的输出中看到了两条斜线:

$ ls -d .v*/
.vim//
$

这可能是因为你执行的是加入了 -F 选项的 ls 别名。在命令名前面使用反斜线就可以避开所有的别名:

$ \ls -d .v*/
.vim/
$

有些文件名很难匹配。.[!.]* 会漏掉名为..foo的文件。你可以加上形如.??* 的模式来匹配以点号开头且长度至少为 3 个字符的文件名,但是 ls -d .[!.]* .??*会将同时匹配这两种模式的文件名显示两遍。但如果只使用.??*,又会漏掉像.a 这样的文件:

$ touch ..foo .a .normal_dot_file normal_file

$ ls -a
. .. ..foo .a .normal_dot_file normal_file

$ ls -d .??*
..foo .normal_dot_file

$ ls -d .[!.]*
.a .normal_dot_file

$ ls -d .[!.]* .??* | sort -u
..foo
.a
.normal_dot_file

具体用哪一种取决于你的需求和环境,没有什么通用的解决方案。

如果 ls 命令损坏或不知何故无法使用,那么可以用echo * 作为一种应急替代。这种方法可行的原因是,shell 会将 * 扩展为当前目录下的所有文件,其结果和 ls 差不多。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!