2012-12-05 52 views
12

我正在学习bash脚本并编写了一个脚本来计算作为参数提供的目录中的文件和目录。我的工作方式对我来说似乎很奇怪,我想知道是否有一种更简单的方法。使用shell脚本计算文件和目录

我已经注释掉了可以正常工作的代码,但是将其留作比较。我试图让for环回工作,而不是使用if语句来检测给定位置中的项目是文件还是目录。

编辑:我刚刚发现注释代码计算给定位置的子目录中的所有文件和目录!有没有什么办法来防止这种情况,只计算给定位置的文件和目录?

#!/bin/bash 

LOCATION=$1 
FILECOUNT=0 
DIRCOUNT=0 

if [ "$#" -lt "1" ] 
then 
    echo "Usage: ./test2.sh <directory>" 
    exit 0 
fi 

#DIRS=$(find $LOCATION -type d) 
#FILES=$(find $LOCATION -type f) 

#for d in $DIRS 
#do 
# DIRCOUNT=$[$DIRCOUNT+1] 
#done 

#for f in $FILES 
#do 
# FILECOUNT=$[$FILECOUNT+1] 
#done 

for item in $LOCATION 
do 
if [ -f "$item" ] 
    then 
     FILECOUNT=$[$FILECOUNT+1] 
    elif [ -d "$item" ] 
     then 
     DIRCOUNT=$[$DIRCOUNT+1] 
fi 
done 

echo "File count: " $FILECOUNT 
echo "Directory count: " $DIRCOUNT 

出于某种原因,for -loop的输出,无论在哪里我点位置,总是返回:

File count: 0 , Directory count: 1 
+0

如果文件名中出现空格,则整个脚本都会中断。正如你在学习,我的第一个建议是:使用更多的行情! –

+0

另一评论:我可以告诉你,学习bash的来源已经过时,并没有显示良好的做法。 –

+0

在文件名扩展考虑阅读:http://bash.cyberciti.biz/bash-reference-manual/Filename-Expansion.html – hovanessyan

回答

4

你不是遍历文件列表中给定的目录;在$LOCATION之后加/*。你的脚本应该是这样的:

... 
for item in $LOCATION/* 
do 
... 

正如指出的罗布麻,只需添加/*将只计算不以.开头的文件;这样做,你应该做到以下几点:

... 
for item in $LOCATION/* $LOCATION/.* 
do 
... 
+2

中的项目这是脚本中的实际主要问题。 – Jite

+1

这就是我正在寻找的答案!谢谢。这里的其他解决方案都计算了位置的子目录的文件和目录,这些我都不需要。干杯。 –

+1

好点。也许一个单独的循环与$ LOCATION /.* ?? ?? –

10

要只是解决您可以使用问题:

FILECOUNT=$(find $LOCATION -type f | wc -l) 
DIRCOUNT=$(find $LOCATION -type d | wc -l) 

find会寻找所有文件(-type f)或目录(-type d)递归$LOCATION下;在每种情况下,wc -l都会计算写入stdout的行数。

但是,如果你想学习,bash脚本可能是一个更好的方法。一些评论:

  • 如果你想寻找的文件/目录中$LOCATION只(不递归下的子目录等),你可以使用for item in $LOCATION/*,其中*将扩大到的文件/目录列表中$LOCATION目录。缺少的*是为什么您的原始脚本返回0/1(因为$LOCATION目录本身是唯一计数的项目)。
  • 您可能首先需要检查$LOCATION是否为[ -d $LOCATION ]
  • 对于算术表达式,请使用$((...)),例如FILECOUNT=$((FILECOUNT + 1))
  • 如果要递归查找所有文件/目录,可以将find与循环组合起来。

例子:

find $LOCATION | while read item; do 
    # use $item here... 
done 
+0

是的,$ LOCATION/*代码完美运作。为什么$((...))而不是$ []?性能相关? –

+0

@AlanSmith,'$ [...]'是不赞成使用的语法,我甚至无法在'man bash'中找到它。现代版本是'$((...))'(尽管它们似乎以相同的方式工作)。对于你的任务,你也可以使用'((++ FILECOUNT))'。请参阅http://stackoverflow.com/questions/2188199/bash-double-or-single-bracket-parentheses-curly-braces。 –

+0

好的,很棒的信息,谢谢。 –

2

... am wondering if there is a simpler way of doing it.

如果你这么说;)

另外,你的脚本减少

find /path/to/directory | wc -l 

对于当前目录下,这样做:

find . | wc -l 
+0

注:它也是一个文件。“。所以只有两个普通的文件,我想你要计算,这将打印'3'。 – Jite

+0

他正在寻找一种方法来区分dirs和文件的计数 - 这就是为什么他的代码中有2个计数器。您的查找给出总数,不区分文件类型。 – hovanessyan

1

使用

find $LOCATION -maxdepth 1 -type f | wc -l 

,文件的数量和

find $LOCATION -maxdepth 1 -type d | wc -l 

计数目录

12

使用find,如下图所示。该解决方案将正确计算文件名的空格,换行符和点文件。

FILECOUNT="$(find . -type f -maxdepth 1 -printf x | wc -c)" 
DIRCOUNT="$(find . -type d -maxdepth 1 -printf x | wc -c)" 

注意,DIRCOUNT包括当前目录(.)。如果你不想要,减1。

((DIRCOUNT--)) # to exclude the current directory 
+0

这显然是这种特殊情况下最好的方法!正如提到的那样,它处理所有可能的文件名称中包含有趣符号的情况,并且对于包含大量文件的目录(对于使用globbing的bash解决方案来说不是这种情况)也能很好地工作。但有一件事,我的'find'抱怨'-type f'选项后面给出了'-maxdepth 1'。 (另一件事,双引号在这里不是必要的,但它从不伤害它们)。 –