Tengo problemas para citar un nombre de archivo que eventualmente se pasa a chmod
. El script se escribió originalmente para SSH StrictModes
y authorized_keys
, pero tuve que expandirlo debido a un error UMASK
que causó algunas molestias en el sistema de archivos. El guión está a continuación, y está produciendo montones de:
chmod: /Users/<user>/Library/Application: No such file or directory
chmod: Support/TextMate/Managed/Bundles/HTML.tmbundle/Macros/Delete: No such file or directory
chmod: whitespace: No such file or directory
chmod: between: No such file or directory
chmod: tags.plist: No such file or directory
...
chmod: /Users/<user>/Library/Caches/com.operasoftware.Opera/Media: No such file or directory
chmod: Cache/index: No such file or directory
cut: stdin: Illegal byte sequence
...
He intentado algunas soluciones alternativas, pero ninguna de ellas ha ayudado. Intenté usar comillas dobles como ""$file""
, pero el problema persistió. También probé las marcas de retroceso (que se desaconsejan en este caso), pero el problema persistió.
Lo más cerca que estuve de citar fue lo disfuncional "\"""$file""\""
. Pero luego chmod
se quejó de que el nombre del archivo (con comillas) no era un archivo real:
$ sudo ~/fix-perms.sh
chmod: "/Users/Shared/.localized": No such file or directory
chmod: "/Users/<user>/.CFUserTextEncoding": No such file or directory
chmod: "/Users/<user>/.lesshst": No such file or directory
¿Cómo cito el nombre de archivo que sale del find
que se pasa chmod
? ¿O cómo puedo chmod
tomar el nombre del archivo como un solo argumento?
$ cat ~/fix-perms.sh
#!/bin/bash
# Directories
find /Users/* -type d -exec chmod 0700 {} \;
find /Users/Shared -type d -exec chmod 0777 {} \;
# Files
for file in `find /Users/* -type f`;
do
if [ `file "$file" | cut -d":" -f 2 | grep -i -c executable` -eq 0 ];
then
`chmod 0600 "$file"`
else
`chmod 0700 "$file"`
fi
done
for user in `ls -A /Users`;
do
if [ -e "/Users/$user/.ssh/authorized_keys" ];
then
chmod 0600 "/Users/${user}/.ssh/authorized_keys"
fi
done
fwiw, find [options] -print0
, cuando se usa junto con (conectado a) xargs -0 [options]
, maneja los nombres de archivo con espacios, sin alterar los for
bucles o IFS
:
find /Users ! -path '/Users/Shared*' -type f -print0 | xargs -0 -I {} \
bash -c 'if [[ "$(file -b --mime-type -- "{}")" = "application/x-mach-binary" ]]; then
chmod 700 "{}"
else
chmod 600 "{}"
fi'
find /path -type d -maxdepth 1 ! -perm 0700 -exec chmod 0755 {} \;
es -maxdepth #
arbitraria, a veces no necesita o no quiere ir demasiado lejos en el árbol.Pude resolver el problema cambiando IFS
y IFS=$(echo -en "\n\b")
no citando el nombre del archivo. IFS
es Internal Field Separator , se usa (entre otros) para dividir palabras después de expansiones de shell, e incluye un espacio por defecto.
Encontré el IFS
truco en BASH Shell: For Loop File Names With Spaces de nixCraft .
$ cat fix-perms.sh
#!/bin/bash
SAVED_IFS=$IFS
IFS=$(echo -en "\n\b")
# Directories
chmod 0755 /Users
find /Users/* -type d -exec chmod 0700 {} \;
find /Users/Shared -type d -exec chmod 0777 {} \;
# Files
for file in `find /Users/* -type f`;
do
if [ `file "$file" | cut -d":" -f 2 | grep -i -c executable` -eq 0 ];
then
chmod 0600 "$file"
else
chmod 0700 "$file"
fi
done
for user in `ls -A /Users`;
do
if [ -e "/Users/$user/.ssh/authorized_keys" ];
then
chmod 0600 "/Users/${user}/.ssh/authorized_keys"
fi
done
IFS=$SAVED_IFS
a\n*\nb
: se analizará en tres palabras: "/Usuarios/algo/a", * y "b"; luego, el * se expandirá a una lista de archivos y subdirectorios en el directorio en el que se encuentra, y el script cambiará sus permisos (tal vez mal, ya que los subdirectorios no son ejecutables). Pero sus usuarios probablemente no harán esto. Probablemente...\b
ahí, pero no \t
? Ingenuamente, pensé \b
que era el tabulador o el retroceso. Entendí un poco el retroceso, pero la campana no tiene sentido para mí.\0
; consulte Mac OS X Lion: ¿Qué son los caracteres no válidos para un nombre de archivo? en Superusuario. Un líder \0
es probablemente una buena manera para que un virus se oculte...find
puede manejar espacios en los nombres de archivo. Usted for loops
está causando los problemas. Puedes poner tu lógica en múltiples find
comandos. No todos los directorios en la carpeta de inicio de un usuario deben ser accesibles solo para ellos mismos. Público y Sitios vienen a la mente. Puede corregirlos por separado en otro comando de búsqueda.
find /Users/* ! -path '/Users/Shared*' -type d ! \( -name Public -o -name Sites \) -exec chmod 0700 {} +
El comando excluye el directorio compartido junto con los directorios público y de sitios y luego cambia los permisos en los directorios restantes.
Puede usar +
en sus find
declaraciones para que find
actúe como si fuera xargs
.
find /Users/Shared -type d -exec chmod 0777 {} +
Suponiendo que los archivos ejecutables en la carpeta de inicio de un usuario son paquetes de aplicaciones, entonces podría hacer esto.
find /Users/* ! -path '/Users/Shared*' type f ! perm -755 -exec chmod 0600 {} +
Shared
o $HOME/Public
. Eso es la guinda del pastel. La principal preocupación son los permisos en los directorios de inicio).La solución de mtklr (y Patrix) funcionará, pero creo que es más simple usar un while read
bucle cuando se trata de una lista de archivos de find ... -print0
:
find /Users '!' -path '/Users/Shared*' -type f -print0 |
while IFS= read -d '' -r file; do
if file "$file" | grep -iq ": .*executable"; then
chmod 700 "$file"
else
chmod 600 "$file"
fi
done
read -d ''
utiliza valores nulos como delimitador. También solía -r
evitar que intentara analizar los escapes, y IFS=
para evitar que recortara los espacios en blanco al final del nombre del archivo (y dado que es un prefijo del read
comando, solo se aplica a ese y no tiene que volver a configurarlo después).
Por cierto, también usé if ... | grep -q ...
: el -q
indica grep
que no se genere nada, pero su estado de salida solo tendrá éxito si encontró al menos una coincidencia. Y dado que if
solo prueba el estado de salida del comando en él, eso es todo lo que se necesita.
Por cierto, esto se basa principalmente en BashFAQ # 20: ¿Cómo puedo encontrar y manejar de manera segura los nombres de archivos que contienen líneas nuevas, espacios o ambos? . Recomiendo darle un vistazo...
bmike
find | xargs sudo chmod
lugar de desenrollar todo en un bucle for donde los espacios te causan problemas para iterar sobre la variable.