約 3k 以上のフォルダーがあり、その中には 2 種類のファイル (1 つの spring ファイルと 2 つの fastq.gz ファイル) があります。フォルダーをスキャンして、ディレクトリにファイル拡張子の両方またはどちらかが存在するかどうかを確認したいと考えています。
- fastq.gzとspringファイルのペアを含む
- fastq.gz ファイル 1 つと spring ファイル 1 つ
- スプリングファイル1本
- 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
。
[
シェル構文ではありません。[
通常のコマンド(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-