Timeout terminate hele pipe?

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • aawe mwan
  • Registratie: December 2002
  • Laatst online: 06:46

aawe mwan

Wat ook leuk is:

Topicstarter
Ik ben aan het experimenteren met pipes in bash.

Ik laat het "shuf" commando random getallen genereren tussen 100000 en 999999 en dankzij de --repeat optie kan hij daar oneindig lang mee doorgaan. Door middel van het "timeout" commando stop ik hem 2 seconden later. De resulterende lijst van random getallen wil ik daarna in een pipe sorteren.

Dat ziet er dan zo uit:

Bash:
1
2
3
$ ( timeout --verbose 2 shuf -i 100000-999999 --repeat ) | sort | head
timeout: sending signal TERM to command ‘shuf’
Terminated

Je ziet dat dit niet helemaal goed werkt: timeout stopt shuf wel na 2 seconden, maar dan verschijnt het woord "Terminated" en ik krijg verder niets te zien van de gegenereerde lijst getallen. De pipe is afgebroken.

Er zijn verschillende settings die te maken hebben met foutmeldingen en pipes in bash (bijvoorbeeld: set -o pipefail), maar die maken geen verschil. Je kunt timeout het signaal "HUP" laten sturen, maar dit geeft hetzelfde resultaat (maar dan met de melding Hangup in plaats van Timeout).

Gek genoeg werkt het zo wel:
Bash:
1
2
3
4
5
6
7
8
9
10
11
12
$ ( timeout --verbose 2 shuf -i 100000-999999 --repeat ; false ) | sort | head
timeout: sending signal TERM to command ‘shuf’
100000
100000
100001
100002
100002
100003
100003
100003
100003
100004

Maar hoe kan het precies dat deze kleine aanpassing het afbreken van de pipe voorkomt?

Ik gebruik Linux Mint 21.1 en bash versie: 5.1.16(1)-release (x86_64-pc-linux-gnu)

[ Voor 28% gewijzigd door aawe mwan op 03-06-2023 13:37 ]

„Ik kan ook ICT, want heel moeilijk is dit niet”

Alle reacties


Acties:
  • 0 Henk 'm!

  • DaFeliX
  • Registratie: December 2002
  • Laatst online: 12:36

DaFeliX

Tnet Devver
Ben je geen "echo" vergeten voor het commando?

Bash:
1
echo $ ( timeout --verbose 2 shuf -i 100000-999999 --repeat ) | sort | head


Dit werkt zo lokaal bij mij wel :)

Einstein: Mijn vrouw begrijpt me niet


Acties:
  • +1 Henk 'm!

  • vanaalten
  • Registratie: September 2002
  • Nu online
@DaFeliX TS is volgens mij vooral aan het zoeken naar het 'waarom' van dit alles: waarom werkt dit niet:
aawe mwan schreef op donderdag 1 juni 2023 @ 21:00:
Bash:
1
$ ( timeout --verbose 2 shuf -i 100000-999999 --repeat ) | sort | head
(ik neem aan dat de dollar aan het begin staat voor de shell prompt, niet onderdeel van het commando)

...en waarom dit dan wel werkt:
Bash:
1
$ ( timeout --verbose 2 shuf -i 100000-999999 --repeat ; false ) | sort | head
Ik ben verre van een expert op dit gebied, maar hier ook even wat geprobeerd:
code:
1
( timeout --foreground --verbose 1 shuf -i 100000-999999 --repeat ) | sort | head

...werkt hier. Die "--foreground" in de man-page:
code:
1
2
3
       --foreground
              when not running timeout directly from a shell prompt,
              allow COMMAND to read from the TTY and get TTY signals; in this mode, children of COMMAND will not be timed out
Aangezien die (...) constructie volgens mij een subshell oplevert denk ik dat je het qua oorzaak daar moet zoeken. Maar waarom... dat weet ik verder ook niet.

Acties:
  • 0 Henk 'm!

  • aawe mwan
  • Registratie: December 2002
  • Laatst online: 06:46

aawe mwan

Wat ook leuk is:

Topicstarter
De originele $ was inderdaad de prompt.

Als ik er echo $( ... ) van maak, dan werkt het inderdaad ook, maar hij leest de complete verzameling random getallen in het geheugen. Grappig dat dit werkt, maar zo veel geheugen gebruiken was niet de bedoeling en het blijkt ook heel traag te zijn.

De --foreground optie meegeven aan timeout doet het bij mij inderdaad ook, dank voor de tip.

„Ik kan ook ICT, want heel moeilijk is dit niet”


Acties:
  • +2 Henk 'm!

  • aawe mwan
  • Registratie: December 2002
  • Laatst online: 06:46

aawe mwan

Wat ook leuk is:

Topicstarter
Het blijkt dat bash alleen een subshell aanmaakt als je echt een extra commando achter de timeout zet. Voor alleen de timeout, of timeout met haakjes en zelfs een puntkomma, doet hij dat niet:

Bash:
1
( timeout --verbose 100 shuf -i 100000-999999 --repeat ; ) | sort | head

Processtree in htop:
bash
├─ timeout --verbose 100 shuf -i 100000-999999 --repeat
│  └─ shuf -i 100000-999999 --repeat
├─ sort
└─ head


Bash:
1
  ( timeout --verbose 100 shuf -i 100000-999999 --repeat ; false ) | sort | head

Processtree in htop:
bash
├─ bash
│  └─ timeout --verbose 100 shuf -i 100000-999999 --repeat
│     └─ shuf -i 100000-999999 --repeat
├─ sort
└─ head


Dus het is eenvoudiger dan ik dacht: als timeout in een subshell zit, dan gaat het goed, anders niet.
Het zou een bug kunnen zijn dat timeout zonder de --foreground optie in een pipe niet aan de "children of COMMAND" een timeout geeft (zoals op de man page staat), maar de siblings van zichzelf. Met die woorden ben ik nog eens op internet gaan zoeken en nu kon ik vinden dat dit toch wel een bekend probleem is.

Zodoende vond ik nog andere manieren om de subshell-in-een-pipe work-around te typen:
Bash:
1
2
3
(timeout ... || false ) | ...
(timeout ... || true ) | ...
(timeout ... || : ) | ...

„Ik kan ook ICT, want heel moeilijk is dit niet”