【问题标题】:How can I count the hidden files in a directory using a shell script?如何使用 shell 脚本计算目录中的隐藏文件?
【发布时间】:2014-06-11 17:57:25
【问题描述】:

我用过这段代码

#!/bin/bash

ls -l
echo -n "Number of simple files : "
ls -l | egrep '^-' | wc -l 
echo -n "Number of directories : "
ls -l | egrep '^d' | wc -l
echo -n "Number of hidden files : "
ls -la | egrep '^.*\.$' | wc -l
echo -n "Number of hidden directories : "
ls -la | egrep '^d.*\.$' | wc -l
echo " End"

虽然我可以理解前两个 egrep 是如何工作的,但我不知道最后一个是如何工作的 两个工作。更具体地说,这是什么意思 '^.*\.$' ? 我想要一个以 . (隐藏文件)然后我应该如何塑造我的正则表达式?

【问题讨论】:

  • 现在,如果您的真正问题不是如何计算隐藏文件,而是正则表达式^.*\.$ 的含义,您应该将其作为单独的问题提出。
  • 最后两个不起作用。它们分别计算名称以句点结束的常规文件和目录的数量。
  • 对于这里的任何其他人,一些指向由 freenode #bash 频道维护的 wiki 的链接:BashFAQ #4 处理一般计算文件的最佳实践方法。 ParsingLs 详细描述了为什么 ls 不应该用于这种用例,以及可用的替代方案。

标签: bash shell scripting grep


【解决方案1】:

您根本不应该使用grep(或ls)来完成这项任务。请参阅 http://mywiki.wooledge.org/ParsingLs,深入讨论 ls 应该如何永远用于向人类进行交互式显示。

all_files=( * )            # includes directories
directories=( */ )         # directories only
hidden_files=( .* )        # includes directories
hidden_directories=( .*/ ) # directories only

echo "Number of files: $(( ${#all_files[@]} - ${#all_directories[@]} ))"
echo "Number of directories: ${#directories[@]}"
echo "Number of hidden files: $(( ${#hidden_files[@]} - ${#hidden_directories[@]} ))"
echo "Number of hidden directories: $(( ${#hidden_directories[@]} - 2 ))"

最后一次计算中的- 2是去掉...,它们会一直存在。

【讨论】:

  • $(( ${#all_files[@]} - ${#all_directories[@]})" 应该是 $(( ${#all_files[@]} - ${#all_directories[@]} ))"(缺少括号)
  • 谢谢你,jaypal,根据@GergoErdosi 的建议进行编辑
【解决方案2】:

请注意,您为此目的解析ls 输出的方法是错误的。请参阅@Dharles Duffy 的答案以获得更好的选择。不过要回答您的问题并稍微解释一下正则表达式:

'^.*\.$' 表示

^     // From the beginning of the string
.*    // match zero or more of any character
\.    // match one literal full-stop
$     // end of the string

我不确定“秘密”文件是什么意思,但如果您指的是隐藏文件,即以 . 开头然后是文件名的文件,那么正则表达式的方式就是

'^\..*$'

请注意,这不是在解析ls 输出时,它仅用于文件或目录名称,不区分两者。

【讨论】:

  • 是的,我很抱歉我的意思是隐藏。我真的不明白为什么我的示例适用于隐藏文件(这不是我的代码)。你的例子似乎更合乎逻辑。
  • 没有您原始帖子中的最后两个正则表达式将始终匹配并且仅匹配 ... 分别是“此目录”和“父目录”的引用。因此,无论您将其应用到哪个文件夹,结果都将始终为 2。在您的情况下,您有 2 个隐藏文件和目录可能是巧合
  • 我的意思是你的解决方案'^\..*$'
【解决方案3】:

最后两个工作不正确,但是

ls -la | egrep '^.*\.$' | wc -l
ls -la | egrep '^d.*\.$' | wc -l

return 2

ls -la | egrep '^.*\.$' 
ls -la | egrep '^d.*\.$' 

返回

drwxr-xr-x  7 root root  4096 date time .
drwxr-xr-x 31 root root  4096 date time ..

变体:

secret files:
ls -la | grep '^-' |awk '{print $9}' |egrep '^\.[^\.]' |wc -l
secret dirs:
ls -la | grep '^d' |awk '{print $9}' |egrep '^\.[^\.]' |wc -l

【讨论】:

    【解决方案4】:

    正则表达式不起作用,因为'^.*\.$' 匹配行尾的点。使用这些命令来计算隐藏文件和目录:

    ls -ld .* | egrep '^-' | wc -l
    ls -ld .* | egrep '^d' | wc -l
    

    注意egrep '^d' 也匹配...,所以你需要从结果中减去2:

    ls -ld .* | egrep '^d' | wc -l | awk '{print $1 - 2}'
    

    替代方案:

    ls -ld .* | egrep '^d' | tail -n +3 | wc -l
    echo $(($(ls -ld .* | egrep '^d' | wc -l) - 2))
    

    【讨论】:

    • 奇怪的是我的例子确实有效,但我不知道为什么。
    • @Molnia 我测试了你的代码,但它对我不起作用。它总是返回 2,因为它匹配 ...
    • 是的,我认为你是对的。这让我很困惑。
    • 你为什么这么认为?预期值和实际值是多少?
    • 我有 3 个隐藏目录,但实际上我只有一个。也许,它计算了...
    【解决方案5】:
    find $THE_DIRECTORY -maxdepth 1 -type f -name '.*' | wc --lines
    

    应该可以,如果您还想查找符号链接,您可能需要使用 -L。

    【讨论】:

    • 当您只想计算实际姓名时,为什么要告诉find 打印实际姓名? -printf . 可以让您计算字符数,或者-printf '\n' 可以让您计算通过管道的数据较少的行数,从而降低效率。
    • ...另外,wc --lines 仅适用于 GNU 系统,而 wc -l 适用于任何符合 POSIX 的平台。
    • 为什么?感谢您的见解:)