フォルダに拡張子の付いたファイルが含まれているかどうかを確認し、ディレクトリをカテゴリに書き込みます

フォルダに拡張子の付いたファイルが含まれているかどうかを確認し、ディレクトリをカテゴリに書き込みます

約 3k 以上のフォルダーがあり、その中には 2 種類のファイル (1 つの spring ファイルと 2 つの fastq.gz ファイル) があります。フォルダーをスキャンして、ディレクトリにファイル拡張子の両方またはどちらかが存在するかどうかを確認したいと考えています。

  1. fastq.gzとspringファイルのペアを含む
  2. fastq.gz ファイル 1 つと spring ファイル 1 つ
  3. スプリングファイル1本
  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

[シェル構文ではありません。[通常のコマンド(Bashの組み込みコマンドですが、コマンドです)であり、]最後の口論、必須のものです。その間の何でも議論になります。

シェルは、/path/to/dir/*fastq.gzを呼び出す前に 1 つ以上の単語に展開します[[は、これらの単語に加えて必須の を]引数として認識します。 引数の数と内容に応じて、 は[0 個以上の引数が演算子 ( など-f) であると想定します。

は、単一の引数に展開される[ /path/to/dir/*fastq.gz ]場合に有効になります/path/to/dir/*fastq.gz(「有効になる」は「希望どおりに動作する」と同じではないことに注意してください)。これには、何も*一致しない場合も含まれます。従来 (および Bash のデフォルト) は、一致しない場合は/path/to/dir/*fastq.gzそのまま処理されます。/path/to/dir/*fastq.gz複数の単語に展開される場合もありますが、そのどれもが演算子[が理解できるものではありません。発生したエラーは、パターンが 2 つの単語に展開された場合に発生する可能性が最も高いです。

後で を使用しました[ "$in"/*spring -f ]。これはさらに悪いです。なぜなら、おそらく、 が[ -f some/path ]どこに-fあるかのようなことを言いたかったからです。前にテストへの道。まだ[ -f "$in"/*spring ]堅牢な解決策ではないため"$in"/*spring 一般的に複数の引数に展開される可能性があり、[それらに耐えられません。*springディレクトリごとに最大1つのファイルがあると書かれていますので、あなたの場合このようなコードは、一応は機能するかもしれませんが、それでもまだ貧弱なコードです。

では[、 のようなワイルドカードを使用しないでください。*複数の単語に展開される可能性があります。これはすぐに失敗します。[[中身は違うしかし、それはあなたの目的にも適していません。

パターンが一致するファイルの数を知りたい場合/path/to/dir/*fastq.gz、正しい方法は、展開の結果を配列に割り当てることです。移植可能な配列は 1 つだけです。シェル スクリプト (またはシェル関数) の引数の配列です。また、一致するものが 0 個の場合を検出するには追加のコードが必要です (それでも 1 つの単語が生成されます。展開されていないパターン文字列です)。質問のタグはそのため、名前付き配列とその他の移植性のない機能をいくつか使用します。

# 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

  • 関数は意図的にサブシェル (check_dir () (ではなくcheck_dir () {) として定義されているため、シェル オプション ( 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-

    ./たとえば、正確に 1 つの*fastq.gzファイルと正確に 0 つの*springファイルを含むディレクトリを検索するには、次のようにします。

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

関連情報