title | subtitle | author | date |
---|---|---|---|
5. Advanced Text Processing |
Linux (for data Scientists)<br/>HOGENT toegepaste informatica |
Thomas Parmentier, Andy Van Maele, Bert Van Vreckem |
2024-2025 |
2 gangbare manieren om tekstpatronen te definiëren:
- Globbing (wildcards):
man 7 glob
- Reguliere expressies (regex):
man 7 regex
Commando uitvoeren op meer dan 1 bestand?
- Geef elk bestand apart op (spatie ertussen)
cp a.txt b.doc c.jpg /tmp
- Gebruik globbing-patronen
cp /media/usbstick/*.jpg ~/Pictures/
Patroon | Betekenis | Voorbeeld |
---|---|---|
? |
Eén willekeurig teken | ls /bin/?? |
* |
Willekeurige string (ook leeg) | ls *.txt , ls a* |
[...] |
Elk teken opgesomd tussen [] |
ls /bin/[A+_]* |
[A-Z] |
Van A t/m Z | ls /bin/*[A-D1-3] |
[!...] |
Niet 1 v/d opgesomde tekens | ls /bin/[!a-z]* |
ls *.md
: toon alle Markdown-bestandenls [A-Z]*.md
: toon alle Markdown-bestanden waarvan de naam begint met een hoofdletterls [0-9][0-9]-*.md
: toon alle Markdown bestanden waarvan de naam begint met twee cijfers gevolgd door een streepje- bv. 00-index.md, 01-intro.md, ...
ls /usr/bin/[!a-z]*
: toon alle commando's die niet met een kleine letter beginnen- bv.
/usr/bin/[
,/usr/bin/7z
, enz.
- bv.
ls -d /usr/share/man/man?
: toon alle directories onder/usr/share/man
, gevolgd door nog een enkel karakter- bv.
man1
,man7
,mann
- bv.
apt list --installed 'lib*'
: toon alle geïnstalleerde packages met programmabibliotheken
Gebruik nooit regex om bestanden te selecteren!
# Fout:
ls /bin | grep 'a.*'
# Beter:
ls /bin/a*
In dit soort gevallen is find
overbodig:
find . -maxdepth 1 -type f -name 'a*' -exec cp {} /tmp \;
# Beter:
cp a* /tmp
- AWK = Aho, Weinberger & Kernighan
- Dateert van 1977!
- POSIX standaard => altijd aanwezig op UNIX-achtig OS
- Soms handiger dan Python voor specifieke taken
$ ip -br a | awk '{ print $3 }'
127.0.0.1/8
10.0.2.15/24
awk -F: '{print $1,$3}' /etc/passwd
{action}
→ Voer uit voor elke lijn/regex/ { action }
→ Voer enkel uit als regex overeenkomtcondition { action }
→ Voer enkel uit als voorwaarde voldaan is- Geen actie:
{ print }
wordt verondersteld
vb. awk -F: '$3 >= 1000' /etc/passwd
BEGIN { ... }
→ Voer 1x uit, vóór verwerken inputEND { ... }
→ Voer 1x uit, na verwerken input
Bereken de som van (alle getallen in) kolom 3
{s += $3}
END { print s }
- Initialisatie variabele
s=0
geïmpliceerd! $3
wordt automatisch geïnterpreteerd als getal!
FNR
Huidige lijnnummerFS
Field Separator (equivalent van optie-F
)NF
Number Fields (aantal kolommen)NR
Number of Records (aantal lijnen)OFS
Output Field separator
Print de laatste kolom:
awk -F: '{print $NF}' /etc/passwd
Bereken het gemiddelde van kolom 3 in een CSV-bestand:
BEGIN { FS="," } # This is a CSV file
{s += $3} # Calculate sum of column 3
END { print s/NR } # Print mean
Voorbeeld: users.awk
#! /usr/bin/awk -f
BEGIN {FS=":"}
{ print $1, $3}
Uitvoeren met:
$ chmod +x users.awk
$ ./users.awk < /etc/passwd
root 0
bin 1
...
osboxes 1000
Bereken de som van kolommen 2, 3 en 4:
#! /usr/bin/awk -f
{
sums[2] += $2
sums[3] += $3
sums[4] += $4
}
END {
for(s in sums)
print s, sums[s]
}
Print de user shells in /etc/passwsd
en tel hoeveel elk voorkomt
#! /usr/bin/awk -f
# countshells.awk
BEGIN { FS=":" }
{ shells[$NF]++ }
END {
for (s in shells)
printf "%4s\t%s\n", shells[s], s
}
- Free Software Foundation (2022) The GNU Awk User’s Guide
- Herbst, M. (2016) Introduction to AWK programming
jq is a lightweight and flexible command-line JSON processor.
- filter-commando: input > verwerking > output
- zoals awk/sed, maar dan voor JSON
- niet altijd even makkelijk in gebruik...
- RTFM: https://stedolan.github.io/jq/manual/
curl -s 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq
of: jq '.'
(met .
de identity operator)
curl -s 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.[0]'
(in de volgende voorbeelden: enkel het jq
-commando)
jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
- Let op!
|
binnen dejq
-expressie! .key
haalt hetkey
-veld op- kan ook genest, bv.
.commit.message
- kan ook genest, bv.
jq '.[] | {message: .commit.message, name: .commit.committer.name}'
.[]
geeft elk element van de array terug- Resultaat is geen JSON!
- Als JSON-array:
[]
er rond:
jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'
- Veld "parents" (parent commits) kan een array met 1 of meerdere waarden zijn
- (bv. merge commit heeft 2 parents)
jq '[.[] | {message: .commit.message, name: .commit.committer.name, parents: [.parents[].html_url]}]'