Verificando a existência de vários diretórios

8

Quero verificar a existência de vários diretórios, dizem, dir1, dir2e dir3, no diretório de trabalho.

Eu tenho o seguinte

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

Mas suspeito que exista uma maneira mais elegante de fazer isso. Não assuma que exista um padrão nos nomes dos diretórios.

O objetivo é verificar a existência de alguns diretórios e a inexistência de outros.

Estou usando o Bash, mas o código portátil é o preferido.

Elegância
fonte
1
"O objetivo é verificar a existência de alguns diretórios e a inexistência de outros." Bem, seu exemplo verifica a existência de todos os diretórios listados. Você pode elaborar essa parte? Está tudo listado ou algum listado? Você precisa verificar se os valores passados ​​são de fato diretórios e não outros tipos de arquivos?
Sergiy Kolodyazhnyy 02/03/19
1
Você não precisa do $PWD, a propósito. [ -d "$PWD/dir1"]é equivalente a [ -d "dir1" ].
terdon

Respostas:

5

Se você já espera que sejam diretórios e está apenas verificando se todos eles existem, você pode usar o código de saída do lsutilitário para determinar se um ou mais "erros ocorreram" :

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

Eu redireciono a saída e stderr para /dev/null, a fim de fazê-la desaparecer, já que nos preocupamos apenas com o código de saída ls, não com a saída. Tudo o que foi escrito para /dev/nulldesaparecer - não é gravado no seu terminal.

Jeff Schaller
fonte
Você pode me ajudar a entender esse comando? Eu sei o que são descritores de arquivos. Eu sei que 1é stdout, 2é stderr e sei o que é redirecionar. Não entendo o significado de /dev/nulle não sei como analisar o comando.
Elegance
@Elegance Adicionei uma pequena explicação. Para obter respostas mais detalhadas sobre / dev / null, consulte unix.stackexchange.com/questions/163352/… e unix.stackexchange.com/questions/438130/…
Jeff Schaller
Ainda tentando descobrir como a sintaxe funciona. Eu li que &>filenameredireciona stdout e stderr para filename. Portanto, o comando não poderia ser simplificado (pelo menos para mim é mais simples) como ls "$PWD/dir1" "$PWD/dir2" "$PWD/dir2" &>/dev/null && echo All there?
Elegance
3
(1) Você provavelmente deve usar a -dopção (a), portanto ls, apenas precisa declarar os diretórios, e não lê-los; e (b) para que o comando seja bem-sucedido, mesmo que o usuário não tenha acesso de leitura aos diretórios. (2) Não vejo nenhuma razão para usá-lo, "$PWD/"exceto para me proteger contra diretórios cujos nomes começam com -(e, é claro, existem maneiras melhores de fazer isso).
G-Man diz 'Restabelecer Monica
1
esse comando pode levar muito mais tempo para ser executado do que o teste na pergunta original. Também não verifica se há diretórios.
Jasen
9

Gostaria de loop:

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

Isso breakcausa um curto-circuito no loop, assim como sua cadeia de&&

Glenn Jackman
fonte
5

Um loop pode ser mais elegante:

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

Este é o Bash. Um mais portátil é o Sh. Lá você pode usar a matriz posicional:

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

Então, para fazer um loop, use "$@".


fonte
5

Por que não apenas:

if [ -d "dir1" -a -d "dir2" -a -d "dir3" ]; then
    echo True
else
    echo False
fi
David Conrad
fonte
Isto é essencialmente o que o OP começou com,But I suspect there is a more elegant way of doing this
Jeff Schaller
5
O POSIX também desencoraja o uso de -a: " -ae -ooperadores binários de primárias (...) foram marcados como obsoletos": pubs.opengroup.org/onlinepubs/9699919799
Elegance
@JeffSchaller É mais conciso, pois faz tudo em uma chamada para testar.
David Conrad
2
não é de todo o mesmo, o original invoca test(aka [) três vezes isso invoca uma vez,
Jasen
1
pubs.opengroup.org/onlinepubs/9699919799/utilities/… é uma referência mais precisa à localização da instrução POSIX.
G-Man diz 'Reinstate Monica'
4

Conforme a pergunta, duas funções portáteis de shell que testam a existência e a inexistência de vários diretórios:

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

Exemplo:

$ 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
fonte
1

O objetivo é verificar a existência de alguns diretórios e a inexistência de outros.   [Enfase adicionada]

Com base na resposta de glenn jackman , podemos testar a inexistência de outros nomes como este:

result = True
para dir in \
        "$ PWD / dir1" \
        "$ PWD / dir2" \
        "$ PWD / dir3" 
Faz
    E se ! [-d "$ dir"]; então
        resultado = Falso
        quebrar
    fi
feito
para dir in \
        "$ PWD / dir4" \
        "$ PWD / dir5" \
        "$ PWD / dir6" 
Faz
    if [-e "$ dir"]; então # Nota: não "!"
        resultado = Falso
        quebrar
    fi
done 
echo "$ result"
Eu costumava [ -e "$dir" ]testar se "$dir"existe; ou seja, se dir5existe, mas é um arquivo, o resultado é False. Se você quiser apenas testar se os nomes no segundo grupo são diretórios, use [ -d "$dir" ], como no primeiro loop.

Como estamos falando de verificar a existência de coisas no diretório de trabalho atual, provavelmente não é necessário especificar $PWD/os nomes; apenas faça

para dir in \
        "dir1" \
        "dir2" \
        "dir3" 
Faz
      ︙

G-Man diz que 'restabelece Monica'
fonte