![檢查資料夾是否包含帶有副檔名的檔案並將目錄寫入類別](https://rvso.com/image/1684200/%E6%AA%A2%E6%9F%A5%E8%B3%87%E6%96%99%E5%A4%BE%E6%98%AF%E5%90%A6%E5%8C%85%E5%90%AB%E5%B8%B6%E6%9C%89%E5%89%AF%E6%AA%94%E5%90%8D%E7%9A%84%E6%AA%94%E6%A1%88%E4%B8%A6%E5%B0%87%E7%9B%AE%E9%8C%84%E5%AF%AB%E5%85%A5%E9%A1%9E%E5%88%A5.png)
我有大約 3k + 資料夾,它們可以有兩種類型的文件,一個 spring 檔案和一對 fastq.gz 檔案。我想掃描資料夾並了解目錄中是否存在兩個或其中一個檔案副檔名 -
- 包含一對fastq.gz和spring文件
- 1個fastq.gz檔案和spring文件
- 單一彈簧文件
- 一對 fastq.gz 文件
- 單一 fastq.gz 文件
我使用過[ /path/to/dir/*fastq.gz ]
,但出現unary operator expected
錯誤,並且使用[[ ]]
似乎沒有正確測試事物。
我使用的實際腳本是 -
check_dir () {
in="$1"
echo "$in Checking for spring"
[ "$in"/*spring -f ] && echo "$in"
}
export -f check_dir
我正在使用 bash,任何有關邏輯的幫助將不勝感激
答案1
unary operator expected
是因為[
和*
(在你的*fastq.gz
)中獨立工作。
[
不是 shell 語法。[
是一個常規命令(Bash 中的內建命令,但仍然是一個命令)並且]
是它的最後一個命令爭論,強制性的。介於兩者之間的任何事情也是一個爭論。
shell/path/to/dir/*fastq.gz
在呼叫 之前會擴展為一個或多個單字[
。[
將看到這些單字加上強制參數]
作為參數。根據參數的數量及其內容,[
期望零個或多個參數為運算符(如-f
)。
[ /path/to/dir/*fastq.gz ]
如果/path/to/dir/*fastq.gz
擴展到單一參數,您的will 是有效的(注意「將是有效的」不等於「將做您想做的事」)。這包括不匹配任何內容的情況*
;傳統上(Bash 中預設)如果沒有匹配,/path/to/dir/*fastq.gz
則將按原樣處理。它可能會/path/to/dir/*fastq.gz
擴展為多個單詞,但它們看起來都不像是操作員[
能夠理解的。您得到的錯誤很可能是由於模式擴展為兩個單字的情況造成的。
後來你用了[ "$in"/*spring -f ]
.這更糟,因為你可能想要類似[ -f some/path ]
where-f
is前測試的路徑。仍然[ -f "$in"/*spring ]
不是一個強有力的修復,因為"$in"/*spring
一般來說可能會擴展到多個論點並且[
無法忍受它們。你寫的最多有一個*spring
文件,所以在你的情況下像這樣的程式碼可能有點工作;但它仍然是糟糕的程式碼。
對於[
,不要使用通配符,*
這樣可能會擴展到多個單字;這將立即或很快失敗。[[
引擎蓋下是不同的但這也不利於您的目的。
您想知道某個模式有多少文件/path/to/dir/*fastq.gz
匹配了多少個檔案。正確的方法是將擴展的結果分配給數組。可移植的是,只有一個陣列:shell 腳本(或 shell 函數)的參數陣列;並且您需要額外的程式碼來檢測零匹配的情況(仍然產生一個單字:未擴展的模式字串)。您的問題已被標記巴什,所以我將使用命名數組和其他一些不可移植的功能:
# non-portable code, works in Bash
check_dir () (
dir="${1-.}"
dir="${dir%/}/"
[ -d "$dir" ] || { echo "Not a directory." >&2; return 1; }
shopt -s nullglob
files=( "$dir"/*fastq.gz )
nf="${#files[@]}"
files=( "$dir"/*spring )
ns="${#files[@]}"
printf '%s\t%s\t%s\n' "$nf" "$ns" "$dir"
)
用法:check_dir path/to/dir
或check_dir
(預設路徑為.
)。此函數將列印檔案數*fastq.gz
、選項卡、檔案數*spring
、選項卡、最後檢查的路徑(以尾隨列印/
)。
現在您可以分析目錄樹(以下函數需要定義上述函數):
# non-portable code, works in Bash
check_dirs () (
dir="${1-.}"
dir="${dir%/}/"
[ -d "$dir" ] || { echo "Not a directory." >&2; return 1; }
shopt -s nullglob globstar
for d in "$dir"**/; do
check_dir "$d"
done
)
用法:check_dirs path/to/dir
或check_dirs
(預設路徑為.
)。
筆記:
對於大型目錄樹來說,
check_dirs
最初可能看起來停滯不前。這是因為在呼叫和列印任何內容for d in "$dir"**/
之前需要完全展開。check_dir
這些函數被故意定義為子 shell(
check_dir () (
而不是check_dir () {
),因此 shell 選項 (shopt
) 和所有變數都是本地的。如果你想
check_dir
統計隱藏檔案的數量,你需要dotglob
這個函數(即shopt -s nullglob dotglob
)。如果你想
check_dirs
下降到隱藏目錄,你需要dotglob
這個函數(即shopt -s nullglob globstar dotglob
)。除非目錄名稱包含換行符,否則可以使用標準工具輕鬆解析
check_dir
或 的輸出。check_dirs
有用的指令:sort -n
、grep $'^2\t1\t'
、cut -f 3-
。例如,要尋找下
./
只有一個*fastq.gz
檔案和零個*spring
檔案的目錄:check_dirs | grep $'^1\t0\t' | cut -f 3-