我需要递归地遍历一个目录,并删除所有扩展名为.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

我需要帮助来完成代码,因为我没有得到任何地方。


只做

find . -name '*.pdf'|xargs rm

这并不能直接回答你的问题,但是你可以用一句话来解决你的问题:

find /tmp \( -name "*.pdf" -o -name "*.doc" \) -type f -exec rm {} +

一些版本的find (GNU, BSD)有一个-delete操作,你可以使用它来代替调用rm:

find /tmp \( -name "*.pdf" -o -name "*.doc" \) -type f -delete

Find就是为这个设计的。

find /tmp -name '*.pdf' -or -name '*.doc' | xargs rm

如果你想递归地做一些事情,我建议你使用递归(是的,你可以使用堆栈等来做,但是嘿)。

recursiverm() {
  for d in *; do
    if [ -d "$d" ]; then
      (cd -- "$d" && recursiverm)
    fi
    rm -f *.pdf
    rm -f *.doc
  done
}

(cd /tmp; recursiverm)

也就是说,find可能是一个更好的选择,就像已经建议的那样。


作为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

这个方法很好地处理了空格。

files="$(find -L "$dir" -type f)"
echo "Count: $(echo -n "$files" | wc -l)"
echo "$files" | while read file; do
  echo "$file"
done

编辑,逐个修复

function count() {
    files="$(find -L "$1" -type f)";
    if [[ "$files" == "" ]]; then
        echo "No files";
        return 0;
    fi
    file_count=$(echo "$files" | wc -l)
    echo "Count: $file_count"
    echo "$files" | while read file; do
        echo "$file"
    done
}

没有找到:

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中,这将遍历到目录和目录的符号链接,这通常是不可取的。


下面的代码将递归地遍历给定目录并列出所有内容:

for d in /home/ubuntu/*; 
do 
    echo "listing contents of dir: $d"; 
    ls -l $d/; 
done

下面是一个使用shell (bash)的例子:

#!/bin/bash

# loop & print a folder recusively,
print_folder_recurse() {
    for i in "$1"/*;do
        if [ -d "$i" ];then
            echo "dir: $i"
            print_folder_recurse "$i"
        elif [ -f "$i" ]; then
            echo "file: $i"
        fi
    done
}


# try get path from param
path=""
if [ -d "$1" ]; then
    path=$1;
else
    path="/tmp"
fi

echo "base path: $path"
print_folder_recurse $path

对于bash(自版本4.0起):

shopt -s globstar nullglob dotglob
echo **/*".ext"

这是所有。 拖尾扩展”。在这里选择具有该扩展名的文件(或dirs)。

选项globstar激活**(递归搜索)。 选项nullglob在不匹配文件/dir时删除*。 选项dotglob包含以点开始的文件(隐藏文件)。

注意,在bash 4.3之前,**/也会遍历到目录的符号链接,这是不可取的。


下面的函数将递归遍历\home\ubuntu目录(ubuntu下的整个目录结构)中的所有目录,并在else块中应用必要的检查。

function check {
        for file in $1/*      
        do
        if [ -d "$file" ]
        then
                check $file                          
        else
               ##check for the file
               if [ $(head -c 4 "$file") = "%PDF" ]; then
                         rm -r $file
               fi
        fi
        done     
}
domain=/home/ubuntu
check $domain

没有理由将find的输出管道到另一个实用程序。Find有一个内置的-delete标志。

find /tmp -name '*.pdf' -or -name '*.doc' -delete

提供的其他答案将不包括以。开头的文件或目录。下面的方法对我很有效:

#/bin/sh
getAll()
{
  local fl1="$1"/*;
  local fl2="$1"/.[!.]*; 
  local fl3="$1"/..?*;
  for inpath in "$1"/* "$1"/.[!.]* "$1"/..?*; do
    if [ "$inpath" != "$fl1" -a "$inpath" != "$fl2" -a "$inpath" != "$fl3" ]; then 
      stat --printf="%F\0%n\0\n" -- "$inpath";
      if [ -d "$inpath" ]; then
        getAll "$inpath"
      #elif [ -f $inpath ]; then
      fi;
    fi;
  done;
}

如果可以更改用于运行该命令的shell,则可以使用ZSH来完成该工作。

#!/usr/bin/zsh

for file in /tmp/**/*
do
    echo $file
done

这将递归循环遍历所有文件/文件夹。


这是我所知道的最简单的方法: rm * * / @ (* . doc | * . pdf)

**使此工作递归地进行

@(*.doc|*.pdf)查找以pdf或doc结尾的文件

通过将rm替换为ls,可以轻松安全地进行测试


我认为最直接的解决方案是使用递归,在下面的例子中,我打印了目录及其子目录中的所有文件名。

您可以根据自己的需要修改。

#!/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。