Tengo un programa que produce información útil stdout
pero 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 program
algo 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 redirigirSTDERR
sin también redirigirSTDOUT
. La solución en la que programą envíaSTDOUT
aSTDIN
de programB, a continuación, vuelve a dirigirSTDERR
a un archivo de registro:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
su -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
program
como un coproceso .ksh
:program > output |&
zsh
,bash
:coproc program > output
Eso comienza
program
en 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
program
muera (úsalowait
para esperarlo)program
terminará (obtengaeof
su stdin si el shell sale).fuente
tail -f /dev/null
no 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 inf
o su equivalente más portátilsleep 2147483647
son mejores enfoques para un comando que se encuentra allí sin hacer nada IMO (tenga en cuenta quesleep
está construido en unos pocos shells comoksh93
omksh
).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í
yes
realmente escribe en stdout.cat
saldrá cuando su stdin esté cerrado (o lo que sea que redireccione a él está hecho). Creo quesleep 1000000000d
podría funcionar, perotail
claramente es mejor. Mi cuadro de Debian tiene untailf
comando que acorta un poco.Tomando un rumbo diferente, ¿qué tal si ejecutamos el programa
screen
?fuente
tail -f /dev/null
enfoque 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/null
lo que parece, lostail
usosinotify
y 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 usarloscreen
es un poco exagerado.sleep infinity
es la solución más clara que conozco.Puede usar
infinity
porquesleep
acepta 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 infinity
también funciona en BSD y Mac .sleep infinity
espera 24 días como máximo; quien tiene razonsleep
utilidad 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-1
es 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 deSIGSTOP
esSIGCONT
, es decir, si sabe que el shell tiene PID 12345, puedekill -CONT 12345
hacerlo 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,
read
nunca volverá, porque lo único que puede escribir en esa tubería es en sí mismo, yread
no 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
program
que no escriba en su stdin (ninguna aplicación lo hace),read
no obtendrá nada que leer desde esa dirección de la tubería.En sistemas donde las tuberías no son bidireccionales,
read
es 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
x
con bash; Además, con zsh puedes hacerread
y funciona (¡aunque no entiendo por qué!). ¿Es este truco específico de Linux, o funciona en todos los sistemas * nix?read
solo, se leerá desde stdin. Entonces, si es la terminal, leerá lo que escribe hasta que presione enter.read
y funciona ?read | program > output
y funciona de la misma manera que lo sugerido. (Y no entiendo por qué.)La
read
solució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/null
en un script (con SIGINT, por ejemplo) es necesario poner en segundo plano eltail
comando ywait
.fuente
Redireccionar
/dev/zero
como entrada estándar!fuente