Navigatie overslaan.
Start

Subshells

Computers worden steeds sneller.
Gelukkig maar, want blijkbaar worden gebruikers en programmeurs steeds dommer en dommer.
Om de een of andere reden proberen ze altijd alles op de meest onefficiënte manier te doen.

Bijvoorbeeld het doorlopen van een lijst en dan bepaalde acties ondernemen aan de hand van de inhoud van die lijst.
Heel vaak wordt die lijst meerdere keren doorlopen: 1 keer voor iedere actie. Terwijl het perfect mogelijk is om de lijst slechts 1 keer te doorlopen.
Je gaat dan een enorme tijdswinst krijgen, vooral als de lijst erg groot is, of als je veel acties hebt.

Bijvoorbeeld: Maak een bestandslijst van de huidige directory, en tel hoeveel ".html"-bestanden er zijn, hoeveel ".jpg"-bestanden, en hoeveel ".pdf" -bestanden.

Laten we dit stap voor stap oplossen...

"Maak een bestandslijst van de huidige directory", kan eenvoudig met:

find . -type f

Dit vertrekt vanuit de huidige directory (.), en "vindt" alle bestanden van het type "f" (files), dus geen directories, etc...
Aangezien het "find" commando 1 regel tekst geeft per bestand, is het aantal bestanden tellen, exact hetzelfde als het aantal regels tekst tellen, dus je kan het "wc"-commando gebruiken (Word Count).

find . -type f |wc -l

Dit commando telt het totaal aantal bestanden.

Hoe tellen we nu bestaande bestandstypes?
Er zijn 2 manieren.

Allereerst, kan je met het "find" commando zelf al aangeven wat je wil vinden.

find . -type f -name "*.pdf" |wc -l

De tweede manier is met grep:

find . -type f |grep "\.pdf$" |wc -l

De resultaten moeten natuurlijk hetzelfde zijn...

Maar hoe zoeken we nu hoeveel exemplaren we hebben van verschillende types?

3 keer zoeken met een andere "grep" parameter?
Ik dacht het niet...


Subshells

De Linux shells zijn krachtig, enorm krachtig.
De windows shell kan alleen maar dromen om ooit ook zo krachtig te zijn...

Door subshells te gebruiken kunnen we een dergelijk probleem oplossen.

| find . -type f |tee >(grep "\.pdf$" |wc -l) \
|                     >(grep "\.html$" |wc -l) \
|                     >(grep "\.jpg$" |wc -l)

"tee" is een op z'n Engels uitgesproken T, een T-stuk, zoals bijvoorbeeld bij een waterleiding.
De output van het find-commando wordt daardoor opgesplitst, 1 deel gaat naar het
scherm, het andere vervolgt de "pipe", richting "wc".
Dus eigenlijk riolering, en niet waterleiding. ;-)

Ik zoek met "find", en ik stuur de output naar 3 verschillende subshells.
Elke subshell doet zijn eigen ding met de output.
Ik ga dus de bestandslijst met find slechts 1 keer doorlopen en parallel zoeken.

Als je dan toch een (veel te) snelle processor koopt met meedere cores, laat die cores dan ook werken door dingen te parrallelliseren, want het heeft geen zin om dingen te hebben die je niet gebruikt...

Is er ook een manier om de

Is er ook een manier om de volgorde waarop de output van de subshells verschijnt te ordenen? Nu is dat random waardoor je moet gokken welk getal op welk type slaat. Het zou ook handig zijn om nog andere dingen in de subshell te doen zodat dit mogelijk is:

PDF : 1345 documenten
HTML : 4512 documenten
JPG : 436 documenten
Het probleem is dat iets zoals count = `grep "fegdfs"|wc -l"` niet kan waardoor de variabele niet later gebruikt kan worden. Is hier een oplossing voor?

Had ik al gezegd dat de

Had ik al gezegd dat de Linux shell krachtig was? ;-)

Neen, er is geen manier om de volgorde te ordenen, tenzij je nog met "sort" wil gaan werken.
De volgorde is ook niet echt "random", maar de subshell die het eerst "klaar" is, zal het eerst output geven.

Dat gezegd zijnde: Je kan wel "betere" output geven met "xargs".

| find . -type f |tee >(grep "\.pdf$" |wc -l |xargs echo "PDF :")
|                     >(grep "\.html$" |wc -l |xargs echo "HTML :")
|                     >(grep "\.jpg$" |wc -l |xargs echo "JPG :") 

Output:

PDF : 22
JPG : 7077
HTML : 226

Als je echt "goede user output" wil, dan moet je natuurlijk niet met one-liners gaan werken...