Compruebe si la carpeta contiene archivos con extensiones y escriba directorios en categorías

Compruebe si la carpeta contiene archivos con extensiones y escriba directorios en categorías

Tengo alrededor de 3k + carpetas y pueden tener dos tipos de archivos, un solo archivo Spring y un par de archivos fastq.gz. Quiero escanear las carpetas y saber si ambas o alguna de las extensiones de archivo están presentes en el directorio.

  1. Contiene un par de archivos fastq.gz y spring.
  2. Un archivo fastq.gz y un archivo spring
  3. Una sola lima de resorte
  4. Un par de archivos fastq.gz
  5. Archivo único fastq.gz

Lo usé [ /path/to/dir/*fastq.gz ]pero recibo unary operator expectedun error y el uso [[ ]]no parece probar las cosas correctamente.

El script real que utilicé es:

check_dir () {
in="$1"
echo "$in Checking for spring"
[ "$in"/*spring -f ] && echo "$in"
}
export -f check_dir

Estoy usando bash, se agradecerá cualquier ayuda con la lógica.

Respuesta1

unary operator expectedes porque [y *(en tu *fastq.gz) trabajas de forma independiente.

[no es la sintaxis de shell. [es un comando normal (integrado en Bash, pero sigue siendo un comando) y ]es su últimoargumento, uno obligatorio. Cualquier cosa intermedia también es una discusión.

El shell se expande /path/to/dir/*fastq.gza una o más palabras antes de llamar [. [Verá estas palabras más las obligatorias ]como argumentos. Dependiendo del número de argumentos y de cuáles sean, [espera que cero o más argumentos sean operadores (como -f).

Será [ /path/to/dir/*fastq.gz ]válido si /path/to/dir/*fastq.gzse expande a un solo argumento (tenga en cuenta que "será válido" no equivale a "hará lo que quiera"). Esto incluye casos en los que *no coincide nada; Tradicionalmente (y de forma predeterminada en Bash), si no hay ninguna coincidencia, /path/to/dir/*fastq.gzse procesará tal cual. Puede suceder /path/to/dir/*fastq.gzque se expanda a varias palabras, pero ninguna de ellas parecerá que el operador [las entienda. Lo más probable es que el error que obtuvo se deba a un caso en el que el patrón se expandió a dos palabras.

Más tarde usaste [ "$in"/*spring -f ]. Esto es aún peor, porque probablemente querías algo como ¿ [ -f some/path ]dónde -festá?antesel camino a la prueba. Todavía [ -f "$in"/*spring ]no es una solución sólida porque"$in"/*spring en generalPuede expandirse a múltiples argumentos y [no los soportará. Escribiste que hay como máximo un *springarchivo por directorio, por lo queen tu casoun código como este puede funcionar; Sin embargo, sigue siendo un código deficiente.

Con [, no utilice comodines *que puedan expandirse a varias palabras; esto fallará inmediatamente o pronto.[[es diferente bajo el capópero tampoco es bueno para tu propósito.

Quiere saber con cuántos archivos /path/to/dir/*fastq.gzcoincide un patrón. La forma correcta de hacerlo es asignar el resultado de la expansión a una matriz. Portatilmente sólo hay una matriz: la matriz de argumentos del script de shell (o la función de shell); y necesita código adicional para detectar un caso de coincidencias cero (que aún genera una palabra: la cadena de patrón no expandida). Tu pregunta está etiquetada, así que usaré una matriz con nombre y algunas otras funcionalidades no portátiles:

# 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"
)

Uso: check_dir path/to/diro check_dir(la ruta predeterminada es .). La función imprimirá la cantidad de *fastq.gzarchivos, una pestaña, la cantidad de *springarchivos, una pestaña, finalmente la ruta examinada (impresa con un final /).

Ahora puede analizar un árbol de directorios (la siguiente función requiere que se defina la función anterior):

# 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
)

Uso: check_dirs path/to/diro check_dirs(la ruta predeterminada es .).

Notas:

  • Para un árbol de directorios grande, check_dirspuede parecer que inicialmente se detiene. Esto se debe a que for d in "$dir"**/debe expandirse completamente antes check_dirde llamar e imprimir algo.

  • Las funciones se definen deliberadamente como subcapas ( check_dir () (a diferencia de check_dir () {), por lo que las opciones de la shell ( shopt) y todas las variables son locales.

  • Si desea check_dircontar archivos ocultos, necesita dotglobesta función (es decir shopt -s nullglob dotglob).

  • Si desea check_dirsdescender a directorios ocultos, necesita dotglobesta función (es decir shopt -s nullglob globstar dotglob).

  • A menos que los nombres de sus directorios contengan caracteres de nueva línea, la salida de check_diro check_dirses fácilmente analizable con herramientas estándar. Comandos útiles: sort -n, grep $'^2\t1\t', cut -f 3-.

    Por ejemplo, para buscar directorios ./con exactamente un *fastq.gzarchivo y exactamente cero *springarchivos:

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

información relacionada