我正在查看一些shell代碼,以獲取目錄中文件數量的計數。它讀取:「ls -1 path」中的-1是什麼意思?
COUNT=$(ls -1 ${DIRNAME} | wc -l)
什麼是-1
部分是什麼意思?在任何其他問題中,我都找不到任何有關此問題的任何內容,只是將引用反覆遍歷目錄中的文件,而這不是我正在查看的內容。另外,從命令中刪除它似乎沒有效果。
我正在查看一些shell代碼,以獲取目錄中文件數量的計數。它讀取:「ls -1 path」中的-1是什麼意思?
COUNT=$(ls -1 ${DIRNAME} | wc -l)
什麼是-1
部分是什麼意思?在任何其他問題中,我都找不到任何有關此問題的任何內容,只是將引用反覆遍歷目錄中的文件,而這不是我正在查看的內容。另外,從命令中刪除它似乎沒有效果。
COUNT=$(ls -1 ${DIRNAME} | wc -l)
...是一個目錄來算文件馬車道:ls -1
告訴ls
不要把在一行多個文件;確保wc -l
然後,通過計數行,計數文件。
現在,讓我們說話 「馬車」:
ls
版本如何處理這個問題是由實現定義的;某些版本可能會對這些文件進行重複計算(GNU系統不會,但我不希望對在嵌入式路由器上隨機發布的busybox
進行下注)。${DIRNAME}
允許目錄名稱在傳遞到ls
之前進行字符串拆分和全局展開,因此如果名稱包含空格,它可以變成多個參數。這應該是"$DIRNAME"
或"${DIRNAME}"
。...也是,這是低效的,因爲它調用多個外部工具(ls
和wc
)做某事的外殼可以在內部管理。
如果你想要的東西更強大的,這個版本將與所有POSIX殼工作:
count_entries() { set -- "${1:-.}"/*; if [ -e "$1" ]; then echo "$#"; else echo 0; fi; }
count=$(count_entries "$DIRNAME") ## ideally, DIRNAME should be lower-case.
...或者,如果你希望它是執行的速度更快(不需要子shell)見下面的(只針對bash)的:
# like above, but write to a named variable, not stdout
count_entries_to_var() {
local destvar=$1
set -- "${2:-.}"/*
if [[ -e "$1" || -L "$1" ]]; then
printf -v "$destvar" %d "$#"
else
printf -v "$destvar" %d 0
fi
}
count_entries_to_var count "$DIRNAME"
...或者,如果你的目標bash和不想與函數打擾,你可以使用一個數組:
files=("$DIRNAME"/*)
if [[ -e "${files[0]}" || -L "${files[0]}" ]]; then
echo "At least one file exists in $DIRNAME"
echo "...in fact, there are exactly ${#files[@]} files in $DIRNAME"
else
echo "No files exist in $DIRNAME"
fi
最後 - 如果你要處理太大,不適合在內存中的文件名列表,你有GNU find
,請考慮使用:
find "$DIRNAME" -mindepth 1 -maxdepth 1 -printf '\n' | wc -l
...這避免將所有名稱放入流中(從而生成一個可以簡單測量長度(以字節爲單位)而不是行數的流,如果這樣選擇的話)。
你能解釋一下這個問題嗎?並提出一個安全的方法來做到這一點? –
@JonathanLeffler,...完成。 :) –
謝謝。我觀察到,如果由'$ {DIRECTORY}'表示的字符串很長,那麼在極端情況下,您可能會遇到問題,因爲名稱太長。我注意到你可以用'set --'設置更長的參數列表,而不是你用後面的外部命令來處理:'set - $(perl -e'for $ i(1..1000){printf「%.5d - %s.txt \ n「,$ i,」ABC「x 256;}'); echo $#; echo「$ @」|廁所; al「$ @」| wc' 在Mac OS X 10.10 Yosemite上,這會產生'1000'(來自'echo $#'),'1 1000 779000'來自'echo'$ @「| wc'和'argument list too long' from processing'al | wc'(後跟3個來自'wc'的零)。 –
爲了補充Charles Duffy's excellent answer:
有一個邊緣情況下,他的回答不包括:如果第一個目錄項恰好是一個破符號鏈接,與-e
測試的水珠擴張是不夠的,因爲Bash總是在將存在測試應用於符號鏈接的目標 - 在符號鏈接斷開的情況下,根據定義不存在。換句話說:對於破壞的符號鏈接,-e
將指示虛假,即使鏈接本身存在。因此,一個完全可靠的解決方案必須使用類似[[ -e "$1" || -L "$1" ]]
(-L
測試,如果它的參數是一個符號連接,是否破損或不。)
這裏有一個稍微短bash
替代(使用一個子shell):
count=$(shopt -s nullglob; entries=(*); echo "${#entries[@]}")
shopt -s nullglob
確保如果沒有任何匹配,模式將擴展爲空字符串。entries=(*)
收集數組中的所有匹配項(在當前目錄中)echo "${#entries[@]}"
輸出元素數組數。getconf ARG_MAX
限制,因此應使用大型目錄。注意是否上述計數隱藏(.*
)項目,以及依賴於dotglob
選項的狀態。 這是很容易然而,建立固定的隱藏物品-包括有或沒有邏輯到命令:
明確包括隱藏物品:
count=$(shopt -s nullglob dotglob; entries=(*); echo "${#entries[@]}")
明確排除隱藏物品:
count=$(shopt -s nullglob; shopt -u dotglob; entries=(*); echo "${#entries[@]}")
這是可能的包裹所有上述的以靈活的功能:
每個文件輸出的countEntries [<dir>] ... counts based on current state of the `dotglob` option
countEntries <dir> 0 ... counts non-hidden entries only
countEntries <dir> 1 ... counts all entries, including hidden ones
#!/usr/bin/env bash
# SYNOPSIS
# countEntries [<dir> [<includeHidden>]]
# DESCRIPTION
# <dir> defaults to .
# <includeHidden> default to the current state of `shopt dotglob`;
# a value of 0 explicitly EXcludes, 1 explicity INcludes hidden items.
countEntries() (# Run entire function in subhell.
local dir=${1:-.} includeHidden=$2 entries
shopt -s nullglob
case $includeHidden in
0) # EXclude hidden entries
shopt -u dotglob
;;
1) # INclude hidden entries
shopt -s dotglob
;;
# Otherwise: use *current state* of `dotglob`
esac
entries=("$1"/*) # Collect in array
echo "${#entries[@]}" # Output count.
)
發射一個線。 –
...其中,當輸出不是終端時是默認值,但顯式比隱式更好。 –
@CharlesDuffy啊,這很有道理,謝謝。解釋爲什麼當我刪除它時沒有任何變化。 –