Shell Script: chmod recursivo diferenciando archivos y directorios
05 de Diciembre de 2007 en Programación, Linux
Lecturas: 7,885

Permisos chmodCuántas veces tenemos un árbol de directorios y por cualquier cosa debemos aplicarle un chmod diferente a los archivos y a los directorios?

Pues bién, me he encontrado con esta necesidad y he pensado un shell script que recorriera un árbol de directorios dado y aplicara el chmod dependiendo si encuentra un archivo o un directorio. Y ya que estaba metido, lo he adornado aceptando parámetros y haciendo alguna pequeña comprobación antes de que se ponga a trabajar.

A continuación cuelgo el código fuente y lo explico un poco.

Bueno, en primer lugar se comprueba por la existencia de argumentos. Si no hay argumentos, no se puede continuar porque se necesita saber dónde hacer el trabajo… y qué permisos se van a poner!

if [ $# -ne 3 ]; then
echo Bad number of arguments.
echo Usage: $0 ‘path file_permisions dir_permisions’
exit
fi

Luego defino tres variables que vienen a ser los argumentos definidos, pero así el resto del código se entiende mejor ;)

WORK_PATH=$1
FILE_PERM=$2
DIR_PERM=$3

Y seguidamente se hacen unas comprobaciones… Básicamente se comprueba que los permisos que se deben aplicar sean numéricos, mayores que 0 y menores que 777

echo $FILE_PERM | grep [^0-9] > /dev/null 2>&1
if [ “$?” -eq “0″ ]; then
echo Argument File Permision is not a number
echo Must be a 3 digit number like 644 between 0 and 777
exit
fi
if [ “$FILE_PERM” -lt “0″ ]; then
echo Bad File Permision argument
echo Must be a 3 digit number like 644 between 0 and 777
exit
fi
if [ “$FILE_PERM” -gt “777″ ]; then
echo Bad File Permision argument
echo Must be a 3 digit number like 644 between 0 and 777
exit
fi
echo $DIR_PERM | grep [^0-9] > /dev/null 2>&1
if [ “$?” -eq “0″ ]; then
echo Argument Directory Permision is not a number
echo Must be a 3 digit number like 755 between 0 and 777
exit
fi
if [ “$DIR_PERM” -lt “0″ ]; then
echo Bad Directory Permision argument
echo Must be a 3 digit number like 755 between 0 and 777
exit
fi
if [ “$DIR_PERM” -gt “777″ ]; then
echo Bad Directory Permision argument
echo Must be a 3 digit number like 755 between 0 and 777
exit
fi

Y ahora empieza lo bueno. Primero de todo necesito el árbol de directorios. Lo recojo con el ls y le agrego algunos parámetros que me van a simplificar el tema:

  • a: Para ver los archivos ocultos
  • A: Para que las entradas “.” y “..” no me las dé.
  • 1: Para que sólo me devuelva los nombres de los archivos y directorios… ni tamaños ni nada.
  • R: Para que sea recursivo

path=”./”
for iteration in `ls -aA1R`
do

Luego necesito recuperar el path, porque si no a la que entre en un segundo nivel de directorios el chmod no va a saber dónde está el archivo. Con el grep recojo sólo las iteraciones que el ls me pone para definirme que ha entrado en un segundo nivel de profundidad. Luego defino que lo que hay son campos separados por dos puntos y que quiero el primero, así me quita los dos puntos de la ruta que el ls printa. Si al final queda algo lo copio a la variable path, quien guardará la info del path dónde se encuentra el puntero. Así, cada vez que se cambie de directorio yo sé dónde está ;)

tmp_path=`echo $iteration | grep ‘\.\/[a-zA-Z\/_0-9\-\s]*’ | cut -d”:” -f1`
if [ “$tmp_path” != “” ]; then
path=”$tmp_path/”
fi

Justo después necesito el nombre del archivo. De hecho, haciendo la inversa del anterior ya me serviría, pero en ése punto he tenido que modificar alguna otra cosa y me ha salido una instrucción más limpia… que podría usar su inversa para recoger el path, pero bueno, de momento lo dejo así. Después compruebo que la acción anterior haya dado algun resultado.

element=`echo $iteration | grep [^\:]$`
if [ “$?” -eq “0″ ]; then

Y ya por último, monto el path entero y compruebo si el resultado es un archivo o un directorio, para aplicarle un chmod con el código de permisos correcto.

final_path=$path$element
if [ -d $final_path ]; then
chmod $DIR_PERM $final_path
else
chmod $FILE_PERM $final_path
fi

Bueno, soy consciente que no es el mejor código del mundo, pero sirve… Si os queréis descargar el archivo completo podéis hacerlo desde aquí: chmodr.sh

Atención: En los códigos aquí escritos hay tres tipos de comillas: simples, dobles y acentos graves sin letra. Wordpress no imprime correctamente éstos carácteres, así que aconsejo la descarga del script para ver claramente qué carácter es el correcto.

Saludos.

Tag:
 Enviar a Fresqui

Leer los Comentarios

