检查文件夹是否包含带扩展名的文件并将目录写入类别

检查文件夹是否包含带扩展名的文件并将目录写入类别

我有大约 3k + 个文件夹,它们可以包含两种类型的文件,一个 spring 文件和一对 fastq.gz 文件。我想扫描文件夹并了解目录中是否存在两个或其中一个文件扩展名 -

  1. 包含一对fastq.gz和spring文件
  2. 一个 fastq.gz 文件和 spring 文件
  3. 单个 Spring 文件
  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 ]命令将有效(请注意,“将有效”并不等同于“将执行您想要的操作”)。这包括不匹配任何内容的情况;传统上(在 Bash 中默认情况下)如果没有匹配,则将按原样处理。它可能会扩展到多个单词,其中没有一个看起来像操作员可以理解的。您收到的错误很可能来自模式扩展到两个单词的情况。/path/to/dir/*fastq.gz*/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 -n,,。grep $'^2\t1\t'cut -f 3-

    例如,查找./恰好有一个*fastq.gz文件和恰好零个*spring文件的目录:

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

相关内容