¿Qué comando se puede usar para verificar si un directorio existe o no, dentro de un script de shell Bash?
¿Qué comando se puede usar para verificar si un directorio existe o no, dentro de un script de shell Bash?
Respuestas:
Para verificar si existe un directorio en un script de shell, puede usar lo siguiente:
if [ -d "$DIRECTORY" ]; then
# Control will enter here if $DIRECTORY exists.
fi
O para verificar si un directorio no existe:
if [ ! -d "$DIRECTORY" ]; then
# Control will enter here if $DIRECTORY doesn't exist.
fi
Sin embargo, como señala Jon Ericson , los comandos posteriores pueden no funcionar según lo previsto si no tiene en cuenta que un enlace simbólico a un directorio también pasará esta verificación. Ej. Ejecutar esto:
ln -s "$ACTUAL_DIR" "$SYMLINK"
if [ -d "$SYMLINK" ]; then
rmdir "$SYMLINK"
fi
Producirá el mensaje de error:
rmdir: failed to remove `symlink': Not a directory
Por lo tanto, los enlaces simbólicos pueden tener que tratarse de manera diferente, si los comandos posteriores esperan directorios:
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
Tome nota particular de las comillas dobles utilizadas para ajustar las variables. La razón de esto se explica por 8jean en otra respuesta .
Si las variables contienen espacios u otros caracteres inusuales, probablemente hará que el script falle.
[ ! -d "$DIRECTORY" ]
será verdad o bien si $DIRECTORY
no existe, o si lo hace existe, pero no es un directorio. Considera algo como if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi
; esto fallará si "$DIRECTORY"
es un archivo. (Por supuesto, usted debe comprobar si mkdir
tuvieron éxito todos modos, hay una serie de razones por las que puede fallar.)
-d
) como el enlace simbólico ( -L
), es más fácil agregar una barra diagonal a la variable, como if [ -d "${THING:+$THING/}" ]
. A un directorio no le importará la barra extra. Un archivo se evaluará como falso. Vacío permanecerá vacío, tan falso. Y un enlace simbólico se resolverá en su destino. Por supuesto, depende de tu objetivo. Si quieres ir allí, está bien. Si desea eliminarlo , entonces el código en esta respuesta es mejor.
Recuerde siempre envolver las variables entre comillas dobles cuando haga referencia a ellas en un script Bash. En la actualidad, los niños crecen con la idea de que pueden tener espacios y muchos otros personajes divertidos en los nombres de sus directorios. (¡Espacios! En mis días, ¡no teníamos espacios elegantes!;))
Un día, uno de esos niños ejecutará su script con $DIRECTORY
set to "My M0viez"
y su script explotará. No quieres eso. Entonces usa esto.
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists, even if it contains spaces
fi
Tenga en cuenta que la prueba -d puede producir algunos resultados sorprendentes:
$ ln -s tmp/ t
$ if [ -d t ]; then rmdir t; fi
rmdir: directory "t": Path component not a directory
Archivo bajo: "¿Cuándo un directorio no es un directorio?" La respuesta: "Cuando se trata de un enlace simbólico a un directorio". Una prueba un poco más exhaustiva:
if [ -d t ]; then
if [ -L t ]; then
rm t
else
rmdir t
fi
fi
Puede encontrar más información en el manual de Bash sobre las expresiones condicionales de Bash y el [
comando incorporado y el comando [[
compuesto .
if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi
... o, para un comando que funciona en ambos enlaces y directorios:rm -r tmpdir
Creo que la versión de doble paréntesistest
hace que escribir pruebas de lógica sea más natural:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
if [[ -d "$TARFILE" ]]
[[ ]]
se admite la ceniza con opciones de compilación predeterminadas , pero de hecho no proporciona ninguna funcionalidad diferente [ ]
. Si la portabilidad es una preocupación, quédese [ ]
y use las soluciones necesarias.
Forma más corta:
[ -d "$DIR" ] && echo "Yes"
if $dir is a dir, then echo "yes"
? Un poco de explicación ayudaría :)
cmd && other
es una abreviatura común para if cmd; then other; fi
: funciona con la mayoría de los lenguajes de programación que admiten la lógica booleana, y se conoce como evaluación de cortocircuito .
set -e
(que es una práctica recomendada de programación de shell ).
[ -d "$DIR" ]
está marcado (seguido de && echo Yes
), por lo que creo set -e
que no hace ninguna diferencia en el comportamiento del script (es decir, si la prueba falla, el script continúa normalmente).
Para verificar si existe un directorio, puede usar una if
estructura simple como esta:
if [ -d directory/path to a directory ] ; then
# Things to do
else #if needed #also: elif [new condition]
# Things to do
fi
También puedes hacerlo en negativo:
if [ ! -d directory/path to a directory ] ; then
# Things to do when not an existing directory
Nota : ten cuidado. Deje espacios vacíos a ambos lados de las llaves de apertura y cierre.
Con la misma sintaxis puedes usar:
-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 script simple para probar si un directorio o archivo está presente o no:
if [ -d /home/ram/dir ] # For file "if [-f /home/rama/file]"
then
echo "dir present"
else
echo "dir not present"
fi
Un script simple para verificar si el directorio está presente o no:
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
Las secuencias de comandos anteriores verificarán si el directorio está presente o no
$?
si el último comando es exitoso, devuelve "0", de lo contrario, un valor distinto de cero. Supongamos tempdir
que ya está presente. Luego mkdir tempdir
dará un error como el siguiente:
mkdir: no se puede crear el directorio 'tempdir': el archivo existe
Puedes usar test -d
(ver man test
).
-d file
Verdadero si el archivo existe y es un directorio.
Por ejemplo:
test -d "/etc" && echo Exists || echo Does not exist
Nota: El test
comando es el mismo que la expresión condicional [
(ver:) man [
, por lo que es portátil a través de scripts de shell.
[
- Este es un sinónimo de latest
construcción, pero el último argumento debe ser]
, literal , para que coincida con la apertura[
.
Para posibles opciones o ayuda adicional, verifique:
help [
help test
man test
o man [
O para algo completamente inútil:
[ -d . ] || echo "No"
Aquí hay un lenguaje muy pragmático:
(cd $dir) || return # Is this a directory,
# and do we have access?
Normalmente lo envuelvo en una función:
can_use_as_dir() {
(cd ${1:?pathname expected}) || return
}
O:
assert_dir_access() {
(cd ${1:?pathname expected}) || exit
}
Lo bueno de este enfoque es que no tengo que pensar en un buen mensaje de error.
cd
ya me dará un mensaje estándar de una línea al error estándar . También proporcionará más información de la que podré proporcionar. Al realizar cd
dentro de una subshell ( ... )
, el comando no afecta el directorio actual de la persona que llama. Si el directorio existe, este subshell y la función son solo un no-op.
El siguiente es el argumento de que pasamos a cd
: ${1:?pathname expected}
. Esta es una forma más elaborada de sustitución de parámetros que se explica con más detalle a continuación.
Tl; dr: si la cadena que se pasa a esta función está vacía, nuevamente salimos de la subshell ( ... )
y regresamos de la función con el mensaje de error dado.
Citando de la ksh93
página del manual:
${parameter:?word}
Si
parameter
se establece y no es nulo, sustituya su valor; de lo contrario, imprimaword
y salga del shell (si no es interactivo). Siword
se omite, se imprime un mensaje estándar.
y
Si
:
se omiten los dos puntos de las expresiones anteriores, entonces el shell solo verifica si el parámetro está configurado o no.
La redacción aquí es peculiar de la documentación del shell, ya que word
puede referirse a cualquier cadena razonable, incluido el espacio en blanco.
En este caso particular, sé que el mensaje de error estándar 1: parameter not set
no es suficiente, así que amplío el tipo de valor que esperamos aquí: elpathname
de un directorio.
Una nota filosófica:
El shell no es un lenguaje orientado a objetos, por lo que el mensaje dice que pathname
no directory
. En este nivel, prefiero que sea simple: los argumentos de una función son solo cadenas.
test -d
como explicó @Grundlefleck.
test -d /unreadable/exists
fallará, incluso si el argumento existe.
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
El código anterior verifica si el directorio existe y si se puede escribir.
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
fi
space
después [
-> [`` -d . recibí un error por falta de espacio
Escriba este código en el indicador de Bash:
if [ -d "$DIRECTORY" ]; then
# If true this block of code will execute
fi
find
Verifique la existencia de la carpeta dentro de los subdirectorios:
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
Verifique la existencia de una o varias carpetas en función de un patrón dentro del directorio actual:
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
Ambas combinaciones. En el siguiente ejemplo, verifica la existencia de la carpeta en el directorio actual:
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'
. ¿Te importa si añado en tu respuesta este truco? Cheers;)
En realidad, debe usar varias herramientas para obtener un enfoque a prueba de balas:
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
No hay necesidad de preocuparse por espacios y caracteres especiales siempre y cuando utilice "${}"
.
Tenga en cuenta que [[]]
no es tan portátil como []
, pero dado que la mayoría de las personas trabajan con versiones modernas de Bash (ya que, después de todo, la mayoría de las personas ni siquiera trabajan con la línea de comando :-p), el beneficio es mayor que el problema.
¿Has considerado simplemente hacer lo que quieras hacer en el if
lugar de mirar antes de saltar?
Es decir, si desea verificar la existencia de un directorio antes de ingresarlo, intente hacer esto:
if pushd /path/you/want/to/enter; then
# Commands you want to run in this directory
popd
fi
Si el camino que le das pushd
existe, lo ingresarás y saldrá con 0
, lo que significa quethen
se ejecutará parte de la declaración. Si no existe, no sucederá nada (aparte de algún resultado que indique que el directorio no existe, lo que probablemente sea un efecto secundario útil para la depuración).
Parece mejor que esto, que requiere repetirse:
if [ -d /path/you/want/to/enter ]; then
pushd /path/you/want/to/enter
# Commands you want to run in this directory
popd
fi
Lo mismo funciona con cd
, mv
, rm
, etc ... si se los pruebe archivos que no existen, que van a salir con un error e imprimir un mensaje que dice que no existe, y su then
se omitirán bloque. Si los prueba en archivos que existen, el comando se ejecutará y saldrá con un estado de 0
, permitiendo que su then
bloque se ejecute.
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
NB: Citar variables es una buena práctica.
Explicación:
-d
: verifica si es un directorio-L
: verifica si es un enlace simbólicoPara verificar más de un directorio, use este código:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
Verifique si el directorio existe, de lo contrario haga uno:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
mkdir -p "$DIRECTORY"
para el mismo efecto.
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
Esta respuesta envuelta como un script de 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";
El uso de la -e
comprobación buscará archivos y esto incluye directorios.
if [ -e ${FILE_PATH_AND_NAME} ]
then
echo "The file or directory exists."
fi
Según el comentario de Jonathan :
Si desea crear el directorio y todavía no existe, entonces la técnica más simple es usar el mkdir -p
que crea el directorio, y cualquier directorio faltante en la ruta, y no falla si el directorio ya existe, por lo que puede hacerlo todo a la vez con:
mkdir -p /some/directory/you/want/to/exist || exit 1
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists
fi
Eso no es completamente cierto...
Si desea ir a ese directorio, también debe tener los derechos de ejecución en el directorio. Quizás también necesite tener derechos de escritura.
Por lo tanto:
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 el file
programa. Teniendo en cuenta que todos los directorios también son archivos en Linux, bastaría con emitir el siguiente comando:
file $directory_name
Comprobación de un archivo inexistente: file blah
Salida: cannot open 'blah' (No such file or directory)
Comprobando un directorio existente: file bluh
Salida: bluh: directory
El ls
comando junto con la -l
opción (lista larga) devuelve información de atributos sobre archivos y directorios.
En particular, el primer carácter de ls -l
salida suele ser a d
o a -
(guión). En el caso de d
uno, el listado es un directorio seguro.
El siguiente comando en una sola línea le dirá si la ISDIR
variable dada contiene una ruta a un directorio o no:
[[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
Uso práctico:
[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;
Si desea verificar si existe un directorio, independientemente de si es un directorio real o un enlace simbólico, use esto:
ls $DIR
if [ $? != 0 ]; then
echo "Directory $DIR already exists!"
exit 1;
fi
echo "Directory $DIR does not exist..."
Explicación: El comando "ls" da un error "ls: / x: No existe tal archivo o directorio" si el directorio o enlace simbólico no existe, y también establece el código de retorno, que puede recuperar mediante "$?", A no -nulo (normalmente "1"). Asegúrese de verificar el código de retorno directamente después de llamar "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"
Si se encuentra un problema con uno de los enfoques proporcionados anteriormente:
Con el ls
comando; los casos en que no existe un directorio: se muestra un mensaje de error
[[ `ls -ld SAMPLE_DIR| grep ^d | wc -l` -eq 1 ]] && echo exists || not exists
-ksh: no: no encontrado [No existe tal archivo o directorio]
Existen excelentes soluciones, pero en última instancia, cada script fallará si no está en el directorio correcto. Entonces código como este:
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
se ejecutará con éxito solo si en el momento de la ejecución se encuentra en un directorio que tiene un subdirectorio en el que está buscando.
Entiendo la pregunta inicial como esta: para verificar si existe un directorio independientemente de la posición del usuario en el sistema de archivos. Entonces, usar el comando 'encontrar' podría hacer el truco:
dir=" "
echo "Input directory name to search for:"
read dir
find $HOME -name $dir -type d
Esta solución es buena porque permite el uso de comodines, una característica útil al buscar archivos / directorios. El único problema es que, si el directorio buscado no existe, el comando 'buscar' no imprimirá nada en la salida estándar (no es una solución elegante para mi gusto) y tendrá una salida cero. Tal vez alguien podría mejorar esto.
locate
pero no para nada más ...
--
se recomienda su uso (marcador de fin de opciones). De lo contrario, si su variable contiene algo que parece una opción, el script fallará al igual que con los espacios.