8 votos

OSX Bash bucle for - problemas con los espacios en los nombres de carpeta?

Me estoy poniendo un poco confundido acerca de cómo manejar los espacios en los nombres de ruta de acceso cuando se devuelve en un bucle for.

Justificación: yo soy la limpieza de los permisos en las carpetas y archivos que tengo que copiar de Windows. La mayoría de los archivos terminan con -rwx------ o -rwxr-xr-x permisos por lo que me gusta hacer "chmod -x *" y "chmod u+x <folders>" así que estoy tratando de los siguientes:

$ alias getdirs='find . -maxdepth 1 -mindepth 1 -type d | cut -c 3-'
$ for i in $(getdirs); do chmod u+x $i; done

que funciona bien, con tal de que los directorios no tienen un espacio en el nombre.

He intentado varias permutaciones de chmod u+x "$i", chmod u+x '$i' y similares para obtener el comportamiento que yo quería, pero fue en vano.

Cómo mejorar mi código bash, que trabaja con los nombres de carpeta que contiene el espacio?

El propósito de esto es para ser capaz de eliminar el "exec" bits de archivos planos (de ahí el chmod -x * parte), pero luego para restaurar los directorios a permitir entrar en ellos (chmod u+x <dirname>). A partir de los comentarios y respuestas, así que ahora estoy pensando que probablemente será más fácil hacerlo con el propio "encontrar" el conjuro

10voto

Este tipo de cosas puede ser complicado en todos los shells de Unix debido a la manera en que el espacio actúa como un separador, la ejecución de alias como parte de los scripts de shell sólo hace las cosas aún más interesantes. Probablemente voy a correr dos pases de encontrar a establecer primero los directorios en orden y, a continuación, la siguiente archivos:

find . -maxdepth 1 -mindepth 1 -type d -exec chmod u+x '{}' \;
find . -maxdepth 1 -mindepth 1 -type f -exec chmod u-x '{}' \;

7voto

SooDesuNe Puntos 3650

En general, la "correcta" forma de analizar la salida de encontrar en una fiesta de bucle es el uso de un while read de bucle, en lugar de un for de bucle. En bash, para bucles de dividir el uso de cualquier espacio en blanco (espacio, tabulador, nueva línea) por defecto, esto se puede cambiar, pero es más fácil y (en mi opinión) limpiador de uso read, en el que se lee una línea en un momento de forma predeterminada.

find . -maxdepth 1 -mindepth 1 -type d | while read i; do chmod u+x "$i"; done

Tenga en cuenta que he citado el "$i" -- eso es tan importante, porque citando variables evita que la cáscara de la división de su contenido (es el mismo problema que for , pero en el otro extremo). También tenga en cuenta que usted no puede usar comillas simples: '$i' volvería un literal $i, más que el contenido de la variable.

Esto todavía va a romper en directorios con saltos de línea en sus nombres. Hay una solución que implica encontrar la -print0, pero sólo la he visto saltos de línea en los nombres de archivo específicos para secuencias de comandos de prueba. No sé si esto funciona con la versión de bash en OSX (tomado de greg wiki):

find . -maxdepth 1 -mindepth 1 -type d -print0 | while IFS= read -r -d '' i; do chmod u+x "$i"; done

Sin embargo, en este caso es más fácil de utilizar globs: un pegote que termina en un / expandirá a sólo directorios, por lo que sólo podría

chmod u+x */

(esto funciona perfectamente bien con los espacios, saltos de línea, cualquier cosa). Más generalmente, un bucle a través de todos los directorios:

for f in */; do stuff with "$f"; done

Desafortunadamente, no hay manera de seleccionar sólo los archivos con globos en cualquier versión de bash (esta es una de las razones por las que prefieren zsh, donde las bolas son lo suficientemente poderoso que usted nunca tiene que preocuparse de encontrar).

3voto

Flavin Puntos 165

Tengo dos sugerencias:

  1. Uso sed poner comillas alrededor de todos los nombres de directorio.
  2. La tubería a xargs con el argumento de -L 1. Esto va a ejecutar un comando en cada línea de la entrada estándar, obviando la for de bucle.

Pruebe este canal:

find . -maxdepth 1 -mindepth 1 -type d | cut -c 3- | sed 's/.*/"&"/' | xargs -L 1 chmod u+x

2voto

Meysam Puntos 38

El quid de la cuestión es que la palabra de división de la que pasa por la sustitución de comandos, por lo que los nombres con espacios en ellos son indistinguibles de los diferentes nombres de la totalidad. Esta expansión no sufren de esta dificultad, así que si hay una manera de identificar a los directorios con un pegote y evitar la sustitución de comandos totalmente, estás en casa gratis. Y allí está:

chmod -x *
chmod u+x */

Pero incluso esto es demasiado trabajo, porque chmod tiene X (capital X) simbólico de la bandera, la cual se aplica el bit de ejecución sólo a los directorios y archivos que ya están ejecutable. Así que usted puede realmente hacer:

chmod -x *
chmod u+X *

1voto

mtnygard Puntos 141

Su alias es sólo tirando de la primera poco antes de que el espacio, o su bucle for es sólo leer el primer bit

Usted puede probar esto mediante la adición de una prueba de comentario en sus comandos, he limitado el alias de sólo tirar el último encontrado directorio para aislar las iteraciones 1, imprime lo que el alias piensa que está recibiendo y, a continuación, se hizo eco de la variable contenido para asegurarse de que coinciden con:

jaravj$ alias getdirs='find . -maxdepth 1 -mindepth 1 -type d | tail -1|  cut -c 3-'
jaravj$ getdirs
jaravj$ for i in $(getdirs); do echo "Filename is "$i; chmod u+x $i; done

EDIT: cambiado do; echo ... a do echo ... como era la prevención de la línea de la ejecución de

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X