¿Cómo configurar variables desde find+exec?

¿Cómo configurar variables desde find+exec?

Estoy intentando escribir un script bash en el que intento encontrar si alguna ubicación tiene archivos vacíos o no y enviar un correo electrónico si los encuentro. Primero pensé en combinar "buscar" y "correo", pero si la ubicación tiene varios archivos vacíos, enviaría varios correos electrónicos, lo cual no quiero, así que pensé en establecer una variable de marca en cero antes de buscarla y configurarla. a 1 dentro de buscar si se encuentra un archivo vacío. Esto es lo que probé:

FLAG=0
find $LOCATION -size 0 -type f -exec sh -c 'export FLAG=1' \;
echo $FLAG

pero el problema es que, incluso si la ubicación tiene archivos vacíos, el valor del indicador no cambia a 1. ¿Qué estoy haciendo mal?

Respuesta1

set -- "${LOCATION}/"*
while [ -s "$1" ] ; do shift ; done
[ -e "$1" ] && FLAG=1

El shell integrado [ test ]se puede utilizar con el -soperador ize. De man test:

-s FILE

FILEexiste y tiene un tamaño mayor que cero

Sin embargo, eso no funcionará fácilmente para búsquedas recursivas.

findlo hará, pero para una cuestión tan simple como establecer un valor booleano, realmente no es una buena opción para este caso. lspuede realizar búsquedas recursivas con la misma rapidez, se puede configurar fácilmente para proporcionar el tamaño del archivo como primer campo de un listado y para enumerar solo una entrada por línea, garantizado. Si desea establecer el valor booleano de una variable de shell en función de si una lista de archivos recursiva contiene o no un archivo de tamaño 0, entonces esta lses su mejor opción: findsolo complica las cosas. Lo que le interesa son las propiedades de los archivos, no las ubicaciones de los archivos. Aquí es donde lsbrilla, y grephacer ping a su resultado es muy sencillo.

Puedes hacerlo así de fácil:

ls -1aqRsp "$LOCATION" 2>&1 | grep -qv "^ *[^0]\|/"
FLAG=$(($?==0))

Eso solo se configurará FLAGsi 1un archivo...oculto .dotarchivos incluidos: existe en $LOCATIONo en uno de sus directorios secundarios con un tamaño de cero. De lo contrario, $FLAGes 0.

Respuesta2

findestá bifurcando un nuevo proceso hijo cuando lo hace -exec. Ningún proceso hijo puede alterar el entorno de su padre.

Podrías considerar recopilar los nombres de los archivos en cuestión findy luego generar el correo electrónico que deseas en una segunda pasada:

find . -type f -size 0 -print >> /var/tmp/find.sz0
...

Respuesta3

Esto export FLAG=1se realiza en los casos de shinvocación por find. El entorno de un proceso nunca se copia a su padre. Un proceso de shell que solo establece una variable de entorno y sale no logra nada duradero.

Si desea probar si findcoincide con algún archivo, simplemente puede probar si su salida está vacía. Para evitar potencialmente generar una larga lista de archivos solo para descartarla una vez que se haya demostrado que no está vacía, puede truncar la findsalida en la primera oportunidad. GNU find tiene un -quitpredicado y también puede indicarle fácilmente que muestre un solo carácter. En el siguiente fragmento, FLAGtermina vacío si no hay ninguna coincidencia:

FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)

La siguiente variante se establece FLAGen 0 o 1:

FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)
[ -n "$FLAG" ] || FLAG=0

Si desea seguir siendo portátil, puede realizar findcoincidencias de impresión y conservar sólo la primera línea; findmorirá de unSIGPIPEdespués headcierra su lado de la tubería.

if [ -n "$(find "$LOCATION" -size 0 -type f -print | head -n 1 \;)" ]; then
  FLAG=1
else
  FLAG=0
fi

Si este fuera solo un ejemplo simplificado y necesita establecer variables más complejas, existen varios enfoques posibles. Sólo mencionaré un par de los más comunes.

Zsh tiene muchos casos de uso findintegrados gracias aclasificatorios globales. El siguiente fragmento se establece filesen la lista de archivos que coinciden con find $LOCATION -size 0 -type f:

files=(**/*(.DL0))

Ksh y bash también tienen globos recursivos si se habilitan con set -o globstary shopt -s globstarrespectivamente. Sin embargo, tenga en cuenta que con bash hasta 4.2, **se recurre a enlaces simbólicos a directorios, lo que normalmente no es deseable. Puede realizar más procesamiento en el shell.

FIGNORE=         # include dot files in wildcard matches (the ksh way)
GLOBIGNORE=.:..  # include dot files in wildcard matches (the bash way)
for x in **/*; do
done

Si ninguno de los nombres de archivos coincidentes contiene nuevas líneas, puede analizar la salida findcomo una lista delimitada por nuevas líneas.

find "$LOCATION" -size 0 -type f ! -name '*
*' -print | {
  while read -r empty_file; do
  done
}

información relacionada