Eén inputbestand voor twee commando's: cat geeft verschil

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

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

aawe mwan

Wat ook leuk is:

Topicstarter
Mijn vraag
In Bash is het mogelijk om één inputbestand te gebruiken als input voor 2 commando's tegelijk. Als ik dat gebruik met of zonder cat, geeft dit gek genoeg een verschillend resultaat! Hoe is dit te verklaren?

# Aanmaken testbestand:
seq 100 >honderd


# Versie met input redirection
(head ; tail) <honderd
# Resultaat:
1
2
3
4
5
6
7
8
9
10
91
92
93
94
95
96
97
98
99
100


# Versie met cat
cat honderd | (head ; tail)
# Resultaat:
1
2
3
4
5
6
7
8
9
10


Waarom geven deze twee commando's niet exact dezelfde output?

Relevante software en hardware die ik gebruik
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)

Wat ik al gevonden of geprobeerd heb
set pipefail maar dat maakt geen verschil.

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

Alle reacties


Acties:
  • +2 Henk 'm!

  • hcQd
  • Registratie: September 2009
  • Laatst online: 08:28
Buffering. Head zet de positie van de input terug met lseek, dat werkt niet bij een pipe.

Acties:
  • +1 Henk 'm!

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

aawe mwan

Wat ook leuk is:

Topicstarter
hcQd schreef op donderdag 25 juli 2024 @ 21:52:
Buffering. Head zet de positie van de input terug met lseek, dat werkt niet bij een pipe.
Ik heb even moeten puzzelen om je antwoord te begrijpen, maar je legt inderdaad de vinger op de zere plek.

Wat er precies gebeurt is beter te zien als je niet 100 regels als input gebruikt, maar meer, bijvoorbeeld 10.000. Dan zie je dat het commando dat volgt op head ineens wel output gaat geven.

Wat head blijkbaar doet, is de input inlezen in een buffer; de standaard buffer van head is 8 kB en dat is de volledige data van het voorbeeld. Na het outputten van de gewenste hoeveelheid data gebruikt hij lseek() om te zorgen dat het volgende commando op precies de juiste plek kan doorgaan met lezen. Dat lukt niet in een pipe, de te veel gebufferde data gaat alsnog verloren maar daar geeft head geen foutmelding over.

Het is me niet gelukt om de buffer kleiner te maken met buffer, unbuffer of stdbuf.

Wat grappig genoeg wel werkt, is de input vertragen met pv (in dit voorbeeld naar 300 bytes per seconde):
seq 30 | pv --quiet --rate-limit 300 | (head ; tail)
# Resultaat
1
2
3
4
5
6
7
8
9
10
21
22
23
24
25
26
27
28
29
30

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