[ # 10912 ] Comment desde Uno que no sabe mucho [05 de Diciembre de 2007, 01:37]

Hola,

Yo creo que en el ls -aA… la ‘a’ en minúscula no hace falta.

Por otro lado, que pasa si se encuentra con un link simbólico?

Gracias.

[ # 10915 ] Comment desde Xavi [05 de Diciembre de 2007, 02:03]

Buenas

Si no le pongo la ‘a’ minúscula, archivos como el .htaccess no saldrían…

Según la documentación del chmod (que, básicamente, es lo que hace el script), se cambiaran los permisos del archivo dónde apunta, no el enlace propiamente. Mira la documentación del chmod

Saludos!

[ # 10918 ] Comment desde mario [05 de Diciembre de 2007, 02:56]

Madre mía pedazo de script !!, jejeje, la verdad es que han sido varias veces las que he tenido que darle unos permisos determinados a ficheros y otros a directorios y creo que mi forma de hacerlo es bastante más sencilla usando el maravilloso comando “find”, simplemente sería ejecutar estas dos líneas:

find $WORK_PATH -type f -exec chmod $FILE_PERM {} \;
find $WORK_PATH -type d -exec chmod $DIR_PERM {} \;

La primera de ellas para los ficheros y la segunda para los directorios, eso es todo.

[ # 10919 ] Comment desde Oriol [05 de Diciembre de 2007, 03:07]

Como aportación yo esto normalmente lo soluciono con el comando “find” junto con “xargs”, con algo como:


find /directorio -type f -print0 | xargs -0 chmod 0644
find /directorio -type d -print0 | xargs -0 chmod 0755

para fijar los permisos de todos los directorios dentro de “/directorio” a 0755 y los archivos regulares a 0644.

[ # 10920 ] Comment desde cancollons [05 de Diciembre de 2007, 03:12]

Otra opción es utilizar find para distinguir ficheros y directorios, de modo que te quedaría algo así:

[ validaciones iniciales… ]
find $WORK_PATH -type d -exec chmod $DIR_PERM ‘{}’ \;
find $WORK_PATH -type f -exec chmod $FILE_PERM ‘{}’ \;

[ # 10923 ] Comment desde Xavi [05 de Diciembre de 2007, 03:46]

Vale, me doy por aludido… no había usado el comando find… :D Gracias a los tres por el consejo ;)

[ # 10925 ] Comment desde ubersoldat [05 de Diciembre de 2007, 04:14]

Además de lo obviamente sencillo que habría sido utilizar ‘find’, utilizar ‘ls’ es otra gran cagada. No todos los ‘ls’ de sistemas Unix tienen las mismas opciones, por lo cual la portabilidad a la basura. Lo indicado en estos casos es utilizar expresiones regulares

for i in *; if [[ $i -f ]]; then x… etc…

http://www.shelldorado.com/goodcoding/cmdargs.html

Para futuras referencias:
http://wooledge.org:8000/BashFAQ
http://wooledge.org:8000/BashGuide

[ # 10926 ] Comment desde Xavi [05 de Diciembre de 2007, 04:17]

Vaya somantapalos me estáis dando… :-S nada, pues gracias por las referencias. De todo se aprende…

[ # 10927 ] Comment desde Matias Aguirre [05 de Diciembre de 2007, 04:32]

Que lio!

La cuestion es algo mas simple.

find . -type d -exec chmod 775 \{\} \;

Donde “d” es directorios.

Mas Info: http://www.matware.com.ar/bash/cambiar-permisos-solo-a-directorios.html

Saludos

[ # 15774 ] Comment desde fsaravia [21 de Enero de 2008, 08:38]

tuve que modificarlo para que me tome los nombres de archivos y directorios con espacios:

poner al comienzo:
IFS=$’\n’
(ref: http://gnunezr.blogspot.com/2007/10/bash-y-nombres-de-archivo-con-espacios.html)

y ejecutar:
chmod $DIR_PERM “$final_path” # Con comillas

[ # 17829 ] Comment desde Fool [21 de Febrero de 2008, 10:23]

¿Gran cagada lo del ls? Al menos el chaval se lo ha currado. Qué presuntuoso. Qué poca educación.

[ # 17852 ] Comment desde Xavi [22 de Febrero de 2008, 08:47]

Bah. Es igual. Me lo pasé bién haciéndolo.
Y no todo el mundo tiene educación.

Salu10!

[ # 24574 ] Comment desde Ase [13 de Junio de 2008, 07:59]

Gran trabajo :) la verdad es que es un engorro cuando te encuentras con tener que cambiar permisos en plan masivo y encima tener en cuenta que ficheros y directorios no llevan los mismo permisos.

Yo desde hace un tiempo estoy usando Deep para hacer ese tipo de tareas y otras tantas que permite, como renombrados, reemplazos, borrados… Permite patrones de busqueda y esta hecho en Perl.
http://www.neilgunton.com/doc/deep

Lo dicho, a las criticas (destructivas) ni caso xD lo bueno que tiene equivocarse es que uno aprende de los errores ;) anda que no me he peleado yo con el bash :P

Escribe un Comentario





Estadísticas