Hier erzeugen wir ein paar Text-Dateien, die wir später brauchten:
echo "France
Canada
Burkina Faso
Democratic Republic of the Congo
Russia
New Zealand" > countries.txt
echo "Germany
Austria
Poland" > countries_1.txt
echo -e "1618391758\t192.168.0.140\tindex.html
1618391759\t192.168.0.120\tmy_test.html
1618391762\t192.168.0.140\tlogin.html
1618391765\t192.168.0.140\tbla.html
1618391771\t192.168.0.10\tblub.html" > logfile-example.log
echo -e "192.168.0.10\tsokrates
192.168.0.120\taristoteles
192.168.0.140\tplaton" > rechnernamen.txt
Nach der Unix-Philosophie sind Textströme eine universelle Schnittstelle. Daher gibt es viele Unix-Werkzeuge, die Textströme verarbeiten und manipulieren können. Im folgenden werden die wichtigsten Werkzeuge vorgestellt.
Man benötigt dies in der Praxis beispielsweise für die automatische Änderung von Konfigurationsdateien oder zur Logfile-Analyse.
Hinweis: Viele Log-Dateien finden Sie im Verzeichnis /var/log. Diese sind teilweise komprimiert und können z.B. mit zcat zum Standardoutput (stdout) entpackt werden.
cat¶Mit cat kann man (Text-)Dateien (auch) konkatenieren, d.h. unter Beibehaltung der Reihenfolge zusammenfügen.
Dabei muss man lediglich mehrere Dateien als Argumente angeben.
In dem folgenden Beispiel zusätzlich mit Process Substitution, um die Grenzen der ursprünglichen Dateien anzuzeigen.
cat countries.txt <(echo ---------) countries_1.txt
# dies könnte natürlich auch wieder als neue Datei geschrieben werden.
# cat countries.txt countries_1.txt > merged_countries.txt
France Canada Burkina Faso Democratic Republic of the Congo Russia New Zealand --------- Germany Austria Poland
cut¶Mit cut kann man "Spalten" (Felder) aus einer Textdatei extrahieren.
# Anzeigen der Beispieldatei (siehe oben)
cat logfile-example.log
# zeitstempel IP Webseite
1618391758 192.168.0.140 index.html 1618391759 192.168.0.120 my_test.html 1618391762 192.168.0.140 login.html 1618391765 192.168.0.140 bla.html 1618391771 192.168.0.10 blub.html
# Hinweis:
# die Zeitstempelangaben können mit `date` für Menschen übersetzt werden:
date -d @1618391759
Do 16. Jun 10:40:56 CEST 2022
# extrahiere das 1. und 3. Feld (Spalte) mit cut
# Das Standard Feld-Trennzeichen ist TAB, mit
# -d kann man andere Trennzeichen verwenden.
# -f gibt die Felder an, die man extrahieren will.
cut logfile-example.log -d $'\t' -f1,3
1618391758 index.html 1618391759 my_test.html 1618391762 login.html 1618391765 bla.html 1618391771 blub.html
Hier ist das Trennzeichen (delimiter) über den Schalter -d mittels ANSI C Quoting explizit auf TAB (Tabulator \t) gesetzt.
sort¶Mit Hilfe von sort lassen sich Dateien sortieren, z.B. mit den Schaltern (siehe Manpage)
-t, --field-separator=SEP
use SEP instead of non-blank to blank transition
-k, --key=KEYDEF
sort via a key; KEYDEF gives location and type
Sehen Sie sich z.B. die Manpage für die weiteren Schalter an.
Beispiel:
# Sortieren nach dem zweiten Feld (der zweiten Spalte):
sort -t $'\t' -k2 logfile-example.log
1618391771 192.168.0.10 blub.html 1618391759 192.168.0.120 my_test.html 1618391765 192.168.0.140 bla.html 1618391758 192.168.0.140 index.html 1618391762 192.168.0.140 login.html
join¶Mit join lassen sich Dateien, die ein gemeinsames (sortiertes) Datenfeld haben, verbinden.
Beispiel: Mit einer Datei mit IP-Rechnername Zuweisung können wir das sortierte log-File (in Process Substitution) mit den Rechnernamen verbinden:
join -1 2 -2 1 -t $'\t' <(sort -t $'\t' -k2 logfile-example.log) rechnernamen.txt
192.168.0.10 1618391771 blub.html sokrates 192.168.0.120 1618391759 my_test.html aristoteles 192.168.0.140 1618391765 bla.html platon 192.168.0.140 1618391758 index.html platon 192.168.0.140 1618391762 login.html platon
# falls unsortiert
join -1 2 -2 1 -t $'\t' logfile-example.log rechnernamen.txt
join: logfile-example.log:2: is not sorted: 1618391759 192.168.0.120 my_test.html 192.168.0.140 1618391758 index.html platon
Der Schalter -1 2 gibt an, dass von der ersten Datei (hier sortiertes Logfile) das zweite Feld zum Zusammenfügen verwendet werden soll. Analog bedeutet -2 1 von der zweiten Datei (rechnernamen.txt) das erste Feld.
Beachten Sie, dass mittels Process Substitution <(sort -t $'\t' -k2 logfile-example.log), die Datei logfile-example.log sortiert wird.
tr¶tr übersetzt (translate) Zeichen oder löscht diese.
Beispiel alle Leerzeichen "" zu Tabs und alles Großgeschriebene zu Kleingeschrieben.
tr ' [:upper:]' '\t[:lower:]' < countries.txt
france canada burkina faso democratic republic of the congo russia new zealand
Hinweis:
cut funktioniert nicht bei Trennzeichen, die hintereinander vorkommen, aber keine neuen Felder bestimmen,
z.B.:
# Hier gibt es (unterschiedlich) mehrere Spaces zwischen den Feldern:
echo -e "1618391758 192.168.0.140 index.html
1618391759 192.168.0.120 my_test.html
1618391762 192.168.0.140 login.html
" > logfile-example_.log
# dadurch werden die falschen Felder ausgewählt (eventuell leere):
cut logfile-example_.log -d' ' -f1,3
1618391758 index.html 1618391759 1618391762 192.168.0.140
tr kann hier Abhilfe schaffen. Mit dem Schalter -s (squeeze) werden wiederholte Instanzen eines Zeichens zu einem Zeichen.
# mehrere hintereinanderfolgende "Whitespace" zu einem Zeichen
tr -s '[:space:]' < logfile-example_.log | cut -d' ' -f1,3
1618391758 index.html 1618391759 my_test.html 1618391762 login.html
tee¶Mit Hilfe des Kommando tee wird die Standard-Eingabe (stdin)
in die Standard-Ausgabe geschrieben und zusätzlich in eine Datei.
tee ist somit ein Verzweigung, die den Input verdoppelt.
Beispielsweise wird hier zusätzlich zur Ausgabe auf der Kommandozeile das Listing in eine Datei geschrieben:
ls | tee inhalt_des_verzeichnisses.txt
Beispiel für eine sinnvolle Anwendung:
Modifiziere "crontab" Datei mit sed (siehe unten) und erstelle Backup in einem Schritt
crontab -l | tee crontab-backup.txt | sed 's/old/new/' | crontab -
crontab-Datei konfiguriert, mehr siehe z.B. in der [Ubuntu-Cron Dokumentation]. Die crontab-Datei wird in der regel nicht direkt modifiziert, sondern z.B. über den Befehl crontab -e.- bei crontab Kommando steht für die Pseudodatei stdin siehe man crontab. Dadurch wird die durch die Pipe modifizierte cron-Datei "geschrieben".
(https://wiki.ubuntuusers.de/Cron/) oder in Linux-Praxis: zeitbezogene Kommandos.uniq¶Mit uniq können Duplikat-Zeilen, die direkt aufeinanderfolgen, beseitigt werden. Eventuell muss die Datei vorher sortiert werden.
Mit dem Schalten -c kann außerdem gezählt, werden wiehäufig die einzelnen Duplikate vorkommen.
-c, --count
prefix lines by the number of occurrences
Für die weiteren Schalter sehen Sie sich z.B. die Manpage an.
# Erzeuge eine Datei mit Duplikaten:
# zweimal countries für Duplikate und extra France
cat countries.txt countries_1.txt countries.txt <(echo France) | tee duplicate_countries
France Canada Burkina Faso Democratic Republic of the Congo Russia New Zealand Germany Austria Poland France Canada Burkina Faso Democratic Republic of the Congo Russia New Zealand France
sort duplicate_countries | uniq -c
1 Austria
2 Burkina Faso
2 Canada
2 Democratic Republic of the Congo
3 France
1 Germany
2 New Zealand
1 Poland
2 Russia
paste¶paste führt Daten aus mehreren Dateien spaltenweise zusammen.
Beispiele aus https://wiki.ubuntuusers.de/paste/:
# mit Sequenzen wies
seq 1 5
1 2 3 4 5
paste <(seq 1 5) <(seq 11 15) <(seq 21 25)
1 11 21 2 12 22 3 13 23 4 14 24 5 15 25
# auch zeilenweise mögich
paste -s <(seq 1 5) <(seq 11 15) <(seq 21 25)
1 2 3 4 5 11 12 13 14 15 21 22 23 24 25
So kann man dies für eine Addition nutzen:
echo $(paste -sd+ <(seq 1 5))
paste -sd+ <(seq 1 5) | bc
1+2+3+4+5 15
Ersetzen Sie die Zeitstempel von logfile-example.log durch für Menschen lesbare Zeitangaben.
Gewünschte Ausgabe:
Mi 14. Apr 11:15:58 CEST 2021 192.168.0.140 index.html
Mi 14. Apr 11:15:59 CEST 2021 192.168.0.120 my_test.html
Mi 14. Apr 11:16:02 CEST 2021 192.168.0.140 login.html
Mi 14. Apr 11:16:05 CEST 2021 192.168.0.140 bla.html
Mi 14. Apr 11:16:11 CEST 2021 192.168.0.10 blub.html
Hinweis: Eine mögliche Lösung besteht aus der Kombination von paste, cut, date und Process Substitution.
cat logfile-example.log
1618391758 192.168.0.140 index.html 1618391759 192.168.0.120 my_test.html 1618391762 192.168.0.140 login.html 1618391765 192.168.0.140 bla.html 1618391771 192.168.0.10 blub.html
nl¶nl erzeugt eine Nummerierung der Zeilen.
whatis nl
echo
nl countries.txt
nl (1) - number lines of files
nl (1posix) - line numbering filter
1 France
2 Canada
3 Burkina Faso
4 Democratic Republic of the Congo
5 Russia
6 New Zealand
tac¶Gibt eine oder mehere Dateien in ungekehrter Reihenfolge aus:
column¶Mit column kann man (unter anderem) an Trennzeichen Spalten erzeugen:
whatis column
echo
head -4 /etc/passwd
echo
echo columnized with column:
head -4 /etc/passwd | column -t -s :
column (1) - columnate lists root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin columnized with column: root x 0 0 root /root /bin/bash daemon x 1 1 daemon /usr/sbin /usr/sbin/nologin bin x 2 2 bin /bin /usr/sbin/nologin sys x 3 3 sys /dev /usr/sbin/nologin
colrm¶z.B. x-tes bis y-te Zeichen einer Zeile ausschneiden (Zeichen sind hier jeweils "Spalten"):
od¶Dump einer Datei, z.B. im Oktal-Format.
whatis od # ähnlich zu hexdump
od -o longlist
od (1) - dump files in octal and other formats od (1posix) - dump files in various formats 0000000 071554 026440 005154 0000006
split¶Aufteilen von einer großen Datei in Teile, z.B. zum Versenden in Emails.
Mit cat (concatenate) lässt sie sich wieder rekonstruieren.
whatis split
#rm xa*
split (1) - split a file into pieces split (1posix) - split files into pieces
split -b 20 countries.txt
ls x* # so heißen die Dateien per default
xaa xab xac xad
# Anzeigen der Dateien
for file in xa*; do
echo "@"
cat $file
echo "#"
done
echo -------------------
# Zusammensetzen der Teile mit cat (geht auch bei binary files)
cat xa*
@ France Canada Burkin# @ a Faso Democratic R# @ epublic of the Congo# @ Russia New Zealand # ------------------- France Canada Burkina Faso Democratic Republic of the Congo Russia New Zealand
sed¶Mit Hilfe des Stream-Editors sed kann ein (Zeichen-)Datenstrom nach Regeln verändert werden.
Meistens verwendet man sed für Ersetzungen mit regulären Ausdrücken.
Beispiel substitute expressions s: sed -E 's/search-pattern/replacement-string/g'
g: steht für global, d.h. das nicht nur das erste gefundene Muster ersetzt wird, sondern alle.-E für extended regular expressions# Ersetze alle Leerzeichen durch ein underscore `_`
# Mehrere Leerzeichen hintereinander nur mit einem _
cat countries.txt | sed -E 's/[[:space:]]+/_/g'
France Canada Burkina_Faso Democratic_Republic_of_the_Congo Russia New_Zealand
# Beispiel: Schreibe Fehlerausgabe eines Kommandos zusätzlich in eine log-Datei
# Die log-Datei soll das Datum im Namen haben (ohne Leerzeichen!)
# hier mit echo "..." um es sichtbar zu machen
echo "command 2> $(date | sed -E 's/[[:space:]]+/_/g')_command_errors.log"
# aber besser ist als Name
echo "command 2> $(date -Iseconds)_command_errors.log"
command 2> Do_12._Mai_13:50:12_CEST_2022_command_errors.log command 2> 2022-05-12T13:50:12+02:00_command_errors.log
Gefundene Muster können natürlich auch in der Ersetzung genutzt werden. Dazu muss man redex-Gruppen bilden. Diese kann man dann referenzieren: \1 für den Match der ersten Gruppe, \2 für den Match der zweiten Gruppe etc.
Beispiel mit nur einer Gruppe (...):
cat countries.txt | sed -E 's/(a.a)/a\1a/g'
France Caanaada Burkina Faso Democratic Republic of the Congo Russia New Zeaalaand
Reguläre Ausdrücke sind standardmäßig greedy, d.h. sie entsprechen der längst möglichen Zeilenfolge.
Beispiel:
Wir möchten HTML-Tags aus Text beseitigen.
var="Das em-Tag markiert in HTML den Text <em>kursiv</em>."
Dazu verwenden wir folgendes Muster:
echo $var | sed -E 's/<.+>//g'
Das em-Tag markiert in HTML den Text .
Das greedy-Verhalten beseitigt auch den Text zwischen den HTML-Tags, was in unserem Beispiel ungewünscht ist. Daher müssen wir das Muster modifizieren:
echo $var | sed -E 's/<[^>]+>//g'
Das em-Tag markiert in HTML den Text kursiv.
Machen Sie sich klar, was das regex-Muster bedeutet.
Eine andere Möglichkeit ist es, das Muster lazy zu machen. Dann wird
der minimale Teil des Suchstrings ausgewählt, auf der das Muster zutrifft,
Hierfür dient ein ? im Muster. Das geht aber nicht mit sed.
Auf der Kommandozeile bietet sich alternativ perl (eine Programmiersprache) an:
echo $var | perl -pe 's/<.+?>//g'
# -e lese den Perl-Code direkt von stdin und nicht von einer Datei
# -p prints to stdout, for details see https://www.perl.com/pub/2004/08/09/commandline.html/
Das em-Tag markiert in HTML den Text kursiv.
Hinweis:
perl erzielt man mit perl durch $1,$2 etc.# Beispiel
echo $var | perl -pe 's/.*(<.+>).*(<.+>)./tags sind $1 und $2/'
tags sind <em> und </em>
Schreiben Sie einen Einzeiler (verknüpfte Befehle), in dem Sie alle URLs aus einer Textdatei erkennen und zeilenwiese ausgeben. Machen Sie vereinfachte Annahmen über das Muster einer URL, z.B. das diese immer mit http:// bzw. https:// beginnt. Die URLs sollen zudem immer von Leerzeichen bzw. Zeilenumbrüchen vom Rest des Textes getrennt sein.
sed unterstüzt nicht ein optionales Zeichen über ?. Hier müssen Sie auf range {0,1} ausweichen. sed -E /pattern/!d lassen sich alle Zeilen löschen, die nicht auf das Pattern zutreffen.cat text_with_urls.txt
# Kopieren Sie z.B. den Text in eine Datei zu testen Ihrer Lösung
Es gibt im Internet viele Adressen, wie z.B. http://wikipedia.de oder http://christianherta.de/ und so weiter. In dieser Zeile steht keine URL. Aber es ist auch eine Angabe mit Portnummer erlaubt, wie http://localhost:8080/mein/pfad oder mit einem Usernamen http://benutzername@www.mydomain.de/seite/beispiel.php für Durch Textmarken kann man direkt auf Bereiche springen, wie z.B. http://www.mydomain.de/seite//beispiel.php#textmarke Wieder keine Zeile ohne URL. Wieder keine Zeile ohne URL. Dies soll bei der Extraktion ignoriert werden (auch keine Leerzeile!) Statt Servernamen, die per DNS aufgelöst werden, kann aber auch direkt eine IP Adresse stehen: https://192.168.0.1/seite/beispiel.php?vname=christian&ort=berlin Bei dieser Adresse werden noch URL Parameter am Ende übergeben (http get). Der Query String beginnt dabei mit einem Fragezeichen "?" und die Parameter haben die Form name=wert und sind mit "&" getrennt. Wieder keine Zeile ohne URL. Diese soll bei der Ausgabe ignoriert werden (auch keine Leerzeile!).
Geben Sie alle Zeilen mit http:\\ bzw https:\\ aus. Ersetzen Sie im Text dabei vor dem ersten "http://" mit Nichts, d.h. folgendes soll ausgegeben werden:
http://wikipedia.de oder http://christianherta.de/ und so weiter.
http://localhost:8080/mein/pfad oder mit einem Usernamen
http://benutzername@www.mydomain.de/seite/beispiel.php für
http://www.mydomain.de/seite//beispiel.php#textmarke
https://192.168.0.1/seite/beispiel.php?vname=christian&ort=berlin Bei dieser Adresse werden noch URL Parameter am Ende übergeben (http get). Der Query String beginnt dabei mit einem Fragezeichen "?" und die Parameter haben die Form name=wert und sind mit "&" getrennt.
egrep 'http://|https://' text_with_urls.txt | perl -pe 's/^.*?(https?:\/\/)/$1/g'
http://wikipedia.de oder http://christianherta.de/ und so weiter. http://localhost:8080/mein/pfad oder mit einem Usernamen http://benutzername@www.mydomain.de/seite/beispiel.php für http://www.mydomain.de/seite//beispiel.php#textmarke https://192.168.0.1/seite/beispiel.php?vname=christian&ort=berlin Bei dieser Adresse werden noch URL Parameter am Ende übergeben (http get). Der Query String beginnt dabei mit einem Fragezeichen "?" und die Parameter haben die Form name=wert und sind mit "&" getrennt.
Wenn man mit sed Teile extrahieren will, kann man die Zeile mit den entsprechenden
Gruppenreferenzen ersetzen.
Hier mit \1 für die erste regEx-Gruppe:
line="Das ist eine IPv4 Adresse 192.168.0.5 in einem privaten Netz."
# Extract the IPv4
echo $line | sed -n -E 's/.*[^[:digit:]](([0-9]{1,3}\.){3}[0-9]{1,3})[^[:digit:]].*/\1/p'
# Machen Sie sich die Bedeutung der regex klar!
192.168.0.5
Wenn man für Zeilen, die man für ein Ersetzungsmuster ausschießen will, ein Muster angeben will, so geht dies folgendermaßen:
# Ersetze alle "a" durch "e" außer in den Zeilen mit einem großen "C"
sed -E '/C/! s/a/e/g' countries.txt
Frence Canada Burkine Feso Democratic Republic of the Congo Russie New Zeelend
sed cheet sheet:
Mehr zu sed finden Sie z.B. auch
sed manualawk¶"The awk utility interprets a special-purpose programming language that makes it possible to handle simple data-reformatting jobs with just a few lines of code." aus https://www.gnu.org/software/gawk/
awk ist ein Werkzeug (eigentlich sogar eine Programmiersprache), das sich insbesondere zur Prozessierung von Text in Feldstruktur eignet. Hier beschränken wir uns auf einfache Beispiele.
Hier ein ganz einfaches Beispiel (als Alternative zu cut):
awk '{print $2 "\t" $3}' logfile-example.log
192.168.0.140 index.html 192.168.0.120 my_test.html 192.168.0.140 login.html 192.168.0.140 bla.html 192.168.0.10 blub.html
# Erinnerung
cat logfile-example.log # Logfile der Abrufe
# Zeitstempel IP-des-Web-Servers Abgerufene-Seite
echo
cat rechnernamen.txt # Ip-addresse Webservername
1618391758 192.168.0.140 index.html 1618391759 192.168.0.120 my_test.html 1618391762 192.168.0.140 login.html 1618391765 192.168.0.140 bla.html 1618391771 192.168.0.10 blub.html 192.168.0.10 sokrates 192.168.0.120 aristoteles 192.168.0.140 platon
Beispiel: Web-Traffic auf die einzelnen Rechner.
Wir möchten die Uhrzeit zusammen mit dem Namen des Webservers.
Mit gnu-awk gawk ist eine Funktion strftime zur Konvertierung von Timestamps zu Datumsangaben verfügbar:
Hinweis: Muss unter Ubuntu/Debian nachinstalliert werden sudo apt-get install gawk, da standardmäßig mawk installiert ist.
join -1 2 -2 1 -t $'\t' <(sort -t $'\t' -k2 logfile-example.log) rechnernamen.txt | \
sort -t $'\t' -k2 | awk '{ print strftime("%m/%d/%Y %H:%M:%S", $2) "\t" $4 }'
04/14/2021 11:15:58 platon 04/14/2021 11:15:59 aristoteles 04/14/2021 11:16:02 platon 04/14/2021 11:16:05 platon 04/14/2021 11:16:11 sokrates
Mehr zu awk finden Sie
gawk-User GuideSchreiben Sie einen Einzeiler, die gesamte Anzahl der Duplikate zählt und testen Sie dies an
duplicate_countries (siehe oben: cat countries.txt countries_1.txt countries.txt <(echo France) > duplicate_countries)
D.h. für jede Zeile, die mehrfach vorkommt, soll das mehrfache Vorkommen gezählt werden, z.B.
Austria einmal vor. Somit ist die Anzahl der Duplikate für Austria Null.Canada zweimal vor. Somit ist die Anzahl der Duplikate für Canada Eins.France dreimal vor. Somit ist die Anzahl der Duplikate für France Zwei.Das Ergebnis ist für die Datei duplicate_countries somit 7.
cat duplicate_countries
France Canada Burkina Faso Democratic Republic of the Congo Russia New Zealand Germany Austria Poland France Canada Burkina Faso Democratic Republic of the Congo Russia New Zealand France
comm¶comm vergleicht zwei alphabetisch sortiere Dateien:
comm <(seq 1 4) <(seq 2 5)
1 2 3 4 5
In der ersten Ausgabespalte werden die Zeilen, die nur in Datei 1 vorkommen, dargestellt. in der zweiten Spalte werden die Zeilen angezeigt, die nur in Datei 2 vorkommen. In der dritten Spalte werden die Zeilen dargestellt, die in beiden Dateien vorkommen.
Mit de Schalter -2 kann bespielsweise die Darstellung der zweiten Spate unterdrückt werden. Probieren Sie es aus.
comm -2 <(seq 1 4) <(seq 2 5)
1 2 3 4
Wie können (mit einem Einzeiler) nur die Länder angezeigt werden, die in den Dateien countries.txt und countries_2.txt (siehe unten)
vorkommen?
diff¶diff berechnet (zeilenweise) den Unterschied (differences) zwischen zwei Dateien und zeigt diesen an.
Die einfachste Benutzung ist diff datei1 datei2:
echo "Canada
Burkina Faso
France
Democratic Republic of the Kongo
Austria
New Zealand
Germany
Switzerland" > countries_2.txt
diff countries.txt countries_2.txt
1d0 < France 4,5c3,5 < Democratic Republic of the Congo < Russia --- > France > Democratic Republic of the Kongo > Austria 6a7,8 > Germany > Switzerland
diff liefert also eine kompake Darstellung der Unterschiede. Dabei werden Operationen
angegeben, die datei1 in datei2 überführen.
| Änderung | Beschreibung |
|---|---|
l1dl2 |
Lösche (delete) die Zeilen ab Zeile l1 in der ersten Datei, die auftauchen würden bei Zeile l2 der zweiten Datei |
l1cl2 |
Ersetze (bzw. ändere, change) die Zeilen l1 der ersten Datei mit den Zeilen l2 der zweiten Datei. |
l1al2 |
Füge (add) die Zeilen ab Position l1 in der ersten Datei hinzu, die auftauchen bei den Zeilen l2 der zweiten Datei. |
In unserem Beispiel bedeuten die Differenzangaben:
1d0 Lösche die erste Zeile von datei1. Diese wäre in der 0. Zeile in datei2.4,5c3,5 Ersetze die Zeilen 4 und 5 der ersten Datei mit den Zeile 3 bis 5 der zweiten Datei.6a7,8 Füge die Zeilen 7 und 8 von datei2 in datei1 ab Zeile 6 hinzu.Neben diesen POSIX-konformen Änderungsangaben (Standard bei diff) gibt es noch weitere Formate, wie
-c-uDiese beeinhalten Kontext, d.h. die Diffenzangaben sind nicht mehr so sensitiv bzgl. Zeilennummerveränderungen.
diff -c countries.txt countries_2.txt
*** countries.txt 2021-11-17 09:51:55.432388497 +0100 --- countries_2.txt 2021-11-17 10:29:56.299350472 +0100 *************** *** 1,6 **** - France Canada Burkina Faso ! Democratic Republic of the Congo ! Russia New Zealand --- 1,8 ---- Canada Burkina Faso ! France ! Democratic Republic of the Kongo ! Austria New Zealand + Germany + Switzerland
Die Ausgabe beginnt mit den Namen der Dateien und einem Zeitstempel.
***.---.Dann werden jeweils die beiden Dateien ausgegeben, hier steht z.B.
--- 1,8 ---- für zweite Datei (---) mit Zeilen 1 bis 8.
Die Änderungsangaben zur Überführung von Datei 1 in Datei 2 sind:
- Zeile löschen (kommt nur bei Datei 1 vor)+ Zeile hinzufügen (kommt nur bei Datei 2 vor) Keine Änderung! Zeile muss geändert werden. Die jeweiligen Versionen stehen bei den jeweiligen Dateien.diff -u countries.txt countries_2.txt
--- countries.txt 2021-11-17 09:51:55.432388497 +0100 +++ countries_2.txt 2021-11-17 10:29:56.299350472 +0100 @@ -1,6 +1,8 @@ -France Canada Burkina Faso -Democratic Republic of the Congo -Russia +France +Democratic Republic of the Kongo +Austria New Zealand +Germany +Switzerland
Das Unified Format ähnelt dem *Context Format* bezüglich der ersten drei Zeilen.
Die Bedeutungen der Zeichen-,+und ` ist auch die Gleiche, wie im Context Format.
Am einfachsten sind die Angaben ab Zeile 4 zu verstehen, wenn man die Angaben zeilenweise zusammen mit Datei
1 liest und die Änderungen bzw. Nicht-Änderung anwendet, sodass man Datei 2 erhält.
Bemerkung: Für eine einfach zu lesenden Zweispaltenansicht der Unterschiede zweier Text-Dateien gibt es das Kommandozeilentool icdiff.
patch¶Die Änderungsdatei die diff erzeugt, kann automatsch mittels patch auf eine Datei angewendet werden.
So kann man Änderungen einfach nachvollziehen. Wenn außerdem in einer (sehr) großen Datei nur eine kleine Änderung vorgenommen wurde, ist es vorteilhaft nur die Änderung (z.B. über ein Netzwerk) zu übertragen, da diese viel kleiner sind.
Dies wird z.B. auch bei der Entwicklung von Software, wie dem Linux-Kernel, genutzt.
Entwickler erzeugen relative kleine Code-Änderungen auf dem Kernel Source Tree (Dateibaum, kann rekursiv mit diff durchlaufen werden). Diese werden als diff-Dateien weitergegeben.
Dieser Prozess bei der verteilten Softwareentwicklung wird mit Versionkontrollsystemen, wie git, durchgeführt, die unter der Haube diff und patch verwenden.
Hier zwei weitere Versionen der Datei, um zu zeigen, dass patch auf Dateien mit
kleinen Änderungen der Ursprungsdatei (außerhalb des Kontextes) angewendet werden kann.
echo "Kanada
Burkina Faso
France
Democratic Republic of the Kongo
Austria
New Zealand
Germany
Schweiz" > countries_3.txt
echo "Kanada
Burkina Faso
France
Democratic Republic of the Congo
Austria
New Zealand
Germany
Schweiz" > countries_4.txt
cat countries_2.txt
Canada Burkina Faso France Democratic Republic of the Kongo Austria New Zealand Germany Switzerland
In der diff-Datei stehen die Änderungen, die von countries_3.txt zu countries_2.txt führen:
# Reduktion des Kontexts auf 2 (default 3)
diff --context=2 countries_3.txt countries_2.txt | tee countries.patch
*** countries_3.txt 2021-12-06 10:13:36.303466356 +0100 --- countries_2.txt 2021-12-06 09:44:25.445222422 +0100 *************** *** 1,3 **** ! Kanada Burkina Faso France --- 1,3 ---- ! Canada Burkina Faso France *************** *** 6,8 **** New Zealand Germany ! Schweiz --- 6,8 ---- New Zealand Germany ! Switzerland
Aber wir patchen countries_4.txt. Hier ist die Schreibweise von Congo auf C korrigiert. Dies berücksichtigt
der Patch (Patch-Datei) nicht.
# patch the counties.txt file (which file to patch is in the patch file)
#patch < countries.patch
# but we want path countries_3, so we give this filename
# -i Read the patch from patchfile. If patchfile is -, read from standard input, the default.
# -b for backup would copy the original countries_3.txt to countries_3.txt.orig
patch -b -i countries.patch countries_4.txt
patching file countries_4.txt
ls countries_4.txt*
countries_4.txt countries_4.txt.orig countries_4.txt.rej
cat countries_4.txt
Canada Burkina Faso France Democratic Republic of the Congo Austria New Zealand Germany Switzerland
# -R Reverses the previous patch
patch -p0 -R -i countries.patch countries_4.txt
patching file countries_4.txt
cat countries_4.txt
Kanada Burkina Faso France Democratic Republic of the Congo Austria New Zealand Germany Schweiz
Was passiert im obigen patch-Beispiel, wenn beim diff die Standardgröße des Kontext verwendet wird. Erklären Sie dies.
Gängige moderne Datenaustauschformate sind meist Text-basiert, d.h. es sind Textdateien in einem speziellen Format. Beispiele sind hier JSON, YAML und XML.
Für diese gängigen textbasierten Datenaustauschformate gibt es auch unterschiedliche Kommandozeilenwerkzeuge, wie z.B.
Zählen Sie die Anzahl der unterschiedlichen Worte der Datei greetings
mit einem Einzeiler.
Dabei sollen Worte die groß- oder kleingeschrieben werden, nur einmal zählten.
Also alle Wörter Hallo bzw. hallo zählen nur einmal. Insgesamt gibt es
6 verschiedliche Terme (normalisierte Worte) in greetings.
echo "Hallo Welt
hallo welt sind Grüße
an die Welt" > greetings
Wie oft kommt das Wort "Technik" auf der www-Startseite der HTW-Berlin vor?
curl --silent https://www.htw-berlin.de, um den Inhalt der Seite herunterzuladen und pipen Sie den Inhalt direkt weiter in eine Befehlskette. grep zur Filterung.Analysieren Sie die untenstehenden Beispiele.
man ls | sed -e 's/[^[:alpha:]]/ /g' | tr '\n' " " | tr -s " " | tr " " '\n'| \
tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl
1 20 sort
2 20 of
3 19 by
4 17 with
5 17 the
6 16 to
7 16 list
8 15 file
9 15 and
10 14 time
11 14 l
12 13 style
13 13 is
14 12 or
15 12 not
16 12 ls
17 12 a
18 10 size
19 10 format
20 10 entries
21 10 do
22 9 word
23 9 show
24 9 print
25 9 if
26 8 g
27 8 for
28 8 default
29 7 use
30 6 when
31 6 shell
32 6 output
33 6 names
34 6 m
35 6 line
36 6 in
37 6 group
38 6 gnu
39 6 first
40 6 each
41 6 command
42 6 color
43 6 c
44 6 access
45 5 x
46 5 version
47 5 u
48 5 t
49 5 name
50 5 long
51 5 like
52 5 instead
53 5 information
54 5 indicator
55 5 entry
56 5 e
57 5 directory
58 5 coreutils
59 5 but
60 4 software
61 4 s
62 4 pattern
63 4 org
64 4 none
65 4 newest
66 4 link
67 4 k
68 4 iso
69 4 implied
70 4 http
71 4 full
72 4 files
73 4 escape
74 4 directories
75 4 ctime
76 4 cols
77 4 can
78 4 append
79 4 always
80 3 width
81 3 type
82 3 symbolic
83 3 status
84 3 sizes
85 3 quoting
86 3 q
87 3 powers
88 3 p
89 3 nongraphic
90 3 no
91 3 never
92 3 n
93 3 modification
94 3 locale
95 3 ignore
96 3 help
97 3 free
98 3 f
99 3 exit
100 3 dereference
101 3 characters
102 3 be
103 3 b
104 3 auto
105 3 author
106 3 as
107 3 are
108 2 z
109 2 www
110 2 v
111 2 using
112 2 user
113 2 units
114 2 this
115 2 terminal
116 2 slash
117 2 set
118 2 see
119 2 reverse
120 2 recent
121 2 readable
122 2 r
123 2 posix
124 2 otherwise
125 2 order
126 2 options
127 2 option
128 2 only
129 2 one
130 2 omitted
131 2 numeric
132 2 matching
133 2 mandatory
134 2 lt
135 2 literal
136 2 listing
137 2 likewise
138 2 it
139 2 info
140 2 i
141 2 hyperlink
142 2 human
143 2 hide
144 2 h
145 2 gpl
146 2 follow
147 2 extension
148 2 dired
149 2 d
150 2 copyright
151 2 control
152 2 context
153 2 contents
154 2 columns
155 2 classify
156 2 chars
157 2 change
158 2 cannot
159 2 bugs
160 2 blocks
161 2 block
162 2 below
163 2 before
164 2 at
165 2 argument
166 2 any
167 2 also
168 2 alphabetically
169 2 all
170 1 you
171 1 y
172 1 written
173 1 without
174 1 within
175 1 while
176 1 warranty
177 1 w
178 1 via
179 1 vertical
180 1 verbose
181 1 variable
182 1 usage
183 1 unless
184 1 unit
185 1 uid
186 1 types
187 1 trouble
188 1 translationproject
189 1 translation
190 1 too
191 1 tion
192 1 times
193 1 there
194 1 then
195 1 themselves
196 1 them
197 1 their
198 1 that
199 1 than
200 1 text
201 1 team
202 1 takes
203 1 tabsize
204 1 tab
205 1 synopsis
206 1 symlink
207 1 subdirectory
208 1 subdirectories
209 1 stops
210 1 starting
211 1 standard
212 1 stallman
213 1 specified
214 1 speci
215 1 sorting
216 1 single
217 1 si
218 1 showing
219 1 short
220 1 settings
221 1 serious
222 1 separated
223 1 security
224 1 scale
225 1 richard
226 1 reporting
227 1 report
228 1 references
229 1 redistribute
230 1 recursively
231 1 recursive
232 1 rather
233 1 quotes
234 1 quote
235 1 program
236 1 problems
237 1 prints
238 1 printing
239 1 pre
240 1 points
241 1 permitted
242 1 per
243 1 owner
244 1 overridden
245 1 outside
246 1 optional
247 1 online
248 1 on
249 1 ok
250 1 o
251 1 numbers
252 1 number
253 1 nor
254 1 non
255 1 newline
256 1 natural
257 1 more
258 1 mode
259 1 minor
260 1 means
261 1 mb
262 1 mackenzie
263 1 locally
264 1 listed
265 1 links
266 1 lines
267 1 limit
268 1 licenses
269 1 license
270 1 law
271 1 later
272 1 last
273 1 largest
274 1 kibibytes
275 1 key
276 1 kb
277 1 january
278 1 itself
279 1 invocation
280 1 interpreted
281 1 integer
282 1 inode
283 1 informa
284 1 index
285 1 inc
286 1 ids
287 1 html
288 1 horizontal
289 1 grouping
290 1 gplv
291 1 gid
292 1 generate
293 1 foundation
294 1 fixed
295 1 fill
296 1 fied
297 1 extent
298 1 except
299 1 example
300 1 escapes
301 1 environment
302 1 ending
303 1 enclose
304 1 enable
305 1 emits
306 1 emacs
307 1 effect
308 1 double
309 1 don
310 1 documentation
311 1 distinguish
312 1 display
313 1 disk
314 1 disables
315 1 disabled
316 1 disable
317 1 dircolors
318 1 dir
319 1 designed
320 1 description
321 1 david
322 1 date
323 1 current
324 1 connected
325 1 commas
326 1 commands
327 1 comma
328 1 column
329 1 colors
330 1 colorize
331 1 codes
332 1 cftuvsux
333 1 bytes
334 1 byte
335 1 both
336 1 backups
337 1 avoid
338 1 available
339 1 augmented
340 1 au
341 1 atime
342 1 assume
343 1 arguments
344 1 applies
345 1 an
346 1 almost
347 1 allocated
348 1 across
349 1 about
man ls | sed -e 's/[^[:alpha:]]/ /g' | tr '\n' " " | tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | \
sort | uniq -c | sort -nr | nl | awk ' $2 > 12 && length($3) >= 2 { printf "%3s\t%10s\t%2s\n", $1, $3, $2}'
# $2 > 12: alle Worte, die mehr als 12-mal vorkommen - in zweiten Spalte ($2) steht die Häufigkeit
# length($3) > 1 : Die Wortlänge muss mindesten zwei sein - in der ditten Spalte stehen die Worte
1 sort 20 2 of 20 3 by 19 4 with 17 5 the 17 6 to 16 7 list 16 8 file 15 9 and 15 10 time 14 12 style 13 13 is 13
man ls | sed -e 's/[^[:alpha:]]/ /g' | tr '\n' " " | tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | \
sort | uniq -c | sort -nr | nl | awk '{ print $2}'| paste -sd+ | bc -l
997
Modifizieren Sie das Beispiel von oben, so dass nur eine Wort-ID (erste Spalte) und die Worte in der Ausgabe vorkommen. Die häufigsten Worte sollen dabei die niedrigste ID haben, wie oben, d.h. die Ausgabe soll folgendermaßen beginnen:
1 sort
2 of
3 by
4 with
...
Erstellen Sie ein bash-Script, das ein Befehlsinhaltsverzeichnis als HTML-Seite (Grundgerüst einer HTML Seite) mit Link-Referenzen zu den entsprechenden Webseiten erstellt. Die mögliche relevanten Seiten sind alle relative Links der Seite http://christianherta.de/lehre/praktischeInformatik/praktischeInformatik.html.
Die erzeugte HTML-Seite soll in etwas wie folgt aussehen:
<!DOCTYPE html>
<!-- from https://wiki.selfhtml.org/wiki/HTML/Tutorials/HTML5/Grundger%C3%BCst -->
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Befehlsverzeichnis</title>
</head>
<body>
<a href="http://christianherta.de/lehre/praktischeInformatik/./bash/bash_1.html">cd</a></br>
<a href="http://christianherta.de/lehre/praktischeInformatik/./bash/bash_1.html">chmod</a></br>
....
<a href="http://christianherta.de/lehre/praktischeInformatik/./Netzwerke/Netzwerke_1.html">traceroute</a></br>
</body>
</html>
Hinweise:
Versuchen Sie nicht eine perfekte Lösung zu finden. Solche Skripte sind oft ein Hack für eine schnelle Lösung. Überlegen Sie sich zur Extraktion der Befehle entsprechende Extraktionspipelines. Dies arbeiten typischerweise mit regulären Ausdrücken. Sehen Sie sich hierzu den HTML-Quellcode der Seiten an. Bei vielen Browser können Sie hierzu die Tasktenkombination Strg Shift c verwenden.
Bei der Extraktionspipeline müssen Sie zudem typischerweise eine Abwägung zwischen Precision und Recall machen:
Überlegen Sie sich außerdem,welche Probleme beim Programmieren auftreten. Insbesondere welche Datenstrukturen die Entwicklung erleichtern würden. Wo liegen die Grenzen von bash-Skripten?