簡體   English   中英

如何遞歸遍歷目錄以刪除具有某些擴展名的文件

[英]How to loop through a directory recursively to delete files with certain extensions

我需要遞歸遍歷目錄並刪除所有擴展名為.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(內部字段分隔符)臨時設置為換行符來解決此問題。 如果文件名中包含通配符\\[?* ,這也會失敗。 您可以通過暫時禁用通配符擴展(通配符)來解決這個問題。

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應用於兩者or子句。)

GNU 和 *BSD find 也有一個-delete動作,看起來像這樣:

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

find就是為此而生的。

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

沒有find

for f in /tmp/* tmp/**/* ; do
  ...
done;

/tmp/*是目錄中的文件, /tmp/**/*是子文件夾中的文件。 您可能必須啟用 globstar 選項( shopt -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 中,這會遍歷目錄和目錄的符號鏈接,這通常是不可取的。

如果你想遞歸地做某事,我建議你使用遞歸(是的,你可以使用堆棧等來做,但是嘿)。

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

(cd /tmp; recursiverm)

也就是說,正如已經建議的那樣, find可能是更好的選擇。

這不會直接回答您的問題,但您可以使用單線解決您的問題:

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

這是一個使用 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

這種方法可以很好地處理空格。

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
}

對於 bash(從 4.0 版開始):

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

僅此而已。
尾隨擴展名“.ext”用於選擇具有該擴展名的文件(或目錄)。

選項 globstar 激活 **(遞歸搜索)。
選項 nullglob 在不匹配任何文件/目錄時刪除 *。
選項 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

這是我知道的最簡單的方法: rm **/@(*.doc|*.pdf)

**使這項工作遞歸

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

通過將rm替換為ls輕松安全地進行測試

提供的其他答案不包括以 . 以下對我有用:

#/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;
}

我認為最直接的解決方案是使用遞歸,在下面的示例中,我已經打印了目錄及其子目錄中的所有文件名。

您可以根據需要對其進行修改。

#!/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 the file name打印不帶路徑的文件名。

:使用echo ${i%/##*/}; # print the file name echo ${i%/##*/}; # print the file name運行速度極快echo ${i%/##*/}; # print the file name ,無需調用外部basename

就做

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

以下將遞歸遍歷給定目錄並列出所有內容:

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

如果您可以更改用於運行命令的 shell,則可以使用 ZSH 來完成這項工作。

#!/usr/bin/zsh

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

這將遞歸地遍歷所有文件/文件夾。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM