Tengo un programa que produce información útil stdoutpero también lee stdin. Quiero redirigir su salida estándar a un archivo sin proporcionar nada en la entrada estándar. Hasta ahora, todo bien: puedo hacer:
program > output
y no hagas nada en el tty.
Sin embargo, el problema es que quiero hacer esto en segundo plano. Si lo hago:
program > output &
el programa se suspenderá ("suspendido (entrada tty)").
Si lo hago:
program < /dev/null > output &
el programa termina inmediatamente porque llega a EOF.
Parece que lo que necesito es conectarme a programalgo que no hace nada por un tiempo indefinido y que no lee stdin. Los siguientes enfoques funcionan:
while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &
Sin embargo, todo esto es muy feo. No tiene que ser una manera elegante, con las utilidades estándar de Unix, "no hacer nada, por tiempo indefinido" (parafraseando man true). ¿Cómo podría lograr esto? (Mi criterio principal para la elegancia aquí: sin archivos temporales; sin esperas ocupadas o despertares periódicos; sin utilidades exóticas; lo más corto posible).

su -c 'program | output &' user. Estoy a punto de hacer una pregunta similar con la creación de trabajos en segundo plano como un método aceptable para manejar un "servicio / demonio". También noté que no podía redirigirSTDERRsin también redirigirSTDOUT. La solución en la que programą envíaSTDOUTaSTDINde programB, a continuación, vuelve a dirigirSTDERRa un archivo de registro:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/nullsu -c 'while true; do true; done | cat > ~/output &' user?1<&-él, ¿saldrá de su programa?Respuestas:
En los shells que los admiten (ksh, zsh, bash4), puede comenzar
programcomo un coproceso .ksh:program > output |&zsh,bash:coproc program > outputEso comienza
programen segundo plano con su entrada redirigida desde apipe. El otro extremo de la tubería está abierto a la carcasa.Tres beneficios de ese enfoque
programmuera (úsalowaitpara esperarlo)programterminará (obtengaeofsu stdin si el shell sale).fuente
tail -f /dev/nullno es ideal ya que se lee cada segundo/dev/null(las versiones actuales de GNU tail en Linux usando inotify en realidad son un error ).sleep info su equivalente más portátilsleep 2147483647son mejores enfoques para un comando que se encuentra allí sin hacer nada IMO (tenga en cuenta quesleepestá construido en unos pocos shells comoksh93omksh).No creo que te vayas a poner más elegante que el
que ya sugirió (suponiendo que este uso inotifique internamente, no debería haber encuestas ni reactivaciones, por lo que aparte de tener un aspecto extraño, debería ser suficiente).
Necesita una utilidad que se ejecutará indefinidamente, mantendrá su stdout abierto, pero en realidad no escribirá nada en stdout, y no saldrá cuando se cierre su stdin. Algo así
yesrealmente escribe en stdout.catsaldrá cuando su stdin esté cerrado (o lo que sea que redireccione a él está hecho). Creo quesleep 1000000000dpodría funcionar, perotailclaramente es mejor. Mi cuadro de Debian tiene untailfcomando que acorta un poco.Tomando un rumbo diferente, ¿qué tal si ejecutamos el programa
screen?fuente
tail -f /dev/nullenfoque y también lo encuentro lo suficientemente elegante, ya que el uso del comando coincide bastante con el propósito previsto.strace tail -f /dev/nulllo que parece, lostailusosinotifyy los despertares ocurren en casos tontossudo touch /dev/null. Es triste que parezca que no hay una mejor solución ... Me pregunto cuál sería la llamada al sistema correcta para implementar una mejor solución.pause, pero no está expuesta directamente a una interfaz de shell.screen, pero esto es para ejecutar múltiples apariciones del programa desde un script de shell con fines de prueba, por lo que usarloscreenes un poco exagerado.sleep infinityes la solución más clara que conozco.Puede usar
infinityporquesleepacepta un número de coma flotante * , que puede ser decimal , hexadecimal , infinito o NaN , de acuerdo conman strtod.* Esto no es parte del estándar POSIX, por lo que no es tan portátil como
tail -f /dev/null. Sin embargo, es compatible con GNU coreutils (Linux) y BSD (utilizado en Mac) (aparentemente no es compatible con las versiones más nuevas de Mac - ver comentarios).fuente
sleep infinitytambién funciona en BSD y Mac .sleep infinityespera 24 días como máximo; quien tiene razonsleeputilidad no está limitada a 24 días ; es solo el primer syscall que duerme durante 24 días, y luego hará más syscalls. Vea mi comentario aquí: stackoverflow.com/questions/2935183/…Sí,
2^31-1es un número finito, y no se ejecutará para siempre , pero te daré $ 1000 cuando el sueño finalmente se agote. (Sugerencia: uno de nosotros estará muerto para entonces).fuente
sleep 2147483647d...Puede crear un binario que haga exactamente eso con:
fuente
Aquí hay otra sugerencia usando las utilidades estándar de Unix, para "no hacer nada, indefinidamente" .
Esto activa un shell que se envía inmediatamente
SIGSTOP, lo que suspende el proceso. Esto se utiliza como "entrada" a su programa. El complemento deSIGSTOPesSIGCONT, es decir, si sabe que el shell tiene PID 12345, puedekill -CONT 12345hacerlo continuar.fuente
En Linux, puedes hacer:
En Linux, abrir / dev / fd / x donde x es un descriptor de archivo al final de la escritura de una tubería, le da el final de la lectura de la tubería, así que aquí es lo mismo que en el stdin del programa. Entonces, básicamente,
readnunca volverá, porque lo único que puede escribir en esa tubería es en sí mismo, yreadno genera nada.También funcionará en FreeBSD o Solaris, pero por otra razón. Allí, abrir / dev / fd / 1 le da el mismo recurso que abrir en fd 1 como lo esperaría y como la mayoría de los sistemas, excepto Linux, lo hacen al final de la escritura. Sin embargo, en FreeBSD y Solaris, las tuberías son bidireccionales. Por lo tanto, siempre
programque no escriba en su stdin (ninguna aplicación lo hace),readno obtendrá nada que leer desde esa dirección de la tubería.En sistemas donde las tuberías no son bidireccionales,
reades probable que falle con un error al intentar leer desde un descriptor de archivo de solo escritura. También tenga en cuenta que no todos los sistemas tienen/dev/fd/x.fuente
xcon bash; Además, con zsh puedes hacerready funciona (¡aunque no entiendo por qué!). ¿Es este truco específico de Linux, o funciona en todos los sistemas * nix?readsolo, se leerá desde stdin. Entonces, si es la terminal, leerá lo que escribe hasta que presione enter.ready funciona ?read | program > outputy funciona de la misma manera que lo sugerido. (Y no entiendo por qué.)La
readsolución de Stéphane Chazelas también funciona en Mac OS X si se abre un fd de lectura/dev/fd/1.Para poder matar
tail -f /dev/nullen un script (con SIGINT, por ejemplo) es necesario poner en segundo plano eltailcomando ywait.fuente
Redireccionar
/dev/zerocomo entrada estándar!fuente