Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 如果没有这样的文件,则输出错误_Linux_Bash_Shell - Fatal编程技术网

Linux 如果没有这样的文件,则输出错误

Linux 如果没有这样的文件,则输出错误,linux,bash,shell,Linux,Bash,Shell,我试图找出特定类型的文件的数量。若文件存在,那个么这个脚本工作正常,否则for循环执行一次(预计不会运行) 可能还有其他方法来实现相同的功能,如ls*.txt | xargs…。但是作为一个新手,我想知道在发布的脚本中的问题。我请求你分享你在这方面的知识 当模式*.txt没有匹配文件时,它被解释为文本字符串“*.txt”。这就是为什么循环至少运行一次 有几种方法可以解决这个问题。您可以添加对匹配文件存在性的检查,如下所示: if ls *.txt >/dev/null 2>&

我试图找出特定类型的文件的数量。若文件存在,那个么这个脚本工作正常,否则for循环执行一次(预计不会运行)


可能还有其他方法来实现相同的功能,如
ls*.txt | xargs…
。但是作为一个新手,我想知道在发布的脚本中的问题。我请求你分享你在这方面的知识

当模式
*.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
),因为
while
循环在子shell中运行,因此当子shell退出时(即循环终止),对
$j
的所有更改都将丢失


作为旁注:我会将
$j
的增量从
j=`expr$j+1`
更改为
((j++)

脚本中没有问题,实际上,除了可以使用现代内置语言以更好的风格编写,而且如果没有文本文件,它会失败,请参见下文

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时,最好使用
failglob
nullglob

  • failglob
    如果无法扩展glob,将引发错误
  • 如果没有合适的扩展,
    nullglob
    只会扩展为零
如果没有合适的扩展,则
*.txt
将扩展为
*.txt
(逐字),这正是您想要避免的

在你的情况下,把

shopt -s nullglob
在你的脚本顶端,你就完成了

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

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

关于
nullglob
failglob
有什么大惊小怪的

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

$ 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-in时,使用
failglob
nullglob
使脚本更加健壮

底线是:每次你使用globing而不使用
failglob
nullglob
,上帝就会杀死一只小猫


如果您想了解有关shopt和shell可选行为的更多信息,请参考。

您真的需要脚本吗?像
ls-l*.txt | wc-l
这样的东西不管用吗?我刚刚开始学习shell脚本。不管怎样,我也要试试这个。但是这个脚本可能会有什么问题呢?一个风格提示:行尾不需要分号。但我没有得到nullglob的东西。无论如何,我会学习的。:)@Jeyaram看到我的编辑,试图澄清
nullglob
failglob
。所以这些都是bash变量。有趣。谢谢:)@Jeyaram不,不是变量。请参阅。这里它被称为特殊bash变量。这就是我提到bash变量的原因。无论如何,我会参考链接。解析
find
的输出通常不是一个好主意。同样在这里,
while
循环将在子shell中执行,因此如果您在子shell中执行
(++j))
,子shell退出后将看不到它。我不是在这里解析
find
输出,只是逐行读取它。怎么了?不过,关于增加
$j
,您是对的。我已更新了答案。如果文件名包含换行符,则是错误的。尝试:
触摸\n在\its\name.txt'
中出现断线的文件$'!此外,由于
read
会丢弃行首和行尾的空格,因此在某些情况下可能会出现问题。有好习惯也有坏习惯。大多数坏习惯可能在99.9%的时间里有效,但一旦坏习惯打破,情况就糟糕了。逐行读取
find
的输出实际上就是我所说的解析其输出。但我可能错了<代码>:)
如果[-f*.txt]
在多个文件匹配“*.txt”的情况下因“参数太多”而失败,因此第一种方法实际上不起作用。
$ shopt -u nullglob
$ shopt -s failglob
$ echo *.txt
bash: no match: *.txt
$