2013-05-05 68 views
1

我有一個非常簡單的問題,我發現了一堆類似的問題,但沒有一個解決了這個問題。腳本失敗,目錄名稱中的空格

我有一個shell腳本,通過一個目錄,並打印出一個子目錄中的文件和目錄的數量,然後打印目錄名稱。

但是,它帶有空格的目錄會失敗,它會嘗試將每個單詞用作新參數。我試過把$ dir放在引號中,但這沒有幫助。也許是因爲它已經在回聲報價中。

for dir in `find . -mindepth 1 -maxdepth 1 -type d` 
do 
    echo -e "`ls -1 $dir | wc -l`\t$dir" 
done 

在此先感謝您的幫助:)

+1

不管發生了什麼事情。 -mindepth ... |同時閱讀dir;做...; *嘆息* – robertklep 2013-05-05 14:26:39

+0

@robertklep嗯 - 那個版本不太對;它錯誤地處理了一些帶有反斜槓的名字,以IFS字符結尾的名字和任何包含換行符的名字。此外,由於位於流水線的右側,因此在while循環中對變量所做的任何更改在退出時都會被忽略。 – 2013-05-05 14:28:26

+1

@CharlesDuffy和最初發布的版本(我正在迴應)捕捉所有這些問題? ;) – robertklep 2013-05-05 14:31:15

回答

4

警告:下面使用bash化的三個代碼樣本中的兩個。如果你需要POSIX sh而不是bash,請注意使用正確的。


不要做任何這些事情。如果你真正的問題不使用find涉及,你可以用它像這樣:

shopt -s nullglob 
while IFS='' read -r -d '' dir; do 
    files=("$dir"/*) 
    printf '%s\t%s\n' "${#files[@]}" "$dir" 
done < <(find . -mindepth 1 -maxdepth 1 -type d -print0) 

然而,對於迭代只顧眼前利益子目錄,你並不需要找到所有:

shopt -s nullglob 
for dir in */; do 
    files=("$dir"/*) 
    printf '%s\t%s\n' "${#files[@]}" "$dir" 
done 

如果您「再試圖做到這一點與POSIX兼容sh的一種方式,你可以嘗試以下方法:

for dir in */; do 
    [ "$dir" = "*/" ] && continue 
    set -- "$dir"/* 
    [ "$#" -eq 1 ] && [ "$1" = "$dir/*" ] && continue 
    printf '%s\t%s\n' "$#" "$dir" 
done 

你不應該永遠使用ls在腳本:http://mywiki.wooledge.org/ParsingLs

你不應該永遠使用for讀線:http://mywiki.wooledge.org/DontReadLinesWithFor

使用數組和水珠計數文件時,要做到這一點安全,穩健,且無需外部命令:http://mywiki.wooledge.org/BashFAQ/004

始終NUL,終止文件列表從find出來 - 否則,包含換行符的文件名(是的,它們在UNIX中是合法的!)會導致單個名稱被讀作多個文件,或者(在某些查找版本和用法中)您的「文件名」不匹配真實文件的名稱。 http://mywiki.wooledge.org/UsingFind

+0

真棒謝謝:)正如你可以告訴我,這是新的。 我想知道你是否可以向我解釋幾行? - IFS =''read -r -d''dir - files =(「$ dir」/ *) - done <<(find。-mindepth 1 -maxdepth 1 -type d -print0) - 還,它說nullglob是無效的選項名稱 – Chris 2013-05-05 14:32:37

+0

@Chris如果它說nullglob是無效的,你的shell可能不是bash(和其他部分也不會工作)。請參閱mywiki.wooledge.org/BashGuide/Practices – 2013-05-05 14:50:32

+0

的「選擇您的shell」部分@Chris我添加了符合POSIX標準的答案版本;那個人應該爲你工作。 – 2013-05-05 15:07:41