檢查資料夾是否包含帶有副檔名的檔案並將目錄寫入類別

檢查資料夾是否包含帶有副檔名的檔案並將目錄寫入類別

我有大約 3k + 資料夾,它們可以有兩種類型的文件,一個 spring 檔案和一對 fastq.gz 檔案。我想掃描資料夾並了解目錄中是否存在兩個或其中一個檔案副檔名 -

  1. 包含一對fastq.gz和spring文件
  2. 1個fastq.gz檔案和spring文件
  3. 單一彈簧文件
  4. 一對 fastq.gz 文件
  5. 單一 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/dircheck_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/dircheck_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 -ngrep $'^2\t1\t'cut -f 3-

    例如,要尋找下./只有一個*fastq.gz檔案和零個*spring檔案的目錄:

    check_dirs | grep $'^1\t0\t' | cut -f 3-
    

相關內容