Linux
Dipl.-Inf., Dipl.-Ing. (FH) Michael Wilhelm
Hochschule Harz
FB Automatisierung und Informatik
mwilhelm@hs-harz.de
http://www.miwilhelm.de
Raum 2.202
Tel. 03943 / 659 338
Inhalt
1. Einführung, Literatur, Begriffe 2. Installation
3. Konsolen-Befehle, Shell, Manual
4. Komplexe Befehle (grep, find, tar, sed, cron, netcat) 5. C-Programmierung (C, IO, Thread, make)
6. Python (Sprache) 7. Python (GUI)
Linux und C
C
− Variablen à la Java
− Datentypen à la Java, auch unsigned
− if à la Java
− Schleifen à la Java, ohne foreach
− Prozeduren à la Java-Methoden
− Keine Klassen (C++, g++)
− I/O (Komfortables Framework)
− Handle-Konzept
− Pointer
− Threads und Semaphore, Mutex
− Zugriff auf das System (Dateien, Ordner, Prozesse)
Linux und C
Programme
− gcc
− g++
− gdb Debugger
− make-Datei
− Editoren
• vi, vim
• nano
• Emacs
• Texteditor in der GUI
− Übersetzen in der Konsole
C-Programmierung
Beispielcode: Ausgabe eines Textes
#include <stdio.h>
int main(void){
puts("Hallo Wernigerode");
return 0;
}
Übersetzen mit:
• gcc bsp1.c -o bsp1
• -S nur kompilieren
• -c nur kompilieren und assemblieren
• -o <Datei> kompilieren, assemblieren, linken
• -O Optimieren
long long summe; // globale Variable
void calc(long n) { long i;
summe=0.0;
for (i=0; i<=n; i++) { summe+= i;
} }
int main(int argc, char *argv[]) { calc(1000);
printf("Summe: %ld\n",summe);
return 0;
Beispielcode: Summe von 1 bis n
long long calc(long n) { long i;
summe=0.0;
for (i=0; i<=n; i++) { summe+= i;
} }
int main(int argc, char *argv[]) { long long summe = calc(1000);
printf("Summe: %ld\n",summe);
return 0;
}
Beispielcode: Summe von 1 bis n
if [ $# -eq 0 ] then
echo "bitte einen Parameter uebergeben"
echo " c bsp1"
else
gcc $1.c -o $1 fi
I/O-Funktionen
fopen
FILE *fopen (const char *Pfad, const char *Modus);
• Modus:
• r - Datei nur zum Lesen öffnen (READ)
• w - Datei nur zum Schreiben öffnen (WRITE), löscht den Inhalt der Datei, wenn sie bereits existiert
• a - Daten an das Ende der Datei anhängen (APPEND), die Datei wird nötigenfalls angelegt
• r+ - Datei zum Lesen und Schreiben öffnen, die Datei muss bereits existieren
• w+ - Datei zum Lesen und Schreiben öffnen, die Datei wird nötigenfalls angelegt
• a+ - Datei zum Lesen und Schreiben öffnen, um Daten an das Ende der Datei anzuhängen, die Datei wird nötigenfalls angelegt
• b - Binärmodus (anzuhängen an die obigen Modi, z.B. "rb" oder "w+b").
• t – Textdatei Modus
I/O-Funktionen: fopen + fprintf schreiben
Rückgabewert:
• Bei einem Fehler NULL
• Sonst handle für diese Datei Beispiele:
• #include <stdio.h>
• FILE *handle;
• handle = fopen ("testdatei.txt", "wt"); // wenn vorhanden, gelöscht
• if (handle == NULL) {
• printf("Fehler beim Oeffnen der Datei.");
• }
• else {
• int i=42;
• fprintf (handle, "Hallo, Welt i:%d\n");
• fclose (handle);
I/O-Funktionen: fopen + fprintf schreiben
• #include <stdio.h>
• FILE *handle;
• handle = fopen ("testdatei.txt", "wt"); // wenn vorhanden, gelöscht
• if (handle == NULL) {
• printf("Fehler beim Oeffnen der Datei.");
• }
• else {
• for (int i=0; i<100; i++)
• fprintf (handle, "%d\n",i); // %c %i %s %f %lf %ld
• fclose (handle);
• }
I/O-Funktionen: fopen + fgets lesen
#include <stdio.h>
FILE * handle;
handle = fopen ("testdatei.txt", "rt");
if (handle == NULL) {
printf("Fehler beim Oeffnen der Datei.");
}
else {
char s[100];
fgets (s, 100, handle); // ende wenn i>=n oder \r\n fclose (handle);
puts(s);
}
I/O-Funktionen: Parameter, fopen + fgets lesen
#include <stdio.h>
int main(int argc, char *argv[]) if (argc>1) {
FILE * handle;
handle = fopen (argv[1], "rt");
if (handle == NULL) {
printf("Fehler beim Oeffnen der Datei.");
}
else {
char s[100];
fgets (s, 100, handle); // ende wenn i>=n oder \r\n fclose (handle);
} // if } // if } // main
I/O-Funktionen: fopen + fprintf schreiben
#include <stdio.h>
int main(int argc, char *argv[]) if (argc>1) {
FILE * handle;
handle = fopen (argv[1], "wt");
if (handle == NULL) {
printf("Fehler beim Oeffnen der Datei.");
}
else {
fprintf (handle, "Hallo, Welt\nHallo Hochschule\n");
fclose (handle);
} // if } // if } // main
I/O-Funktionen: fopen + binär schreiben
#include <stdio.h>
// size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream) int main(int argc, char *argv[])
if (argc>1) {
FILE * handle;
handle = fopen (argv[1], "wb");
if (handle == NULL) {
printf("Fehler beim Oeffnen der Datei.");
}
else {
for (int i=-2; i<100; i++)
int n = fwrite (&i, sizeof(i), 1, handle);
fclose (handle);
} // if } // if
abc im Hexeditor: 2er Komplement
I/O-Funktionen: fopen + binär lesen
int main(int argc, char *argv[]) if (argc>1) {
FILE * handle;
handle = fopen (argv[1], "rb");
if (handle == NULL) {
printf("Fehler beim Oeffnen der Datei.");
}
else {
int value;
for (int i=0; i<100; i++) {
int n = fread (&value, sizeof(value), 1, handle);
printf("i: %d wert: %d\n",i,value);
}
fclose (handle);
} // if
I/O-Funktionen: fopen + binär schreiben
void testwrite() { int n=102;
fwrite (&n, sizeof(n), 1, handle); // vorher wissen wieviel !!
for (int i=-2; i<100; i++) {
int n = fwrite (&i, sizeof(i), 1, handle);
} }
void testread() { int n;
int anz = fread (&n, sizeof(n), 1, handle);
for (int i=0; i<n; i++) {
anz = fread (&value, sizeof(value), 1, handle);
printf("i: %d wert: %d anz: %d \n",i,value, anz);
} }
Beispielcode: Threads erzeugen
// standardisierte Thread – Methode void * calc(void *param) {
int retcode=0;
puts("im thread");
pthread_exit ( (void *) retcode );
}
int main(int argc, char *argv[]) { pthread_t pt1;
if ( pthread_create(&pt1, NULL, calc, NULL) ) {
fprintf( stderr, "Fehler beim Erzeugen des 1. Threads\n");
exit (EXIT_FAILURE);
}
return EXIT_SUCCESS;
gcc t1.c -o t1 -lpthread
Beispielcode:
Threads erzeugen mit Parameter t2.c
struct ThreadRec { int id;
long anz;
int anzThreads;
};
long long summe;
void * calc(void *param) { long i;
int von, bis, n;
struct ThreadRec *pDaten;
pDaten = (struct ThreadRec *) (param);
int id = pDaten->id;
int diff = pDaten->anz / pDaten->anzThreads;
von=diff*(id-1)+1;
if (id==pDaten->anzThreads) bis=pDaten->anz;
else
bis=diff*(id);
printf("id: %d von:%d bis:%d\n",id, von,bis);
for (i=von; i<=bis; i++) { summe+= i;
} // for }
Beispielcode: Threads erzeugen mit Parameter t2.c
int main(int argc, char *argv[]) { pthread_t p1,p2;
int n=10000;
struct ThreadRec tDaten1;
struct ThreadRec tDaten2;
tDaten1.id=1;
tDaten1.anz=n;
tDaten1.anzThreads=2;
tDaten2.id=2;
tDaten2.anz=n;
tDaten2.anzThreads=2;
summe=0.0;
Beispielcode: Threads erzeugen mit Parameter t2.c
summe=0.0;
if ( pthread_create(&p1, NULL, calc, &tDaten1) ) { puts("error beim Erzeugen des 1. Threads");
exit(EXIT_FAILURE);
}
if ( pthread_create(&p2, NULL, calc, &tDaten2) ) { puts("error beim Erzeugen des 2. Threads");
exit(EXIT_FAILURE);
}
printf("Summe: %ld\n",summe);
return 0;
}
gcc t2.c -o t2 -lpthread
Problem:
− Die Summe ist null
− Es fehlt das Warten auf das Ende der Thread
Lösung:
− pthread_join(p1,NULL);
− pthread_join(p2,NULL);
Beispielcode: Threads erzeugen mit Parameter t3.c
Problem:
− Die Summe ist nicht exakt (Synchronize)
Lösung:
− pthread_mutex_t sumMutex;
− for (i=von; i<=bis; i++) {
− pthread_mutex_lock(&sumMutex);
− summe+= i;
− pthread_mutex_unlock(&sumMutex);
− }
− pthread_mutex_init( &sumMutex, NULL );
Beispielcode: Threads erzeugen mit Parameter t4.c
Debugger
Programm gdb
Konsolen orientiert
Vorgehen:
vi b.c // schreiben und speichern
gcc b.c –ggdb3 -o b // übersetzen
gdb b // Aufruf des Debuggers
run // starten des Programms
- l // Anzeige, list um main
- r // Starten
- n // next, nächster Schritt, ohne Funktion
- s // step. Nächster Schritt, mit Funktion
■ r // Starten, komplett Summe: 55
■ l // Listing um main
■ l 1,30 // Listing von Zeile 1 bis 30
■ b 23 // Breakpoint setzen auf Zeile 23
■ r // Starten bis zum ersten Breakpoint oder vollständig
■ // Angezeigt wird IMMER der nächste Befehl
■ n // nächster Befehl, bis zum Ende
■ r // Starten bis zum ersten Breakpoint oder vollständig // Angezeigt wird IMMER der nächste Befehl
■ s // nächster Befehl step, in die Funktion
■ print i // Anzeige des Inhalts von i
■ print s // Anzeige des Inhalts von s
■ whatis i // Anzeige des Typs von i
■ set variable s=0 // ändern der Summe
■ print s // Anzeige des Inhalts von s, Test
c // laufen lassen bis zum Ende oder zum nächsten Breakpoint
Optionen
int summe (int n) { int i, s;
s=0;
for (i=0; i<=n; i++) s+=i;
return s;
}
int main(int argc, char* argv[]) { int i, n, s;
int f[10];
n=10;
s=summe(n);
printf("summe: %d \n",s);
for (i=0; i<10; i++) { f[i]=i;
}
i=2; // für Haltepunkt
Testbeispiel
für das Debugging
I/O mit Dateien und Verzeichnissen
mkdir(char *path)
− Anlegen eines Verzeichnisses
− Rückgabe: 0=okay -1=Fehler
ckdir(char *path)
− Wechseln in ein Verzeichnis (relativ und absolut)
− Rückgabe: 0=okay -1=Fehler
rmdir
− Löscht ein leeres Verzeichnis
− Rückgabe: 0=okay -1=Fehler
opendir
Neue vereinheitliche Posix-Funktion
I/O mit Dateien und Verzeichnissen
Dir* dir = opendir(char *path) // "/home/user1" "."
− Anlegen eines Verzeichnisses
− Rückgabe: 0=okay -1=Fehler
− Liefert eine Liste der Einträge
struct* dirent dirItem = readdir(Dir *dir)
− Gibt den i-ten Eintrag zurück
− Rückgabe: Fehler: NULL
int closedir(Dir *dir)
− Rückgabe: Fehler: NULL
struct dirent
− ino_t d_ino; /* inode number */
− off_t d_off; /* offset to the next dirent */
− unsigned short d_reclen; /* length of this record */
− unsigned char d_type; // DT_REG DT_DIR DT_UNKNOWN
Nachbau von
− mkdir
− cd
− ls
− grep
Rekursiv
− ls -R
− find