2

我正在尝试找出特定类型的文件数。如果文件存在,则此脚本可以正常工作,否则 for 循环执行一次(预计不会运行)。

echo "Checking for text files..."

j=0
for i in *.txt;
do
echo $i;
j=`expr $j + 1`;
done

if [ $j -ge 0 ];then
echo "No.of Text files:"$j
else
echo "No Text files."
fi

可能还有其他方法可以处理相同的事情,例如ls *.txt |xargs .... 但作为一个新手,我想知道发布脚本中的问题。我请求你分享你在这方面的知识。

4

2 回答 2

5

实际上,您的脚本没有问题,除了可以使用现代内置程序以更好的风格编写之外,如果没有文本文件它会失败,请参见下文。

echo "Checking for text files..."

j=0
for i in *.txt; do
    echo "$i"
    ((++j))
done

if ((j!=0)); then
    echo "No. of Text files: $j"
else
    echo "No Text files."
fi

使用 globbing 时最好使用nullglob.failglob

  • failglob如果无法扩展 glob,将引发错误,
  • nullglob如果没有合适的扩展,只会扩展为空。

没有这些,如果没有合适的扩展,*.txt将扩展为*.txt(逐字),这正是您要避免的!

在你的情况下,只要把

shopt -s nullglob

在脚本的顶部,您就完成了!

现在计算文件数量的一种可能方法*.txt是:

shopt -s nullglob
a=(*.txt)
echo "There are ${#a[@]} text files"

这是什么大惊小怪的nullglobfailglob

让我们进入一个临时目录:

$ mkdir scratch; cd scratch
$ # this dir is empty
$ echo *.txt
*.txt
$ 

因为 glob 在那里没有合适的扩展。现在:

$ shopt -s nullglob
$ echo *.txt

$ 

因为nullglob. 现在我们将取消设置nullglob并设置failglob

$ shopt -u nullglob
$ shopt -s failglob
$ echo *.txt
bash: no match: *.txt
$

得到它?

底线是:每次您在中使用 globbing 时,请使用failglobornullglob使您的脚本更加健壮。

作为脸颊底线的舌头:每次您使用不带failglobor的 globbing 时nullglob,上帝都会杀死一只小猫。

如果您想了解有关shoptshell 可选行为的更多信息,请参阅手册中的 Shopt Builtin 部分

于 2013-06-29T12:50:11.030 回答
1

当模式没有匹配的文件时*.txt,它被解释为文字字符串"*.txt"。这就是为什么你的循环至少运行一次。

有几种方法可以处理这个问题。您可以添加检查是否存在匹配文件,如下所示:

if ls *.txt >/dev/null 2>&1; then
  for i in *.txt; do
    ...
  done
fi

根据您想要在循环内执行的操作,您还可以使用find

find . -maxdepth 1 -name "*.txt" | while read i; do
  ...
done

然而,有些事情不适用于这种结构(例如递增$j),因为循环在子shell 中运行,所以当子shell 退出时(即循环终止)while,所有更改都将丢失。$j

附带说明:我会将$jfrom的增量更改j=`expr $j + 1`((j++)).

于 2013-06-29T12:48:54.827 回答