[英]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.