Opérations sur les répertoires et fichiers sous Linux
Arborescence standard de Linux
Windows utilise des commandes DOS, tandis que Linux utilise des commandes shell.
Commandes Linux courantes
cd dossier: accéder à un dossierls: lister les fichiers du répertoire couranttouch fichier: créer un fichierrm fichier: supprimer un fichiermkdir repertoire: créer un répertoirerm -rf repertoire: supprimer un répertoire (récursif et forcé)TAB: autocomplétionsudo commande: exécuter avec les droits administrateurpwd: afficher le chemin absolu du répertoire courant
Éditeur vi
vi est un éditeur de texte présent par défaut sur la plupart des systèmes Linux. vim est une version améliorée, mais les systèmes embarqués ne possèdent souvent que vi. Sous Ubuntu, on peut installer vim avec :
sudo apt-get install vim
Pour ouvrir ou créer un fichier : vi nomfichier
Deux modes principaux de vi
Mode commande (accessible via Echap) :
: + numéro_ligne: aller à une ligne spécifiqueG: aller à la fin du fichieryy: copier la ligne couranteyx(x = nombre) : copier x lignes à partir de la position courantep: coller le contenu copié:wq: enregistrer et quitter:q: quitter sans enregistrer (si aucune modification):q!: quitter de force:set nu: afficher les numéros de ligne:dd: supprimer une ligneESC: gg=G: indenter automatiquement tout le code
Mode insertion (accessible via i) : permet de taper du texte (souris inutilisable).
Pour compiler un programme C avec GCC :
sudo apt-get install gcc
gcc test.c # produit a.out par défaut
gcc test.c -o hello # produit un exécutable nommé hello
Les fichiers sous Linux
Les pages de manuel Linux s'utilisent ainsi : man 1 pour les commandes shell, man 2 pour les appels système (open, write, etc.).
Permissions des fichiers
Les permissions sont représentées par trois chiffres octaux (ex: 0755, 0644).
- 7 = rwx (lecture, écriture, exécution)
- 6 = rw- (lecture, écriture)
- 5 = r-x (lecture, exécution)
- 4 = r-- (lecture seule)
- 3 = -wx (écriture, exécution)
- 2 = -w- (écriture seule)
- 1 = --x (exécution seule)
- 0 = --- (aucun droit)
Exemple avec ls -l :
-rw-rw-r-- 1 cc cc 41 mai 2 06:53 1q
-rw-rw-r-- 1 cc cc 13 mai 2 05:53 a.c
-rwxrwxr-x 1 cc cc 8656 mai 2 02:04 demo
Pour le fichier a.c : l'utilisateur et le groupe ont les droits rw-, les autres ont r--.
Fonctions d'entrée/sortie de bas niveau (file I/O)
1. open()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
Retour : un descripteur de fichier (entier) en cas de succès, -1 en cas d'échec.
Paramètres :
pathname: chemin du fichier (absolu ou relatif).flags: mode d'ouverture (O_RDONLY, O_WRONLY, O_RDWR) combiné avec O_CREAT, O_TRUNC, O_APPEND, O_EXCL, etc.mode: permissions si création (ex : 0666).
Exemple :
int fd = open("/home/user/fichier.txt", O_RDWR | O_CREAT, 0644);
if (fd == -1) { /* erreur */ }
2. close()
#include <unistd.h>
int close(int fd);
3. write()
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
Écrit count octets depuis buf dans le fichier référencé par fd. Retourne le nombre d'octets écrits, ou -1 en cas d'erreur.
4. read()
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
Lit au plus count octets depuis fd et les stocke dans buf. Retourne le nombre d'octets lus (0 si fin de fichier), -1 en cas d'erreur.
Paramètres de main()
int main(int argc, char *argv[])
{
return 0;
}
argc = nombre d'arguments (le nom du programme compte), argv = tableau de chaînes (argv[0] = nom du programme, argv[1] = premier arguement, etc.).
Exemple : implémentation simplifiée de la commande cp
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Usage: %s source dest\n", argv[0]);
return -1;
}
int fd_src = open(argv[1], O_RDONLY);
if (fd_src == -1) { perror("source"); return -2; }
int fd_dest = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd_dest == -1) { perror("dest"); close(fd_src); return -3; }
char buffer[128];
ssize_t bytes;
while ((bytes = read(fd_src, buffer, sizeof(buffer))) > 0) {
write(fd_dest, buffer, bytes);
}
close(fd_src);
close(fd_dest);
return 0;
}
5. lseek()
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
whence : SEEK_SET (début), SEEK_CUR (position actuelle), SEEK_END (fin). Retourne la nouvelle position (en octets depuis le début) ou -1 en cas d'erreur.
E/S fichier (file I/O) vs E/S standard (stdio)
| Caractéristique | File I/O (appels système) | Standard I/O (bibliothèque C) |
|---|---|---|
| Interface | open, read, write, close, lseek | fopen, fread, fwrite, fclose, fseek |
| En-tête | <unistd.h>, <fcntl.h> |
<stdio.h> |
| Bufferisation | Pas de buffer utilisateur (buffer noyau) | Buffer utilisateur (ligne, bloc, ou aucun) |
| Portabilité | Dépend du système | Standard C, portable |
| Performances | Moins d'overhead mais plus d'appels système | Moins d'appels système grâce au buffer |
Types de bufferisaiton (stdio)
- Sans buffer : les données sont écrites immédiatement (ex : stderr).
- Buffer de ligne : les données sont écrites quand un '\n' apparaît ou quand le buffer est plein (ex : stdin/stdout avec un terminal).
- Buffer complet : les données sont écrites quand le buffer est plein (ex : fichier disque).
Exemple illustrant le buffer (stdio)
#include <stdio.h>
int main() {
printf("Hello Linux");
while(1); // boucle infinie, le texte n'apparaît pas car pas de '\n' ni fflush
return 0;
}
Fonctions stdio
6. fopen()
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
Mode : "r", "r+", "w", "w+", "a", "a+", "rb", "wb", etc. Retourne un pointeur FILE* ou NULL en cas d'rereur.
7. fread()
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
Lit nmemb éléments de size octets chacun depuis stream et les place dans ptr. Retourne le nombre d'éléments lus.
8. fwrite()
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
Écrit nmemb éléments de size octets depuis ptr vers stream. Retourne le nombre d'éléments écrits.
9. fseek()
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
Retourne 0 en cas de succès, une valeur non nulle en cas d'erreur. whence : SEEK_SET, SEEK_CUR, SEEK_END.
10. fclose()
#include <stdio.h>
int fclose(FILE *stream);
11. fgets() et fputs()
char *fgets(char *s, int size, FILE *stream);
int fputs(const char *s, FILE *stream);
fgets lit au plus size-1 caractères (inclut le '\n' si présent). fputs écrit la chaîne (sans '\n' ajouté). Contrastes avec gets/puts : gets ne limite pas la taille, puts ajoute un '\n'.
12. fflush()
int fflush(FILE *stream);
Vide le buffer utilisateur vers le noyau.
13. Autres fonctions utiles
rewind(FILE *stream): remet le pointeur au début (équivalent àfseek(fp, 0, SEEK_SET)).ftell(FILE *stream): retourne la position courante (en octets depuis le début) ou -1L en cas d'erreur.fprintf(FILE *stream, const char *format, ...): écrit formaté dans un fichier.sprintf(char *str, const char *format, ...): écrit dans une chaîne.fgetc(FILE *stream): lit un caractère (retourne int, EOF si fin ou erreur).fputc(int c, FILE *stream): écrit un caractère (retourne le caractère écrit ou EOF).feof(FILE *stream): teste si la fin de fichier a été atteinte (non nul si oui).ferror(FILE *stream): teste s'il y a eu une erreur de lecture/écriture.clearerr(FILE *stream): efface les indicateurs de fin de fichier et d'erreur.
Exemple : implémentation de la commande cat avec stdio
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s fichier\n", argv[0]);
return 1;
}
FILE *fp = fopen(argv[1], "r");
if (!fp) {
perror("fopen");
return 2;
}
int ch;
while ((ch = fgetc(fp)) != EOF) {
fputc(ch, stdout);
}
fclose(fp);
return 0;
}
Bibliothèques statiques et dynamiques
Les bibliothèques se trouvent généralement dans /lib et /usr/lib.
Bibliothèque statique (libxxx.a)
Liée lors de la compilation. Avantage : exécutable autonome et rapide. Inconvénient : taille plus importante.
Création :
gcc -c mylib.c -o mylib.o
ar rcs libmylib.a mylib.o
Utilisation :
gcc main.c -o monprog -L. -lmylib
./monprog
-L. indique de chercher dans le répertoire courant, -lmylib référence libmylib.a (sans le préfixe lib ni l'extension).
Bibliothèque dynamique (libxxx.so)
Liée lors de l'exécution. Avantage : exécutable plus petit. Inconvénient : nécessite que la bibliothèque soit présente sur le système.
Création :
gcc -c mylib.c -o mylib.o
gcc -shared -fpic -o libmylib.so mylib.o
Utilisation :
gcc main.c -o monprog -L. -lmylib
Avant d'exécuter, il faut que le système trouve la bibliothèque.
Trois méthodes pour rendre la bibliothèque accessible
-
Copie dans un répertoire standard :
sudo cp libmylib.so /usr/lib/ sudo ldconfig -
Variable d'environnement (temporaire) :
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/chemin/vers/la/bibliothèque" -
Modification de
/etc/ld.so.conf:sudo nano /etc/ld.so.conf # Ajouter la ligne : /chemin/vers/la/bibliothèque sudo ldconfig