我需要递归地遍历一个目录,并删除所有扩展名为.pdf和.doc的文件。我设法递归地循环通过一个目录,但不设法过滤与上述文件扩展名的文件。
我目前的代码
#/bin/sh
SEARCH_FOLDER="/tmp/*"
for f in $SEARCH_FOLDER
do
if [ -d "$f" ]
then
for ff in $f/*
do
echo "Processing $ff"
done
else
echo "Processing file $f"
fi
done
我需要帮助来完成代码,因为我没有得到任何地方。
作为mouviciel回答的后续,您还可以将其作为for循环来执行,而不是使用xargs。我经常发现xargs很麻烦,特别是当我需要在每次迭代中做一些更复杂的事情时。
for f in $(find /tmp -name '*.pdf' -or -name '*.doc'); do rm $f; done
正如许多人所评论的那样,如果文件名中有空格,这将失败。您可以通过临时将IFS(内部字段分隔符)设置为换行符来解决这个问题。如果有通配符\[?文件名中的*。您可以通过暂时禁用通配符展开(globbing)来解决这个问题。
IFS=$'\n'; set -f
for f in $(find /tmp -name '*.pdf' -or -name '*.doc'); do rm "$f"; done
unset IFS; set +f
如果文件名中有换行符,那么这也行不通。你最好使用基于xargs的解决方案:
find /tmp \( -name '*.pdf' -or -name '*.doc' \) -print0 | xargs -0 rm
(这里需要转义的括号,以使-print0应用于两个或子句。)
GNU和*BSD find也有一个-delete操作,看起来像这样:
find /tmp \( -name '*.pdf' -or -name '*.doc' \) -delete
没有找到:
for f in /tmp/* tmp/**/* ; do
...
done;
“/tmp/*”为目录下的文件,“/tmp/**/*”为子目录下的文件。有可能您必须启用globstar选项(shop -s globstar)。
所以对于这个问题,代码应该是这样的:
shopt -s globstar
for f in /tmp/*.pdf /tmp/*.doc tmp/**/*.pdf tmp/**/*.doc ; do
rm "$f"
done
请注意,这要求bash≥4.0(或zsh不带shopt -s globstar,或ksh带set -o globstar而不是shopt -s globstar)。此外,在bash <4.3中,这将遍历到目录和目录的符号链接,这通常是不可取的。
我认为最直接的解决方案是使用递归,在下面的例子中,我打印了目录及其子目录中的所有文件名。
您可以根据自己的需要修改。
#!/bin/bash
printAll() {
for i in "$1"/*;do # for all in the root
if [ -f "$i" ]; then # if a file exists
echo "$i" # print the file name
elif [ -d "$i" ];then # if a directroy exists
printAll "$i" # call printAll inside it (recursion)
fi
done
}
printAll $1 # e.g.: ./printAll.sh .
输出:
> ./printAll.sh .
./demoDir/4
./demoDir/mo st/1
./demoDir/m2/1557/5
./demoDir/Me/nna/7
./TEST
它也适用于空格!
注意:
你可以使用echo $(basename "$i") # print文件名来打印不包含路径的文件名。
或:使用echo ${i%/##*/};#打印运行速度非常快的文件名,不需要调用外部basename。