![Compruebe si la carpeta contiene archivos con extensiones y escriba directorios en categorías](https://rvso.com/image/1684200/Compruebe%20si%20la%20carpeta%20contiene%20archivos%20con%20extensiones%20y%20escriba%20directorios%20en%20categor%C3%ADas.png)
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.
- Contiene un par de archivos fastq.gz y spring.
- Un archivo fastq.gz y un archivo spring
- Una sola lima de resorte
- Un par de archivos fastq.gz
- Archivo único fastq.gz
Lo usé [ /path/to/dir/*fastq.gz ]
pero recibo unary operator expected
un 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 expected
es 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.gz
a 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.gz
se 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.gz
se procesará tal cual. Puede suceder /path/to/dir/*fastq.gz
que 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 -f
está?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 *spring
archivo 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.gz
coincide 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á etiquetadaintento, 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/dir
o check_dir
(la ruta predeterminada es .
). La función imprimirá la cantidad de *fastq.gz
archivos, una pestaña, la cantidad de *spring
archivos, 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/dir
o check_dirs
(la ruta predeterminada es .
).
Notas:
Para un árbol de directorios grande,
check_dirs
puede parecer que inicialmente se detiene. Esto se debe a quefor d in "$dir"**/
debe expandirse completamente antescheck_dir
de llamar e imprimir algo.Las funciones se definen deliberadamente como subcapas (
check_dir () (
a diferencia decheck_dir () {
), por lo que las opciones de la shell (shopt
) y todas las variables son locales.Si desea
check_dir
contar archivos ocultos, necesitadotglob
esta función (es decirshopt -s nullglob dotglob
).Si desea
check_dirs
descender a directorios ocultos, necesitadotglob
esta función (es decirshopt -s nullglob globstar dotglob
).A menos que los nombres de sus directorios contengan caracteres de nueva línea, la salida de
check_dir
ocheck_dirs
es 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.gz
archivo y exactamente cero*spring
archivos:check_dirs | grep $'^1\t0\t' | cut -f 3-