J'utilise startx
pour démarrer X qui évaluera mon .xinitrc
. Dans mon .xinitrc
Je lance mon gestionnaire de fenêtres avec /usr/bin/mywm
. Maintenant, si je tue mon WM (afin de tester un autre WM), X se terminera aussi parce que le .xinitrc
le script a atteint EOF. J'ai donc ajouté ceci à la fin de mon .xinitrc
:
while true; do sleep 10000; done
De cette façon, X ne se terminera pas si je tue mon WM. Maintenant ma question: comment puis-je faire un sommeil infini au lieu de dormir en boucle? Existe-t-il une commande qui va un peu comme geler le script?
Meilleures salutations
sleep infinity
fait exactement ce que cela suggère et fonctionne sans abus de chat.
Cela semble peut-être moche, mais pourquoi ne pas simplement lancer cat
et le laisser attendre pour toujours?
tail
ne bloque pasComme toujours: Pour tout, il existe une réponse courte, facile à comprendre, facile à suivre et complètement fausse. Ici tail -f /dev/null
Entre dans cette catégorie;)
Si vous le regardez avec strace tail -f /dev/null
, Vous remarquerez que cette solution est loin de bloquer! C'est probablement encore pire que la solution sleep
de la question, car elle utilise (sous Linux) des ressources précieuses comme le système inotify
. De même, d'autres processus qui écrivent dans /dev/null
Créent la boucle tail
. (Sur mon Ubuntu64 16.10, cela ajoute plusieurs 10 appels système par seconde sur un système déjà occupé.)
Lire: Je ne sais pas comment archiver cela directement avec le shell.
Tout (même sleep infinity
) Peut être interrompu par un signal. Donc, si vous voulez être vraiment sûr qu'il ne retourne pas exceptionnellement, il doit fonctionner en boucle, comme vous l'avez déjà fait pour votre sleep
. Veuillez noter que (sous Linux) /bin/sleep
Est apparemment limité à 24 jours (regardez strace sleep infinity
), Par conséquent, le mieux que vous puissiez faire est probablement:
while :; do sleep 2073600; done
(Notez que je crois que sleep
effectue une boucle interne pour des valeurs supérieures à 24 jours, mais cela signifie: cela ne bloque pas, cela tourne très lentement. Alors pourquoi ne pas déplacer cette boucle vers l'extérieur?)
fifo
Vous pouvez créer quelque chose qui bloque réellement tant qu'aucun signal n'est envoyé au processus. Après utilise bash 4
, 2 PID et 1 fifo
:
bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'
Vous pouvez vérifier que cela bloque vraiment avec strace
si vous aimez:
strace -ff bash -c '..see above..'
read
se bloque s'il n'y a pas de données d'entrée (voir d'autres réponses). Cependant, le tty
(alias. stdin
) n'est généralement pas une bonne source car il est fermé lorsque l'utilisateur se déconnecte. En outre, il pourrait dérober des informations au tty
. Pas gentil.
Pour bloquer read
, nous devons attendre quelque chose comme un fifo
qui ne retournera jamais rien. Dans bash 4
, Il existe une commande qui peut nous fournir exactement un tel fifo
: coproc
. Si nous attendons aussi le blocage read
(qui est notre coproc
), nous avons terminé. Malheureusement, deux PID et un fifo
doivent rester ouverts.
fifo
Si vous ne vous souciez pas d'utiliser un nom nommé fifo
, procédez comme suit:
mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"
Ne pas utiliser de boucle lors de la lecture est un peu bâclé, mais vous pouvez réutiliser ce fifo
aussi souvent que vous le souhaitez et créer la terminaison read
s en utilisant touch "$HOME/.pause.fifo"
(S'il y en a plus qu’une seule lecture en attente, tous sont terminés en même temps).
pause()
syscallPour le blocage infini, il existe un appel du noyau Linux, appelé pause()
, qui fait ce que nous voulons: attendre pour toujours (jusqu'à ce qu'un signal arrive). Cependant, il n'y a pas encore de programme utilisateur.
Créer un tel programme est facile. Voici un extrait permettant de créer un très petit programme Linux appelé pause
qui s'interrompt indéfiniment (nécessite diet
, gcc
etc.):
printf '#include <unistd.h>\nint main(){for(;;)pause();}' > pause.c;
diet -Os cc pause.c -o pause;
strip -s pause;
ls -al pause
python
Si vous ne voulez pas compiler quelque chose vous-même, mais que vous avez python
installé, vous pouvez l'utiliser sous Linux:
python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'
(Remarque: utilisez exec python -c ...
Pour remplacer le Shell actuel, cela libère un PID. La solution peut être améliorée avec une certaine redirection IO, libérant ainsi les FD inutilisés. toi.)
Comment cela fonctionne (je pense): ctypes.CDLL(None)
charge la bibliothèque standard C et exécute la fonction pause()
au sein d'une boucle supplémentaire. Moins efficace que la version C, mais fonctionne.
Reste au sommeil en boucle. Il est facile à comprendre, très portable et bloque la plupart du temps.
TL; DR: sleep infinity
Dort réellement le temps maximum autorisé, ce qui est fini.
Me demandant pourquoi cela n’est documenté nulle part, j’ai pris la peine de lire le sources de GNU coreutils et j’ai trouvé qu’il exécutait à peu près ce qui suit:
strtod
à partir de C stdlib sur le premier argument pour convertir "infinity" en double précision. Donc, en supposant une double précision IEEE 754, la valeur 64 bits l'infini positif est stockée dans la variable seconds
.xnanosleep(seconds)
( trouvé dans gnulib ), ceci invoque à son tour dtotimespec(seconds)
( également dans gnulib ) pour convertir de double
à struct timespec
.struct timespec
Est juste une paire de nombres: une partie entière (en secondes) et une partie fractionnaire (en nanosecondes). Une conversion naïve l'infini positif en entier entraînerait un comportement indéfini (voir le §6.3.1.4 du standard C). Par conséquent, il est tronqué à TYPE_MAXIMUM (time_t)
.TYPE_MAXIMUM (time_t)
n'est pas définie dans la norme (même si sizeof(time_t)
ne l'est pas); donc, pour l'exemple, prenons x86-64 à partir d'un noyau Linux récent.Ceci est TIME_T_MAX
Dans le noyau Linux, qui est défini ( time.h
) comme:
(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
Notez que time_t
Est __kernel_time_t
Et time_t
Est long
; Le modèle de données LP64 est utilisé, donc sizeof(long)
vaut 8 (64 bits).
Ce qui donne: TIME_T_MAX = 9223372036854775807
.
C'est-à-dire que sleep infinite
Donne un temps de sommeil réel de 9223372036854775807 secondes (10 ^ 11 ans). Et pour les systèmes Linux 32 bits (sizeof(long)
est égal à 4 (32 bits)): 2147483647 secondes (68 ans; voir aussi problème de l'année 2038 ).
Edit : apparemment, la fonction nanoseconds
appelée n'est pas directement l'appel système, mais un wrapper dépendant du système d'exploitation (également défini dans gnulib ).
Il en résulte une étape supplémentaire: pour certains systèmes où HAVE_BUG_BIG_NANOSLEEP
Est true
, le sommeil est tronqué à 24 jours, puis appelé en boucle. C'est le cas pour certaines (ou toutes les) distributions Linux. Notez que ce wrapper peut ne pas être utilisé si le test configure - time aboutit ( source ).
En particulier, ce serait 24 * 24 * 60 * 60 = 2073600 seconds
(Plus 999999999 nanosecondes); mais ceci est appelé dans une boucle afin de respecter le temps total de sommeil spécifié. Par conséquent, les conclusions précédentes restent valables.
En conclusion, le temps de sommeil qui en résulte n’est pas infini, mais suffisamment élevé pour toutes les utilisations pratiques , même si le laps de temps réellement généré n’est pas portable; cela dépend du système d'exploitation et de l'architecture.
Pour répondre à la question initiale, cela suffit évidemment, mais si pour une raison quelconque (un très système contraint par des ressources), vous voulez vraiment éviter un compte à rebours inutile, je suppose que la solution la plus correcte consiste à utiliser la méthode cat
décrite dans d'autres réponses.
sleep infinity
semble plus élégant, mais parfois cela ne fonctionne pas pour une raison quelconque. Dans ce cas, vous pouvez essayer d'autres commandes de blocage telles que cat
, read
, tail -f /dev/null
, grep a
etc.
Qu'en est-il de l'envoi d'un SIGSTOP à lui-même?
Cela devrait suspendre le processus jusqu'à la réception de SIGCONT. Ce qui est dans votre cas: jamais.
kill -STOP "$$";
# grace time for signal delivery
sleep 60;
J'ai eu récemment besoin de le faire. Je suis arrivé avec la fonction suivante qui permettra à bash de dormir pour toujours sans appeler aucun programme externe:
snore()
{
local IFS
[[ -n "${_snore_fd:-}" ]] || { exec {_snore_fd}<> <(:); } 2>/dev/null ||
{
# workaround for MacOS and similar systems
local fifo
fifo=$(mktemp -u)
mkfifo -m 700 "$fifo"
exec {_snore_fd}<>"$fifo"
rm "$fifo"
}
read ${1:+-t "$1"} -u $_snore_fd || :
}
REMARQUE: j’avais précédemment posté une version qui ouvrait et fermait le descripteur de fichier à chaque fois, mais j’ai constaté que, sur certains systèmes, le faire des centaines de fois par seconde finissait par se bloquer. Ainsi, la nouvelle solution conserve le descripteur de fichier entre les appels à la fonction. Bash le nettoiera de toute façon à la sortie.
Cela peut être appelé comme/bin/sleep, et il dormira pendant le temps demandé. Appelé sans paramètres, il sera bloqué pour toujours.
snore 0.1 # sleeps for 0.1 seconds
snore 10 # sleeps for 10 seconds
snore # sleeps forever
Il y a un article avec des détails excessifs sur mon blog ici
Cette approche ne consomme aucune ressource pour maintenir le processus en vie.
while :; do sleep 1; done & kill -STOP $! && wait $!
while :; do sleep 1; done &
Crée un processus factice en arrière-plankill -STOP $!
Arrête le processus d'arrière-planwait $!
Attendez le processus en arrière-plan, il bloquera pour toujours, car le processus en arrière-plan a été arrêté avantAu lieu de tuer le gestionnaire de fenêtres, essayez d’exécuter le nouveau avec --replace
ou -replace
si disponible.