Quale comando può essere utilizzato per verificare se esiste una directory o meno all'interno di uno script della shell Bash?
Quale comando può essere utilizzato per verificare se esiste una directory o meno all'interno di uno script della shell Bash?
Risposte:
Per verificare se esiste una directory in uno script di shell, è possibile utilizzare quanto segue:
if [ -d "$DIRECTORY" ]; then
# Control will enter here if $DIRECTORY exists.
fi
O per verificare se non esiste una directory:
if [ ! -d "$DIRECTORY" ]; then
# Control will enter here if $DIRECTORY doesn't exist.
fi
Tuttavia, come sottolinea Jon Ericson , i comandi successivi potrebbero non funzionare come previsto se non si tiene conto del fatto che anche un collegamento simbolico a una directory passerà questo controllo. Es. Eseguendo questo:
ln -s "$ACTUAL_DIR" "$SYMLINK"
if [ -d "$SYMLINK" ]; then
rmdir "$SYMLINK"
fi
Produrrà il messaggio di errore:
rmdir: failed to remove `symlink': Not a directory
Quindi i collegamenti simbolici potrebbero dover essere trattati in modo diverso, se i comandi successivi prevedono directory:
if [ -d "$LINK_OR_DIR" ]; then
if [ -L "$LINK_OR_DIR" ]; then
# It is a symlink!
# Symbolic link specific commands go here.
rm "$LINK_OR_DIR"
else
# It's a directory!
# Directory command goes here.
rmdir "$LINK_OR_DIR"
fi
fi
Prendi nota in particolare delle doppie virgolette utilizzate per racchiudere le variabili. La ragione di ciò è spiegata da 8jean in un'altra risposta .
Se le variabili contengono spazi o altri caratteri insoliti, probabilmente lo script non funzionerà.
[ ! -d "$DIRECTORY" ]
sarà vero o se $DIRECTORY
non esiste, o se lo fa esistere, ma non è una directory. Considera qualcosa di simile if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi
; questo fallirà se "$DIRECTORY"
è un file. (Ovviamente dovresti controllare se è mkdir
riuscito comunque; ci sono una serie di ragioni per cui può fallire.)
-d
) che per il symlink ( -L
), è più semplice aggiungere una barra alla variabile, come if [ -d "${THING:+$THING/}" ]
. A una directory non dispiacerà la barra aggiuntiva. Un file verrà valutato come falso. Vuoto rimarrà vuoto, quindi falso. E un collegamento simbolico verrà risolto alla sua destinazione. Certo, dipende dal tuo obiettivo. Se vuoi andare lì, va bene. Se vuoi eliminarlo , allora il codice in questa risposta è migliore.
Ricorda di includere sempre le variabili tra virgolette quando fai riferimento a esse in uno script Bash. I bambini di questi tempi crescono con l'idea di poter avere spazi e molti altri personaggi divertenti nei loro nomi di directory. (Spazi! Ai miei tempi, non avevamo spazi fantasiosi!;))
Un giorno, uno di quei bambini eseguirà la tua sceneggiatura con $DIRECTORY
set "My M0viez"
e la tua sceneggiatura esploderà. Non lo vuoi. Quindi usa questo.
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists, even if it contains spaces
fi
Nota che il test -d può produrre alcuni risultati sorprendenti:
$ ln -s tmp/ t
$ if [ -d t ]; then rmdir t; fi
rmdir: directory "t": Path component not a directory
File in: "Quando una directory non è una directory?" La risposta: "Quando si tratta di un collegamento simbolico a una directory". Un test leggermente più approfondito:
if [ -d t ]; then
if [ -L t ]; then
rm t
else
rmdir t
fi
fi
Puoi trovare maggiori informazioni nel manuale di Bash sulle espressioni condizionali di Bash e sul [
comando incorporato e sul comando [[
composto .
if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi
... oppure, per un comando che funziona su entrambi i collegamenti e le directory:rm -r tmpdir
Trovo che la versione a doppia parentesitest
renda la scrittura dei test logici più naturale:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
if [[ -d "$TARFILE" ]]
sto ottenendo [[: non trovato
[[ ]]
è supportato con le opzioni di compilazione predefinite , ma in realtà non offre funzionalità diverse a [ ]
. Se la portabilità è un problema, attenersi [ ]
e utilizzare le soluzioni alternative necessarie.
Forma più corta:
[ -d "$DIR" ] && echo "Yes"
if $dir is a dir, then echo "yes"
:? Un po 'di spiegazione sarebbe d'aiuto :)
cmd && other
è una scorciatoia comune per if cmd; then other; fi
: funziona con la maggior parte dei linguaggi di programmazione che supportano la logica booleana ed è nota come valutazione del corto circuito .
set -e
(che è una best practice per la programmazione della shell ).
[ -d "$DIR" ]
è spuntato (seguito da && echo Yes
), quindi credo set -e
che non faccia alcuna differenza al comportamento dello script (cioè se il test fallisce, lo script continua normalmente).
Per verificare l'esistenza di una directory è possibile utilizzare una if
struttura semplice come questa:
if [ -d directory/path to a directory ] ; then
# Things to do
else #if needed #also: elif [new condition]
# Things to do
fi
Puoi anche farlo in negativo:
if [ ! -d directory/path to a directory ] ; then
# Things to do when not an existing directory
Nota : fai attenzione. Lasciare spazi vuoti su entrambi i lati delle parentesi graffe di apertura e chiusura.
Con la stessa sintassi puoi usare:
-e: any kind of archive
-f: file
-h: symbolic link
-r: readable file
-w: writable file
-x: executable file
-s: file size greater than zero
Un semplice script per verificare se è presente una directory o un file:
if [ -d /home/ram/dir ] # For file "if [-f /home/rama/file]"
then
echo "dir present"
else
echo "dir not present"
fi
Un semplice script per verificare se la directory è presente o meno:
mkdir tempdir # If you want to check file use touch instead of mkdir
ret=$?
if [ "$ret" == "0" ]
then
echo "dir present"
else
echo "dir not present"
fi
Gli script sopra verificheranno se la directory è presente o meno
$?
se l'ultimo comando ha esito positivo, restituisce "0", altrimenti un valore diverso da zero. Supponiamo che tempdir
sia già presente. Quindi mkdir tempdir
verrà visualizzato un errore come di seguito:
mkdir: impossibile creare la directory 'tempdir': il file esiste
Puoi usare test -d
(vedi man test
).
-d file
Vero se il file esiste ed è una directory.
Per esempio:
test -d "/etc" && echo Exists || echo Does not exist
Nota: il test
comando è uguale all'espressione condizionale [
(vedi:) man [
, quindi è portatile su tutti gli script di shell.
[
- Questo è sinonimo ditest
builtin, ma l'ultimo argomento deve essere letterale]
per corrispondere all'apertura[
.
Per possibili opzioni o ulteriore aiuto, controllare:
help [
help test
man test
o man [
O per qualcosa di completamente inutile:
[ -d . ] || echo "No"
Ecco un linguaggio molto pragmatico:
(cd $dir) || return # Is this a directory,
# and do we have access?
In genere lo avvolgo in una funzione:
can_use_as_dir() {
(cd ${1:?pathname expected}) || return
}
O:
assert_dir_access() {
(cd ${1:?pathname expected}) || exit
}
La cosa bella di questo approccio è che non devo pensare a un buon messaggio di errore.
cd
mi darà già un messaggio standard di una riga per errore standard . Fornirà anche più informazioni di quelle che sarò in grado di fornire. Eseguendo l' cd
interno di una subshell ( ... )
, il comando non influisce sulla directory corrente del chiamante. Se la directory esiste, questa subshell e la funzione sono solo no-op.
Avanti è l'argomento che si passa a cd
: ${1:?pathname expected}
. Questa è una forma più elaborata di sostituzione dei parametri che viene spiegata più dettagliatamente di seguito.
Tl; dr: se la stringa passata in questa funzione è vuota, usciamo di nuovo dalla subshell ( ... )
e torniamo dalla funzione con il messaggio di errore dato.
Citando dalla ksh93
pagina man:
${parameter:?word}
Se
parameter
è impostato e non è null, sostituisce il suo valore; in caso contrario, stampareword
ed uscire dalla shell (se non interattivo). Seword
viene omesso, viene stampato un messaggio standard.
e
Se i due punti
:
vengono omessi dalle espressioni precedenti, la shell controlla solo se il parametro è impostato o meno.
La frase qui è peculiare alla documentazione della shell, come word
può riferirsi a qualsiasi stringa ragionevole, incluso lo spazio bianco.
In questo caso particolare, so che il messaggio di errore standard 1: parameter not set
non è sufficiente, quindi ingrandisco il tipo di valore che ci aspettiamo qui: ilpathname
di una directory.
Una nota filosofica:
La shell non è un linguaggio orientato agli oggetti, quindi il messaggio dice di pathname
no directory
. A questo livello, preferirei che fosse semplice: gli argomenti di una funzione sono solo stringhe.
test -d
come ha spiegato @Grundlefleck.
test -d /unreadable/exists
fallirà, anche se l'argomento esiste.
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
Il codice sopra controlla se la directory esiste e se è scrivibile.
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
fi
space
dopo [
-> [`` -d . ho ricevuto un errore a causa della mancanza di spazio
Digita questo codice al prompt di Bash:
if [ -d "$DIRECTORY" ]; then
# If true this block of code will execute
fi
find
Verifica l'esistenza della cartella all'interno delle sottodirectory:
found=`find -type d -name "myDirectory"`
if [ -n "$found"]
then
# The variable 'found' contains the full path where "myDirectory" is.
# It may contain several lines if there are several folders named "myDirectory".
fi
Verifica l'esistenza di una o più cartelle in base a un modello all'interno della directory corrente:
found=`find -maxdepth 1 -type d -name "my*"`
if [ -n "$found"]
then
# The variable 'found' contains the full path where folders "my*" have been found.
fi
Entrambe le combinazioni. Nel seguente esempio, verifica l'esistenza della cartella nella directory corrente:
found=`find -maxdepth 1 -type d -name "myDirectory"`
if [ -n "$found"]
then
# The variable 'found' is not empty => "myDirectory"` exists.
fi
find -maxdepth 1 -type d -name 'pattern'
. Ti dispiace se aggiungo nella tua risposta questo trucco? Saluti;)
In realtà, dovresti usare diversi strumenti per ottenere un approccio antiproiettile:
DIR_PATH=`readlink -f "${the_stuff_you_test}"` # Get rid of symlinks and get abs path
if [[ -d "${DIR_PATH}" ]] ; Then # Now you're testing
echo "It's a dir";
fi
Non è necessario preoccuparsi di spazi e caratteri speciali finché si utilizza "${}"
.
Nota che [[]]
non è portatile come []
, ma dal momento che la maggior parte delle persone lavora con le versioni moderne di Bash (dal momento che la maggior parte delle persone non lavora nemmeno con la riga di comando :-p), il vantaggio è maggiore del problema.
Hai mai considerato di fare qualsiasi cosa tu voglia fare if
piuttosto che guardare prima di saltare?
Vale a dire, se si desidera verificare l'esistenza di una directory prima di accedervi, provare a fare questo:
if pushd /path/you/want/to/enter; then
# Commands you want to run in this directory
popd
fi
Se il percorso che dai a pushd
esiste esiste, lo inserirai e uscirà con 0
, il che significa chethen
uscirà verrà eseguita parte dell'istruzione. Se non esiste, non accadrà nulla (a parte qualche output che dice che la directory non esiste, il che è probabilmente un utile effetto collaterale comunque per il debug).
Sembra meglio di questo, che richiede di ripetersi:
if [ -d /path/you/want/to/enter ]; then
pushd /path/you/want/to/enter
# Commands you want to run in this directory
popd
fi
La stessa cosa funziona con cd
, mv
, rm
, ecc ... se li cerca su file che non esistono, loro escono con un errore e stampare un messaggio che non esiste, e il tuo then
blocco verranno ignorati. Se li provi su file esistenti, il comando verrà eseguito e uscirà con uno stato di 0
, consentendo l' then
esecuzione del blocco.
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
NB: citare le variabili è una buona pratica.
Spiegazione:
-d
: controlla se è una directory-L
: controlla se si tratta di un link simbolicoPer controllare più di una directory utilizzare questo codice:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
Controlla se la directory esiste, altrimenti creane una:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
mkdir -p "$DIRECTORY"
per lo stesso effetto.
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
Questa risposta è racchiusa in uno script di shell
$ is_dir ~
YES
$ is_dir /tmp
YES
$ is_dir ~/bin
YES
$ mkdir '/tmp/test me'
$ is_dir '/tmp/test me'
YES
$ is_dir /asdf/asdf
NO
# Example of calling it in another script
DIR=~/mydata
if [ $(is_dir $DIR) == "NO" ]
then
echo "Folder doesnt exist: $DIR";
exit;
fi
function show_help()
{
IT=$(CAT <<EOF
usage: DIR
output: YES or NO, depending on whether or not the directory exists.
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ -z "$1" ]
then
show_help
fi
DIR=$1
if [ -d $DIR ]; then
echo "YES";
exit;
fi
echo "NO";
L'uso del -e
controllo controllerà la presenza di file e questo include le directory.
if [ -e ${FILE_PATH_AND_NAME} ]
then
echo "The file or directory exists."
fi
Secondo il commento di Jonathan :
Se vuoi creare la directory e non esiste ancora, la tecnica più semplice è quella di mkdir -p
creare la directory - e tutte le directory mancanti nel percorso - e non fallire se la directory esiste già, quindi puoi fare tutto subito con:
mkdir -p /some/directory/you/want/to/exist || exit 1
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists
fi
Questo non è del tutto vero ...
Se vuoi andare in quella directory, devi anche avere i diritti di esecuzione sulla directory. Forse devi avere anche i diritti di scrittura.
Perciò:
if [ -d "$DIRECTORY" ] && [ -x "$DIRECTORY" ] ; then
# ... to go to that directory (even if DIRECTORY is a link)
cd $DIRECTORY
pwd
fi
if [ -d "$DIRECTORY" ] && [ -w "$DIRECTORY" ] ; then
# ... to go to that directory and write something there (even if DIRECTORY is a link)
cd $DIRECTORY
touch foobar
fi
Usa il file
programma. Considerando che tutte le directory sono anche file in Linux, è sufficiente emettere il seguente comando:
file $directory_name
Verifica di un file inesistente: file blah
Produzione: cannot open 'blah' (No such file or directory)
Verifica di una directory esistente: file bluh
Produzione: bluh: directory
Il ls
comando insieme -l
all'opzione (elenco lungo) restituisce informazioni sugli attributi su file e directory.
In particolare il primo carattere ls -l
dell'output è di solito a d
o a -
(trattino). Nel caso di d
quello elencato è sicuramente una directory.
Il seguente comando in una sola riga ti dirà se la ISDIR
variabile data contiene o meno un percorso in una directory:
[[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
Uso pratico:
[claudio@nowhere ~]$ ISDIR="$HOME/Music"
[claudio@nowhere ~]$ ls -ld "$ISDIR"
drwxr-xr-x. 2 claudio claudio 4096 Aug 23 00:02 /home/claudio/Music
[claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
YES, /home/claudio/Music is a directory.
[claudio@nowhere ~]$ touch "empty file.txt"
[claudio@nowhere ~]$ ISDIR="$HOME/empty file.txt"
[claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directoy"
Sorry, /home/claudio/empty file.txt is not a directory
file="foo"
if [[ -e "$file" ]]; then echo "File Exists"; fi;
Se si desidera verificare l'esistenza di una directory, indipendentemente dal fatto che sia una directory reale o un collegamento simbolico, utilizzare questo:
ls $DIR
if [ $? != 0 ]; then
echo "Directory $DIR already exists!"
exit 1;
fi
echo "Directory $DIR does not exist..."
Spiegazione: Il comando "ls" restituisce un errore "ls: / x: nessun file o directory" se la directory o il collegamento simbolico non esiste e imposta anche il codice di ritorno, che è possibile recuperare tramite "$?", Su non -null (normalmente "1"). Assicurati di controllare il codice di ritorno direttamente dopo aver chiamato "ls".
if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
(1)
[ -d Piyush_Drv1 ] && echo ""Exists"" || echo "Not Exists"
(2)
[ `find . -type d -name Piyush_Drv1 -print | wc -l` -eq 1 ] && echo Exists || echo "Not Exists"
(3)
[[ -d run_dir && ! -L run_dir ]] && echo Exists || echo "Not Exists"
Se viene riscontrato un problema con uno degli approcci forniti sopra:
Con il ls
comando; i casi in cui non esiste una directory: viene visualizzato un messaggio di errore
[[ `ls -ld SAMPLE_DIR| grep ^d | wc -l` -eq 1 ]] && echo exists || not exists
-ksh: not: not found [Nessun file o directory simile]
Ci sono ottime soluzioni là fuori, ma alla fine ogni script fallirà se non sei nella directory giusta. Quindi codice come questo:
if [ -d "$LINK_OR_DIR" ]; then
if [ -L "$LINK_OR_DIR" ]; then
# It is a symlink!
# Symbolic link specific commands go here
rm "$LINK_OR_DIR"
else
# It's a directory!
# Directory command goes here
rmdir "$LINK_OR_DIR"
fi
fi
verrà eseguito correttamente solo se al momento dell'esecuzione ci si trova in una directory con una sottodirectory che si verifica per caso.
Comprendo la domanda iniziale in questo modo: verificare se esiste una directory indipendentemente dalla posizione dell'utente nel file system. Quindi usare il comando 'trova' potrebbe fare il trucco:
dir=" "
echo "Input directory name to search for:"
read dir
find $HOME -name $dir -type d
Questa soluzione è valida perché consente l'uso di caratteri jolly, una funzione utile durante la ricerca di file / directory. L'unico problema è che, se la directory cercata non esiste, il comando 'trova' non stamperà nulla sullo standard output (non è una soluzione elegante per i miei gusti) e avrà comunque un'uscita zero. Forse qualcuno potrebbe migliorare su questo.
locate
ma non bello per nient'altro ...
--
è altamente raccomandato (marker di fine opzioni). Altrimenti, se la tua variabile contiene qualcosa che sembra un'opzione, lo script fallirà proprio come con gli spazi.