0

我有一个包含大量子目录的目录,其中一些子目录中有几个 zip 文件。我正在尝试编写一个 bash 脚本,它将遍历目录并查找名称“Archive-foo”进入子目录,如果它包含 zip 文件,则解压缩它们,然后将 zip 文件丢弃。

我编写的脚本适用于我的测试目录(5 个子目录),但是当我尝试在主存档目录(1200 多个子目录)上使用它时,它什么也没做。

for循环可以循环通过的最大项目数吗?

这是我的代码

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
NUMBER=0
for i in $( ls )
do
#echo "$i"" is in the Top Level"
NUMBER=$[NUMBER+1]
if ($(test -d "$i")) 
then
    #echo "$i"" is a Directory"
    if [[ "$i" == *Archive* ]]
    then
        #echo "$i"" has Archive in the name"
        cd "$i" 
        unzip -n "*".zip
        mv *.zip ~/.Trash
    #else
        #echo "$i"" does not have Archive in the name"
    fi
 #else
    #echo "$i"" is NOT a Directory skipping"
fi
done
echo "$NUMBER of items"
IFS=$SAVEIFS
4

2 回答 2

3

命令行的大小有一个限制,并且for i in $( ls )可能会超过它。

请尝试以下语法:

ls | while read i;
do
  ...
done

唯一的问题是管道while在子shell中运行循环,因此分配NUMBER不会持续到原始shell进程中。您可以让循环在处理一行时打印一行,并将整个循环通过管道传递wc -l给计算行数。

于 2013-07-26T20:55:52.047 回答
3

Barmer的回答一针见血。用作for file in $(...)循环头不是一个好主意:

  • 速度较慢:shell$(..)先执行其中的内容,然后运行for循环。它不能开始for直到$(...)完成。
  • 它可以溢出命令行缓冲区:shell 执行$(..),然后将其放在命令行上。命令行缓冲区可能大约 32 KB,现在可能更多,但是如果您有 10,000 个文件并且每个文件平均有 20 个字符,那么您最终会得到超过 200Kb 的命令行缓冲区,
  • For 循环在处理错误的文件名时非常糟糕:如果文件名中包含空格,则每个单词都被视为文件。

一个更好的构造是:

find . ... -print0 | while read -d $\0 file
do
   ...
done
  • 这可以在执行while read时执行循环find,使其更快。
  • 这不能超出命令行缓冲区。
  • 最重要的是,这个结构几乎可以处理任何类型的文件名。将find返回由一个字符分隔的每个文件NUL- 一个不能在文件名中的字符。-d $\0告诉read命令该字符NUL是文件名之间的分隔符。这可以处理文件名中的空格、制表符甚至新行

find也非常灵活。您可以将列表限制为仅包含文件、特定年龄范围内的文件等。替换for循环所需的最常见的是:

$ find . -depth 1

行为就像ls -a

$ find . \! -name ".*" -prune -a  -depth 1

就像ls, 并且会跳过以 . 开头的文件名.

于 2013-07-26T22:46:32.157 回答