Tengo un requisito, si ejecuto un script ./123
con argumentos de ruta vacía, digamos /usr/share/linux-headers-3.16.0-34-generic/.tmp_versions
(este directorio está vacío). Debería mostrar "el directorio está vacío"
Mi código es:
#!/bin/bash
dir="$1"
if [ $# -ne 1 ]
then
echo "please pass arguments"
exit
fi
if [ -e $dir ]
then
printf "minimum file size: %s\n\t%s\n" \
$(du $dir -hab | sort -n -r | tail -1)
printf "maximum file size: %s\n\t%s\n" \
$(du $dir -ab | sort -n | tail -1)
printf "average file size: %s"
du $dir -sk | awk '{s+=$1}END{print s/NR}'
else
echo " directory doesn't exists"
fi
if [ -d "ls -A $dir" ]
then
echo " directory is empty"
fi
Tengo un error que aparece como, si ejecuto el nombre del script ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
(este directorio está vacío).
minimum file size: 4096
/usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
maximum file size: 4096
/usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
average file size: 4
en lugar de mostrar la salida solo "el directorio está vacío" muestra la salida anterior
La salida a continuación debe mostrarse si excedo el script con los argumentos correctos (quiero decir con la ruta de directorio correcta). decir./123 /usr/share
minimum file size: 196
/usr/share
maximum file size: 14096
/usr/share
average file size: 4000
mi salida esperada es: ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
directory is empty.
shell-script
Buda sreekanth
fuente
fuente
Respuestas:
Lo anterior es una prueba compatible con POSIX, y debería ser muy rápido.
ls
mostrará una lista de todos los archivos / directorios en un directorio con excepción.
y..
cada uno por línea y se-q
uote todos los caracteres no imprimibles (para incluir\n
ewlines) en la salida con un?
signo de interrogación. De esta manera, sigrep
recibe incluso un solo carácter en la entrada, devolverá verdadero, de lo contrario, falso.Para hacerlo solo en un shell POSIX:
Un shell POSIX (que no ha deshabilitado
-f
anteriormente la generación de ilename) colocaráset
la"$@"
matriz de parámetros posicionales en las cadenas literales seguidas por elset
comando anterior o en los campos generados por los operadores glob al final de cada uno. Si lo hace, depende de si los globos realmente coinciden con algo. En algunos proyectiles, puede indicarle a un globo que no se resuelve que se expanda a nulo, o nada en absoluto. Esto a veces puede ser beneficioso, pero no es portátil y a menudo viene con problemas adicionales, como tener que configurar opciones especiales de shell y luego desarmarlas.El único medio portátil de manejar argumentos de valor nulo involucra variables vacías o no definidas o
~
expansiones de tilde. Y el último, por cierto, es mucho más seguro que el primero.Por encima del shell solo se prueba la
-e
existencia de cualquiera de los archivos para xistence si ninguno de los tres globos especificados resuelve más de una coincidencia. Por lo tanto, elfor
ciclo solo se ejecuta en absoluto para tres o menos iteraciones, y solo en el caso de un directorio vacío, o en el caso de que uno o más de los patrones se resuelvan solo en un solo archivo. Elfor
tambiénbreak
s si alguno de los globos representan un archivo real - y, como he dispuesto los globos en el orden de mayor probabilidad de que menos, debe dejar de fumar más o menos en la primera iteración cada vez.De cualquier manera, debe implicar solo una
stat()
llamada al sistema : el shell yls
ambos solo debenstat()
consultar el directorio consultado y enumerar los archivos que sus dentries informan que contiene. Esto se contrasta con el comportamiento delfind
cual, en su lugar, se incluiríastat()
cada archivo que pueda incluir en la lista.fuente
ls
caso. Glob y[
están en silencio cuando no tienen acceso. Por ejemplo,[ -e /var/spool/cron/crontabs/stephane ]
informará silenciosamente falso, mientras haya un archivo con ese nombre.Con GNU o BSD modernos
find
, puede hacer:(asume
$dir
no se ve como unfind
predicado (!
,(
,-name...
).POSIXY:
fuente
[-z $dir ]
se queja de que no hay un comando llamado[-z
en la mayoría de los sistemas. Necesita espacios alrededor de los corchetes .[ -z $dir ]
resulta ser verdadero sidir
está vacío, y es falso para la mayoría de los demás valores dedir
, pero no es confiable, por ejemplo, es verdadero si el valor dedir
es= -z
o-o -o -n -n
. Utilice siempre comillas dobles alrededor de las sustituciones de comandos (esto también se aplica al resto de su secuencia de comandos).[ -z "$dir" ]
prueba si el valor de la variabledir
está vacío. El valor de la variable es una cadena, que resulta ser la ruta al directorio. Eso no te dice nada sobre el directorio en sí.No hay operador para probar si un directorio está vacío, como lo hay para un archivo normal (
[ -s "$dir" ]
es cierto para un directorio incluso si está vacío). Una forma sencilla de probar si un directorio está vacío es enumerar su contenido; Si obtiene texto vacío, el directorio está vacío.En sistemas más antiguos que no tienen
ls -A
, puede usarls -a
, pero luego.
y..
están listados.(No sangra la línea que comienza
..
ya que la cadena debe contener solo una nueva línea, no una nueva línea y espacio adicional).fuente
$(…)
es la sustitución del comandoEstás viendo los atributos del directorio en sí.
Desea contar cuántos archivos hay allí:
Entonces, la prueba para "directorio está vacío" es:
Me gusta esto:
fuente
Mi respuesta tldr es:
Cumple con POSIX y, no es que importe mucho, generalmente es más rápido que la solución que enumera el directorio y canaliza la salida a grep.
Uso:
Me gusta la respuesta /unix//a/202276/160204 , que reescribo como:
Enumera el directorio y canaliza el resultado a grep. En cambio, propongo una función simple que se basa en la expansión y comparación global.
Esta función no es POSIX estándar y llama a una subshell con
$()
. Primero explico esta función simple para que podamos comprender mejor la solución final (ver la respuesta tldr más arriba) más adelante.Explicación:
El lado izquierdo (LHS) está vacío cuando no se produce expansión, que es el caso cuando el directorio está vacío. Se requiere la opción nullglob porque, de lo contrario, cuando no hay coincidencia, el glob en sí es el resultado de la expansión. (Tener el RHS coincide con los globos del LHS cuando el directorio está vacío no funciona debido a los falsos positivos que ocurren cuando un globo del LHS coincide con un solo archivo llamado como el globo en sí: el
*
en el globo coincide con la subcadena*
en el nombre del archivo. ) La expresión de llaves{,.[^.],..?}
cubre archivos ocultos, pero no..
o.
.Debido a que
shopt -s nullglob
se ejecuta dentro$()
(un subshell), no cambia lanullglob
opción del shell actual, que normalmente es algo bueno. Por otro lado, es una buena idea establecer esta opción en los scripts, ya que es propenso a errores que un glob devuelva algo cuando no hay coincidencia. Entonces, uno podría establecer la opción nullglob al comienzo del script y no será necesaria en la función. Tengamos esto en cuenta: queremos una solución que funcione con la opción nullglob.Advertencias:
Si no tenemos acceso de lectura al directorio, la función informa lo mismo que si hubiera un directorio vacío. Esto se aplica también a una función que enumera el directorio y grep la salida.
El
shopt -s nullglob
comando no es POSIX estándar.Utiliza la subshell creada por
$()
. No es gran cosa, pero es bueno si podemos evitarlo.Pro:
No es que realmente importe, pero esta función es cuatro veces más rápida que la anterior, medida con la cantidad de tiempo de CPU en el núcleo dentro del proceso.
Otras soluciones:
Podemos eliminar el
shopt -s nullglob
comando que no es POSIX en el LHS y poner la cadena"$1/* $1/.[^.]* $1/..?*"
en el RHS y eliminar por separado los falsos positivos que ocurren cuando solo tenemos archivos nombrados'*'
,.[^.]*
o..?*
en el directorio:Sin el
shopt -s nullglob
comando, ahora tiene sentido eliminar la subshell, pero debemos tener cuidado porque queremos evitar la división de palabras y, sin embargo, permitir la expansión global en el LHS. En particular, las citas para evitar la división de palabras no funcionan, porque también evitan la expansión global. Nuestra solución es considerar los globos por separado:Todavía tenemos división de palabras para el globo individual, pero ahora está bien, porque solo dará como resultado un error cuando el directorio no esté vacío. Agregamos 2> / dev / null, para descartar el mensaje de error cuando hay muchos archivos que coinciden con el glob dado en el LHS.
Recordamos que queremos una solución que también funcione con la opción nullglob. La solución anterior falla con la opción nullglob, porque cuando el directorio está vacío, los LHS también están vacíos. Afortunadamente, nunca dice que el directorio está vacío cuando no lo está. Solo deja de decir que está vacío cuando lo está. Entonces, podemos administrar la opción nullglob por separado. No podemos simplemente agregar los casos,
[ "$1/"* = "" ]
etc., porque estos se expandirán como[ = "" ]
, etc., que son sintácticamente incorrectos. Entonces, usamos[ "$1/"* "" = "" ]
etc. en su lugar. De nuevo tenemos que considerar los tres casos*
,..?*
y.[^.]*
para que coincida con los archivos ocultos, pero no.
y..
. Estos no interferirán si no tenemos la opción nullglob, porque tampoco dicen que está vacía cuando no lo está. Entonces, la solución final propuesta es:Preocupación de seguridad:
Cree dos archivos
rm
yx
en un directorio vacío y ejecútelos*
en la solicitud. El globo*
se expandirárm x
y se ejecutará para eliminarx
. Esto no es un problema de seguridad, porque en nuestra función, los globos se encuentran donde las expansiones no se ven como comandos, sino como argumentos, al igual que enfor f in *
.fuente
$(set -f; echo "$1"/*)
Parece una forma bastante complicada de escribir"$1/*"
. Y esto no coincidirá con directorios o archivos ocultos."$1/*"
(tenga en cuenta que las comillas incluyen*
), por lo que elset -f
y la subshell son innecesarios para eso en particular../* ./.[!.]* ./..?*
). Tal vez pueda incorporar eso para completar la función.Aquí hay otra forma simple de hacerlo. Suponga que D es el nombre completo de la ruta del directorio que desea probar para el vacío.
Luego
Esto funciona porque
tiene como salida
awk elimina la D y si el tamaño es 0, el directorio está vacío.
fuente
fuente
echo
, todo lo que necesitas eslist="$somedir/*"
. Además, esto es complicado y propenso a errores. No ha mencionado que el OP debería dar la ruta del directorio de destino, incluida la barra diagonal, por ejemplo.