我有一个包含大量子目录的目录,其中一些子目录中有几个zip文件。我正在尝试编写一个bash脚本,该脚本将遍历目录并查找名称"Archive foo",进入子目录,如果其中包含zip文件,则解压缩它们,然后丢弃zip文件。
我编写的脚本适用于我的测试目录(5个子目录),但当我尝试在主归档目录(1200多个子目录)上使用它时,它什么都做不了。
for循环可以循环通过的项目的最大数量是多少?
这是我的代码
#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "nb")
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
命令行的大小有限制,for i in $( ls )
可能会超过这个限制。
请尝试以下语法:
ls | while read i;
do
...
done
唯一的问题是管道在子shell中运行while
循环,因此对NUMBER
的分配不会持久存在于原始shell进程中。您可以让循环在处理一行时打印一行,并通过管道将整个循环发送到wc -l
来计算行数。
Barmer的回答切中要害。使用for file in $(...)
作为循环头不是一个好主意:
-
它更慢:shell首先执行
$(..)
中的内容,然后运行for
循环。直到$(...)
结束,它才能启动for
-
它可能会溢出命令行缓冲区:shell执行
$(..)
,然后将其放在命令行上。命令行缓冲区可能大约是32千字节,现在可能更多,但如果你有10000个文件,每个文件平均20个字符,你最终会得到超过200Kb的命令行缓冲 - For循环在处理错误的文件名方面很糟糕:如果文件名中有空格,则每个单词都被视为一个文件
一个更好的构造是:
find . ... -print0 | while read -d $ file
do
...
done
- 这可以在执行
find
的同时执行while read
循环,使其更快 - 这不能使命令行缓冲区溢出
- 最重要的是,这个构造几乎可以处理任何类型的文件名。
find
将返回由NUL
字符分隔的每个文件,该字符不能在文件名中。-d $
告诉read
命令NUL
字符是文件名之间的分隔符。这可以处理文件名中的空格、制表符,甚至新行
find
也非常灵活。您可以将列表限制为仅文件、特定年龄范围内的文件等。最常见的需要复制for
循环的文件有:
$ find . -depth 1
行为就像ls -a
:
$ find . ! -name ".*" -prune -a -depth 1
行为与ls
类似,并将跳过以.
开头的文件名。