
Mi Qnap NAS tiene un find
comando que carece del -exec
parámetro, por lo que tengo que conectarme a algo. El shell es: GNU bash, versión 3.2.57(2)-lanzamiento-(arm-unknown-linux-gnueabihf)
Estoy intentando configurar el bit setgid en todos los subdirectorios (no archivos) del directorio actual.
Esto no funciona:
find . -type d | xargs chmod g+s $1
Usar "$1"
, "$(1)"
, $("1")
etc. tampoco funcionará. Todos indican que chmod
se le está pasando un nombre de directorio que contiene espacios como dos o más parámetros (escupe su mensaje de ayuda estándar sobre qué parámetros son compatibles).
No me importa usarlo xargs
si no es necesario; Creo que de todos modos se atraganta con los nombres largos, ¿no?
Estos y sus variantes no funcionan:
find . -type d | chmod g+s
find . -type d | chmod g+s "$1"
He pensado en usar awk
o sed
insertar comillas, pero creo que hay una forma más sencilla de hacerlo. ¿Qué hacía la gente antes -exec
? (Lo triste es que probablemente lo sabía, allá por 1995, más o menos, pero hace mucho que lo olvidé).
PD: Varios de estos nombres de directorio contendrán caracteres Unicode, el ?
símbolo, etc. Son originarios de macOS, lo cual es bastante permisivo. Dicho esto, probablemente debería reemplazar todas las ?
instancias con algo como el carácter Unicode ⁇
para que Windows no se ahogue con ellas. Pero eso también requerirá una find
operación similar con esta versión paralizada de find
.
Respuesta1
La salida de find
emite nombres de archivos separados por nuevas líneas 1 . Este no es el formato que xargs
quiere y find
no tiene forma de producir el formato que xargs
quiere: analiza su entrada como elementos separados por espacios en blanco, que \'"
se utilizan para citar. Algunas versiones de xargs
pueden aceptar entradas separadas por nuevas líneas, pero si find
carece de opciones estándar, es probable que xargs
también las tenga.
find . -type d | xargs chmod g+s
funciona siempre que los nombres de sus directorios no contengan espacios en blanco o archivos \'"
. Tenga en cuenta que no hay ningún $1
: que tenga significado para un shell, pero ningún shell participa en el análisis de la salida find
y la alimentación de chmod
, solo xargs
.
Si find
tiene -print0
y xargs
tiene -0
, puede usar estas opciones para pasar nombres de archivos delimitados por nulos, lo que funciona con nombres de archivos arbitrarios.
find . -type d -print0 | xargs -0 chmod g+s
Si xargs
admite la opción estándar -I
, puede usarla para indicarle que procese cada línea como un elemento, en lugar de cadenas entre comillas separadas en espacios en blanco. Esto hace frente a los espacios, pero no a \"'
las nuevas líneas.
find . -type d | xargs -I {} chmod g+s {}
Puede utilizar el shell para recorrer líneas en lugar de xargs
. Esto funciona para cualquier nombre de archivo que no contenga caracteres de nueva línea.
find . -type d | while IFS= read -r line; do chmod g+s "$line"; done
Ambas soluciones funcionan sólo con nombres de archivos que no contienen caracteres de nueva línea. La salida de find
with nombres de archivos que contienen nuevas líneas es ambigua excepto en un caso que es difícil de analizar: find
no emitirá espontáneamente múltiples barras diagonales, por lo que si ingresa //
la ruta al directorio a recorrer, puede reconocer esto en la salida. A continuación se muestra un código mínimamente probado que utiliza este hecho para convertir la salida find
al formato de entrada de xargs
.
chars=$(printf '\t "'\\\')
{ find .//. -type d; echo .// } | LC_ALL=C sed -n '
s/['"$chars"']/\\&/g
/^\.\/\// {
x
s/\n/\\&/g
p
b
}
H' | LC_ALL=C xargs chmod g+s
1 Más precisamente: terminado por nuevas líneas (hay una nueva línea después del apellido).
Respuesta2
Podrías hacer la recursividad tú mismo con bash. Algo como:
shopt -s nullglob dotglob
recurse_chmod () (
cd "$1"
for d in ./*/
do
if [ -L "$d" ]; then continue; fi
chmod g+s "$d"
recurse_chmod "$d"
done
)
recurse_chmod .
Respuesta3
Puedes decirle a xargs que use \0 como uso delimitadorfind . -type d -print0 | xargs -0 chmod g+s
o
find . -type d | xargs -I{} -d '\n' chmod g+s "{}"
. Utilizará \n como delimitador.