Comprobando la existencia de múltiples directorios

8

Quiero verificar la existencia de múltiples directorios, digamos dir1, dir2y dir3, en el directorio de trabajo.

Tengo lo siguiente

if [ -d "$PWD/dir1" ] && [ -d "$PWD/dir2" ] && [ -d "$PWD/dir3" ]; then
    echo True
else
    echo False
fi

Pero sospecho que hay una forma más elegante de hacer esto. No asuma que hay un patrón en los nombres de los directorios.

El objetivo es verificar la existencia de unos pocos directorios y la inexistencia de otros.

Estoy usando Bash, pero se prefiere el código portátil.

Elegancia
fuente
1
"El objetivo es verificar la existencia de unos pocos directorios y la inexistencia de otros". Bueno, su ejemplo verifica la existencia de todos los directorios listados. ¿Puedes dar más detalles sobre esta parte? ¿Está todo en la lista o alguno en la lista? ¿Necesita verificar que los valores pasados ​​son en realidad directorios y no otros tipos de archivos?
Sergiy Kolodyazhnyy
1
No necesitas el $PWD, por cierto. [ -d "$PWD/dir1"]es equivalente a [ -d "dir1" ].
terdon

Respuestas:

5

Si ya espera que sean directorios y solo está verificando si todos existen, puede usar el código de salida de la lsutilidad para determinar si se produjeron uno o más "errores" :

ls "$PWD/dir1" "$PWD/dir2" "$PWD/dir3" >/dev/null 2>&1 && echo All there

Redirijo la salida y stderr a /dev/nullpara que desaparezca, ya que solo nos importa el código de salida ls, no su salida. Todo lo que está escrito /dev/nulldesaparece, no está escrito en su terminal.

Jeff Schaller
fuente
¿Me pueden ayudar a entender este comando? Sé lo que son los descriptores de archivo. Sé que 1es stdout, 2es stderr y sé lo que es la redirección. No entiendo el significado de /dev/null, y no sé cómo analizar el comando.
Elegancia
@ Elegancia Agregué una pequeña explicación. Para obtener respuestas más detalladas sobre / dev / null, consulte unix.stackexchange.com/questions/163352/… y unix.stackexchange.com/questions/438130/…
Jeff Schaller
Todavía estoy tratando de descubrir cómo funciona la sintaxis. Leí que &>filenameredirige tanto stdout como stderr a filename. Entonces, ¿no podría simplificarse el comando (al menos para mí es más simple) como ls "$PWD/dir1" "$PWD/dir2" "$PWD/dir2" &>/dev/null && echo All there?
Elegancia
3
(1) Probablemente debería usar la -dopción (a), por lo que lssolo necesita registrar los directorios y no leerlos, y (b) para que el comando tenga éxito incluso si el usuario no tiene acceso de lectura a los directorios. (2) No veo ninguna razón para usar, "$PWD/"excepto para proteger contra directorios cuyos nombres comienzan con -(y, por supuesto, hay mejores formas de hacerlo).
G-Man dice 'Restablece a Monica' el
1
Este comando podría tardar mucho más en ejecutarse que la prueba de la pregunta original. Además, no busca directorios.
Jasen
9

Me gustaría bucle:

result=True
for dir in \
        "$PWD/dir1" \
        "$PWD/dir2" \
        "$PWD/dir3" 
do
    if ! [ -d "$dir" ]; then
        result=False
        break
    fi
done
echo "$result"

Esto breakhace que el bucle se cortocircuite, al igual que su cadena de&&

Glenn Jackman
fuente
5

Un bucle podría ser más elegante:

arr=("$PWD/dir1" "$PWD/dir2" "$PWD/dir2")
for d in "${arr[@]}"; do
    if [ -d "$d"]; then
        echo True
    else
        echo False
    fi
done

Esto es Bash Una más portátil es Sh. Allí puede usar la matriz posicional:

set -- "$PWD/dir1" "$PWD/dir2" "$PWD/dir2"

Luego, para recorrerlo, úsalo "$@".


fuente
5

¿Por qué no solo:

if [ -d "dir1" -a -d "dir2" -a -d "dir3" ]; then
    echo True
else
    echo False
fi
David Conrad
fuente
Esto es esencialmente con lo que comenzó el OP,But I suspect there is a more elegant way of doing this
Jeff Schaller
55
También POSIX desaconseja el uso de -a: " -ay -olos operadores primarios binarios (...) han sido marcados como obsoletos": pubs.opengroup.org/onlinepubs/9699919799
Elegance
@JeffSchaller Es más conciso ya que lo hace todo en una sola llamada para probar.
David Conrad
2
no es lo mismo, las invocaciones originales test(aka [) tres veces esto lo invoca una vez,
Jasen
1
pubs.opengroup.org/onlinepubs/9699919799/utilities/… es una referencia más precisa a la ubicación de la declaración POSIX.
G-Man dice 'Restablece a Mónica' el
4

Según la pregunta, dos funciones de shell portátiles que prueban la existencia y la inexistencia de múltiples directorios:

# Returns success if all given arguments exists and are directories.
ck_dir_exists () {
    for dir do
        [ -d "$dir" ] || return 1
    done
}

# Returns success if none of the given arguments are existing directories.
ck_dir_notexists () {
    for dir do
        [ ! -d "$dir" ] || return 1
    done
}

Ejemplo:

$ mkdir dir1 dir2
$ ck_dir_exists dir1 dir2; echo $?
0
$ ck_dir_exists dir1 dir2 dir3; echo $?
1
$ ck_dir_notexists dir1 dir2 dir3; echo $?
1
$ ck_dir_notexists dir3 dir4; echo $?
0
Kusalananda
fuente
1

El objetivo es verificar la existencia de algunos directorios y la inexistencia de otros.   [Énfasis añadido]

Sobre la base de la respuesta de Glenn Jackman , podemos probar la inexistencia de otros nombres como este:

resultado = verdadero
para dir en \
        "$ PWD / dir1" \
        "$ PWD / dir2" \
        "$ PWD / dir3" 
hacer
    Si ! [-d "$ dir"]; entonces
        resultado = falso
        rotura
    fi
hecho
para dir en \
        "$ PWD / dir4" \
        "$ PWD / dir5" \
        "$ PWD / dir6" 
hacer
    si [-e "$ dir"]; luego # Nota: no "!"
        resultado = falso
        rotura
    fi
echo 
hecho "$ resultado"
Solía [ -e "$dir" ]probar si "$dir"existe; es decir, si dir5existe pero es un archivo, el resultado es False. Si solo desea probar si los nombres en el segundo grupo son directorios, use [ -d "$dir" ], como en el primer bucle.

Como estamos hablando de verificar la existencia de cosas en el directorio de trabajo actual, probablemente no sea necesario especificar $PWD/los nombres; solo haz

para dir en \
        "dir1" \
        "dir2" \
        "dir3" 
hacer
      ︙

G-Man dice 'restablecer a Mónica'
fuente