2014-09-12 15 views
1

我想傳遞一個文件列表,包括通配符文件和我想要刪除的目錄,但檢查它們是否在刪除之前先存在。如果它們被刪除,則通知該目錄已被刪除,而不是目錄中的每個單獨文件。即如果我刪除/root/*.tst只是說,「我刪除* .tst」。Bash腳本:一種更好的方法來刪除帶有通配符的文件和目錄列表

#!/bin/bash 

touch /boot/{1,2,3,4,5,6,7,8,9,10}.tst 
touch /root/{1,2,3,4,5,6,7,8,9,10}.tst 
mkdir /root/tmpdir 

#setup files and directories we want to delete 
file=/boot/*.tst /root/*.tst /root/tmpdir 
for i in $file; do 
    if [[ -d "$file" || -f "$file" ]]; then #do I exist 
     rm -fr $i 
     echo removed $i #should tell me that I removed /boot/*.tst or /root/*.tst or /root/tmpdir 
    else 
     echo $i does not exist # should tell me if /boot/*.tst or /root/*.tst or /root/tmpdir DNE 
    fi 
done 

我似乎無法使單或雙引號或轉義的任何組合*使上述做我想做的事。

回答

0

非常感謝每個人的職位,包括約翰庫格爾曼。

這是我最終用來提供兩種刪除類型的代碼。第一個是刪除所有內容更有力。第二個保存的目錄結構只是刪除文件。如上所述,請注意,文件名中的空格不是由此方法處理的。

rmfunc() { 
local glob 

for glob in "[email protected]"; do 
    local matched=false 
    local checked=true 

    for path in $glob; do 
     $checked && echo -e "\nAttempting to clean $glob" && checked=false 
     [[ -e $path ]] && rm -fr "$path" && matched=true 
    done 

    $matched && echo -e "\n\e[1;33m[\e[0m\e[1;32mPASS\e[1;33m]\e[0m Cleaned $glob" || echo -e "\n\e[1;33m[\e[0m\e[1;31mERROR\e[1;33m]\e[0m Can't find $glob (non fatal)." 
done 
} 

# Type 2 removal 
xargfunc() { 
local glob 

for glob in "[email protected]"; do 
    local matched=false 
    local checked=true 

    for path in $glob; do 
     $checked && echo -e "\nAttempting to clean $glob" && checked=false 
     [[ -n $(find $path -type f) ]] && find $path -type f | xargs rm -f && matched=true 
    done 

    $matched && echo -e "\n\e[1;33m[\e[0m\e[1;32mPASS\e[1;33m]\e[0m Cleaned $glob" || echo -e "\n\e[1;33m[\e[0m\e[1;31mERROR\e[1;33m]\e[0m Can't find $glob (non fatal)." 
fi 
} 
2

在解釋爲什麼你的代碼沒有,這裏是你應該使用什麼:

for i in /boot/*.txt /root/*.txt /root/tmpdir; do 
    # i will be a single file if a pattern expanded, or the literal 
    # pattern if it does not. You can check using this line: 
    [[ -f $i ]] || continue 
    # or use shopt -s nullglob before the loop to cause non-matching 
    # patterns to be silently ignored 
    rm -fr "$i" 
    echo removed $i 
done 

看來,希望i被設置到每個三種模式,這是一個有點棘手,也許應該應避免,因爲大多數您使用的操作符都需要單個文件或目錄名稱,而不是匹配多個名稱的模式。


的嘗試告訴你

file=/boot/*.tst /root/*.tst /root/tmpdir 

將擴大/root/*.tst,並嘗試在擴張作爲命令名稱,工作的環境變量file有字面值/boot/*.tst執行使用的第一個名字。包括字符串中的所有模式,你需要逃避它們之間的空間,有兩種

file=/boot/*.tst\ /root/*.tst\ /root/tmpdir 

或多種天然

file="/boot/*.tst /root/*.tst /root/tmpdir" 

無論哪種方式,模式尚未展開;文字*存儲在值file中。然後,將擴大其使用

for i in $file # no quotes! 

$file膨脹到其文本值後,存儲的模式將擴展到該組匹配文件名。但是,此循環僅適用於不包含空格的文件名;名爲foo bar的單個文件將被視爲分配給i的兩個單獨的值,即foobar。對付這樣的文件名中bash正確的方法是使用一個數組:

files=(/boot/*.tst /root/*.tst /root/tmpdir) 

# Quote are necessary this time to protect space-containing filenames 
# Unlike regular parameter assignment, the patterns were expanded to the matching 
# set of file names first, then the resulting list of files was assigned to the array, 
# one file name per element. 
for i in "${files[@]}" 
1

您可以通過

printf -v file "%s " /boot/*.tst /root/*.tst /root/tmpdir 
1

更換

file=/boot/*.tst /root/*.tst /root/tmpdir 

殼自動擴展水珠。如果您希望能夠在錯誤消息中打印字面大小,那麼您需要引用它們。

rmglob() { 
    local glob 

    for glob in "[email protected]"; do 
     local matched=false 

     for path in $glob; do 
      [[ -e $path ]] && rm -rf "$path" && matched=true 
     done 

     $matched && echo "removed $glob" || echo "$glob does not exist" >&2 
    done 
} 

rmglob '/boot/*.tst' '/root/*.tst' '/root/tmpdir' 

請注意仔細使用引用。引用了deleteGlobs的參數。函數內部的$glob變量是而不是引用(for path in $glob),它觸發了當時的外殼擴展。

+0

這隻適用於不包含空格的模式(例如,'rmglob'/ root/tmp dir''不起作用)。 – chepner 2014-09-12 23:59:50

+0

這幾乎完全是我正在尋找通知刪除的東西。你將如何修改上述內容以確保捕獲帶有空格的文件? – vlord 2014-09-15 15:07:26

相關問題