Entiendo cómo funciona una bomba tenedor normal, pero realmente no entiendo por qué se requiere el & al final de la bomba tenedor bash común y por qué estos scripts se comportan de manera diferente:
:(){ (:) | (:) }; :
y
:(){ : | :& }; :
El primero causa un aumento en el uso de la CPU antes de devolverme a la pantalla de inicio de sesión. En cambio, este último solo hace que mi sistema se congele, lo que me obliga a reiniciar por completo. ¿Porqué es eso? Ambos crean continuamente nuevos procesos, entonces, ¿por qué el sistema se comporta de manera diferente?
Ambos scripts también se comportan de manera diferente a
:(){ : | : }; :
lo que no causa ningún problema, aunque hubiera esperado que fueran iguales. La página del manual de bash indica que los comandos en una tubería ya se ejecutan en una subshell, por lo que me hacen creer que: | : ya debería ser suficiente. Creo y debería ejecutar la tubería en una nueva subshell, pero ¿por qué eso cambia tanto?
Editar: Utilizando htop y limitando la cantidad de procesos, pude ver que la primera variante crea un árbol real de procesos, la segunda variante crea todos los procesos en el mismo nivel y la última variante no parece crear ningún proceso en absoluto. Esto me confunde aún más, pero ¿tal vez me ayuda de alguna manera?
fuente
:(){ : | :; }; :
Respuestas:
ADVERTENCIA NO INTENTE EJECUTAR ESTO EN UNA MÁQUINA DE PRODUCCIÓN. SOLO NO. Advertencia: Para probar cualquier "bomba" asegúrese de que
ulimit -u
esté en uso. Lea a continuación [a] .Definamos una función para obtener el PID y la fecha (hora):
Una función simple y sin problemas
bomb
para el nuevo usuario (protéjase: lea [a] ):Cuando se llama a esa función para que se ejecute funciona así:
Se
date
ejecuta el comando , luego se imprime un "sí", un sueño durante 1 segundo, luego el comando de cierredate
y, finalmente, la función sale imprimiendo un nuevo símbolo del sistema. Nada sofisticado.El | tubo
Cuando llamamos a la función así:
Dos comandos se inician en algún momento, los dos finalizan 1 segundo más tarde y luego vuelve el indicador.
Esa es la razón de la tubería
|
, para iniciar dos procesos en paralelo.& antecedentes
Si cambiamos la llamada agregando un final
&
:La solicitud vuelve inmediatamente (toda la acción se envía al fondo) y los dos comandos se ejecutan como antes. Tenga en cuenta el valor del "número de trabajo"
[1]
impreso antes del PID del proceso3380
. Más tarde, se imprimirá el mismo número para indicar que la tubería ha terminado:Ese es el efecto de
&
.Esa es la razón de
&
: comenzar los procesos más rápido.Nombre más simple
Podemos crear una función llamada simplemente
b
para ejecutar los dos comandos. Escrito en tres líneas:Y ejecutado como:
Tenga en cuenta que no utilizamos
;
en la definición deb
(las nuevas líneas se utilizaron para separar elementos). Sin embargo, para una definición en una línea, es habitual usar;
, como este:La mayoría de los espacios tampoco son obligatorios, podemos escribir el equivalente (pero menos claro):
También podemos usar a
&
para separar el}
(y enviar los dos procesos a un segundo plano).La bomba.
Si hacemos que la función muerda su cola (llamándose a sí misma), obtenemos la "bomba tenedor":
Y para que llame a más funciones más rápido, envíe la canalización a un segundo plano.
Si agregamos la primera llamada a la función después de un requerimiento
;
y cambiamos el nombre:
, obtenemos:Usualmente escrito como
:(){ :|:& }; :
O, escrito de forma divertida, con algún otro nombre (un hombre de nieve):
El ulimit (que debería haber configurado antes de ejecutar esto) hará que la solicitud vuelva rápidamente después de muchos errores (presione enter cuando la lista de errores se detenga para obtener la solicitud).
La razón de que esto se llame una "bomba tenedor" es que la forma en que el shell inicia un sub-shell es bifurcando el shell en ejecución y luego llamando a exec () al proceso bifurcado con el comando para ejecutar.
Una tubería "bifurcará" dos nuevos procesos. Hacerlo hasta el infinito causa una bomba.
O un conejo como se llamaba originalmente porque se reproduce muy rápido.
Sincronización:
:(){ (:) | (:) }; time :
Terminado
real 0m45.627s
:(){ : | :; }; time :
Terminado
0m15.283s reales
:(){ : | :& }; time :
0m00.002 verdadera s
Still Running
Sus ejemplos:
:(){ (:) | (:) }; :
Donde el segundo cierre
)
separa}
es una versión más compleja de:(){ :|:;};:
. Cada comando en una tubería se llama dentro de un sub-shell de todos modos. ¿Cuál es el efecto de la()
.:(){ : | :& }; :
Es la versión más rápida, escrita para no tener espacios:
:(){(:)|:&};:
(13 caracteres).:(){ : | : }; :
### funciona en zsh pero no en bash.Tiene un error de sintaxis (en bash), se necesita un metacarácter antes del cierre
}
,ya que esto:
[a] Cree un nuevo usuario limpio (lo llamaré mío
bize
). Inicie sesión con este nuevo usuario en una consolasudo -i -u bize
, o bien:Verifique y luego cambie el
max user processes
límite:Usando sólo 10 obras, es sólo un nuevo usuario solitaria:
bize
. Hace más fácil llamarkillall -u bize
y eliminar el sistema de la mayoría (no todas) de las bombas. Por favor, no pregunte cuáles siguen funcionando, no lo diré. Pero aún así: es bastante bajo, pero en el lado seguro, adáptese a su sistema .Esto asegurará que una "bomba tenedor" no colapsará su sistema .
Otras lecturas:
fuente