Estoy escribiendo un script de shell en el que se comprueba si el directorio bin está presente en todos los directorios de usuarios en el directorio /home. El directorio bin puede estar presente directamente en el directorio de usuarios o en el directorio secundario del directorio de usuarios.
Quiero decir, digamos que tengo un usuario como amit en /home. Entonces, el directorio bin puede estar presente directamente como /amit/bin o puede estar presente como /amit/jash/bin
Ahora mi requisito es que debería tener una lista de directorios de usuarios donde el directorio bin no está presente directamente en el directorio de usuarios o en el directorio secundario del directorio de usuarios. ¡Probé el comando como: find /home -type d! -prueba ejecutiva -e '{}/bin' \; -imprime pero no funciona. Sin embargo, cuando estoy reemplazando el directorio bin con algún archivo, el comando funciona bien. Parece que este comando es particularmente para archivos. ¿Hay algún comando similar para los directorios? Cualquier ayuda en esto será muy apreciada.
Estás en el camino correcto. El problema es que su prueba de "no existe el siguiente directorio en este objetivo" no se puede expresar dentro de las condiciones de búsqueda de tal manera que devuelva solo el directorio de nivel superior. Entonces necesitas anidar, de una forma u otra.
Una estrategia sería usar un bucle for en bash:
$ mkdir foo bar baz one two $ mkdir bar/bin baz/bin $ for d in /home/*/; do find "$d" -type d -name bin | grep -q . || echo "$d"; done foo/ one/ two/ Esto usa la expansión del nombre de la ruta (globbing) para generar la lista de directorios para probar y luego verifica la existencia de "bin". Si esa verificación falla (es decir, no encuentra nada), se imprime el directorio. Tenga en cuenta la barra inclinada final en /home/*/ , lo que garantiza que solo buscará dentro de directorios, en lugar de archivos que puedan existir accidentalmente en /home/ .
Otra posibilidad podría ser usar find anidados, si no quieres depender de bash:
$ find /home/ -type d -depth 1 -not -exec sh -c "find {}/ -type d -name bin -print | grep -q . " \; -print /home/foo /home/one /home/two Esto duplica aproximadamente el efecto del ciclo bash for anterior, pero al anidar find dentro de find -exec . Utiliza grep -q . para convertir la salida de find en un estado de salida que se puede usar como condición para el find externo .
Tenga en cuenta que dado que está buscando un directorio bin , queremos usar test -d en lugar de test -e (que también buscaría un archivo bin, que probablemente no le importe).
Otra opción es usar la redirección de procesos bash. En varias líneas para facilitar la lectura:
cd /home/ comm -3 \ <(printf '%s\n' */ | sed 's|/.*||' | sort) \ <(find */ -type d -name bin | cut -d/ -f1 | uniq) Desafortunadamente, esto requiere que cambie al directorio /home antes de ejecutarse, debido a la forma en que elimina los subdirectorios. Por supuesto, puede colapsar esto en una sola línea grande y larga si se siente tan inclinado.
Esta solución de comm también tiene el riesgo de fallar en directorios con caracteres especiales en sus nombres, como líneas nuevas.
Una última opción es bash-only pero más que una sola línea. Implica restar los directorios que contienen "bin" de la lista completa. Utiliza una matriz asociativa y globstar , por lo que depende de la versión 4 de bash.
#!/usr/bin/env bash shopt -s globstar # Go to our root cd /home # Declare an associative array declare -A dirs=() # Populate the array with our "full" list of home directories for d in */; do dirs[${d%/}]=""; done # Remove directories that contain a "bin" somewhere inside 'em for d in **/bin; do unset dirs[${d%%/*}]; done # Print the result in reproducible form declare -p dirs # Or print the result just as a list of words. printf '%s\n' "${!dirs[@]}"Tenga en cuenta que estamos almacenando directorios en el índice de matriz, lo que (1) nos facilita encontrar y eliminar elementos, y (2) asegura entradas únicas, incluso si un usuario tiene varios directorios "bin" en su hogar.
cd /home find . -maxdepth 1 -type d ! -name . | sort > a find . -type d -name bin | cut -d/ -f1,2 | sort > b comm -23 abAquí, estoy haciendo dos listas ordenadas. El primero contiene todos los directorios de inicio y el segundo contiene el padre superior de cualquier subdirectorio bin. Finalmente, saco cualquier elemento de la primera lista que no esté presente en la segunda.