Difference between revisions of "ProvaPratica 2013.07.18"
Jump to navigation
Jump to search
Amonaldini (talk | contribs) |
m (Aggiunte soluzioni da altre pagine, uniformato) |
||
(17 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
+ | == Esercizio 1 == | ||
+ | ===Soluzione di Tommaso Ognibene=== | ||
+ | <syntaxhighlight lang="C"> | ||
+ | /* | ||
+ | Prova Pratica di Laboratorio di Sistemi Operativi | ||
+ | 18 luglio 2013 | ||
+ | Esercizio 1 | ||
+ | |||
+ | URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf | ||
+ | |||
+ | @author: Tommaso Ognibene | ||
+ | */ | ||
+ | |||
+ | #include <errno.h> | ||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <string.h> | ||
+ | #include <sys/wait.h> | ||
+ | #include <unistd.h> | ||
+ | |||
+ | // Constants | ||
+ | #define MaxNumArguments 10 | ||
+ | #define MaxLenArguments 50 | ||
+ | #define MaxLenPath 100 | ||
+ | #define MaxLenLine MaxLenArguments * MaxNumArguments | ||
+ | #define MaxLenCommands 500 | ||
+ | |||
+ | // Structure for a process element | ||
+ | typedef struct processElem | ||
+ | { | ||
+ | char CommandLine[MaxLenCommands]; | ||
+ | pid_t Pid; | ||
+ | struct processElem *Next; | ||
+ | } ProcessElem; | ||
+ | |||
+ | // Function prototypes | ||
+ | ProcessElem *appendElement (ProcessElem *tail); | ||
+ | char *findCommand (pid_t pid); | ||
+ | void countTokens (const char *string, const char delimiter, int *count, int *longest); | ||
+ | int tokenize (char *string, char delimiter, char ***tokens, int *count); | ||
+ | void readMultipleLines(void); | ||
+ | void runProcesses (void); | ||
+ | |||
+ | // Global variables | ||
+ | static ProcessElem *ProcessList = NULL; | ||
+ | int ProcessCount = 0; | ||
+ | |||
+ | // Given a PID retrieve the relative command | ||
+ | char *findCommand(pid_t pid) | ||
+ | { | ||
+ | ProcessElem *process; | ||
+ | for(process = ProcessList; process->Pid != pid; process = process->Next); | ||
+ | return (process)? (process->CommandLine) : (NULL); | ||
+ | } | ||
+ | |||
+ | // Create a new element | ||
+ | ProcessElem *appendElement(ProcessElem *tail) | ||
+ | { | ||
+ | ProcessElem *newElem = (ProcessElem *)malloc(sizeof(ProcessElem)); | ||
+ | newElem->Next = NULL; | ||
+ | (tail)? (tail->Next = newElem) : (tail = newElem); | ||
+ | return newElem; | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Count tokens and find the longest one | ||
+ | * Example: | ||
+ | * Input: | ||
+ | * string = "ping -c 4 google.com" | ||
+ | * delimiter = ' ' | ||
+ | * Output: | ||
+ | * count = 4 | ||
+ | * longest = 10 | ||
+ | */ | ||
+ | void countTokens(const char *string, const char delimiter, int *count, int *longest) | ||
+ | { | ||
+ | int iterator, lenght; | ||
+ | lenght = *longest = *count = 0; | ||
+ | |||
+ | // Count the first (n - 1) tokens | ||
+ | for(iterator = 0; string[iterator]; iterator++) | ||
+ | { | ||
+ | if(string[iterator] == delimiter) | ||
+ | { | ||
+ | if(*longest < lenght) | ||
+ | *longest = lenght; | ||
+ | lenght = 0; | ||
+ | (*count)++; | ||
+ | } | ||
+ | lenght++; | ||
+ | } | ||
+ | |||
+ | // Count the last token | ||
+ | if(string[iterator - 1] != delimiter) | ||
+ | { | ||
+ | lenght--; | ||
+ | if(*longest < lenght) | ||
+ | *longest = lenght; | ||
+ | (*count)++; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Tokenize a string accordingly to a given delimiter | ||
+ | * Example: | ||
+ | * Input: | ||
+ | * string = "ping -c 4 google.com" | ||
+ | * delimiter = ' ' | ||
+ | * Output: | ||
+ | * tokens = ["ping", "-c", "4", "google.com"] | ||
+ | * count = 4 | ||
+ | */ | ||
+ | int tokenize(char *string, char delimiter, char ***tokens, int *count) | ||
+ | { | ||
+ | if(!(tokens && string && count)) return 0; | ||
+ | |||
+ | int token, i, j, longest; | ||
+ | *count = longest = 0; | ||
+ | |||
+ | countTokens(string, delimiter, count, &longest); | ||
+ | |||
+ | // Allocate space for array of strings | ||
+ | *tokens = (char **)malloc(*count * sizeof(char *)); | ||
+ | |||
+ | if(!*tokens) | ||
+ | { | ||
+ | perror("malloc()"); | ||
+ | exit(EXIT_FAILURE); | ||
+ | } | ||
+ | |||
+ | // Allocate space for each string in the array and tokenize it | ||
+ | i = 0; | ||
+ | for(token = 0; token < *count; token++) | ||
+ | { | ||
+ | (*tokens)[token] = (char *)malloc(sizeof(char) * (longest + 1)); | ||
+ | |||
+ | j = 0; | ||
+ | while(string[i] != delimiter && string[i]) | ||
+ | { | ||
+ | (*tokens)[token][j] = string[i]; | ||
+ | j++; | ||
+ | i++; | ||
+ | } | ||
+ | |||
+ | // Null-terminated string | ||
+ | (*tokens)[token][j] = (char)0; | ||
+ | i++; | ||
+ | } | ||
+ | |||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | // Read multiple input lines | ||
+ | void readMultipleLines(void) | ||
+ | { | ||
+ | ProcessElem *process = NULL; | ||
+ | char input[MaxLenLine]; | ||
+ | char *iterator; | ||
+ | |||
+ | printf("Enter commands. Press enter on blank line to start them.\n"); | ||
+ | while(1) | ||
+ | { | ||
+ | // Get input string | ||
+ | if(!fgets(input, MaxLenLine, stdin)) | ||
+ | { | ||
+ | perror("fgets()"); | ||
+ | exit(EXIT_FAILURE); | ||
+ | } | ||
+ | |||
+ | // Skip blank lines | ||
+ | for(iterator = input; *iterator == ' '; iterator++); | ||
+ | |||
+ | // Check if enter was pressed on blank line | ||
+ | if(*iterator == '\n') break; | ||
+ | |||
+ | // Append a new input element | ||
+ | if(!(ProcessList)) | ||
+ | process = ProcessList = appendElement(ProcessList); | ||
+ | else | ||
+ | { | ||
+ | process->Next = appendElement(process); | ||
+ | process = process->Next; | ||
+ | } | ||
+ | ProcessCount++; | ||
+ | |||
+ | // Eliminate "\n" from the input string | ||
+ | iterator = strtok(iterator, "\n"); | ||
+ | |||
+ | strcpy(process->CommandLine, iterator); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Run child processes -> | ||
+ | * Print when a child process terminates | ||
+ | */ | ||
+ | void runProcesses(void) | ||
+ | { | ||
+ | pid_t pid; | ||
+ | int status, terminated, count; | ||
+ | char path[MaxLenPath]; | ||
+ | ProcessElem *process = ProcessList; | ||
+ | char **command = NULL; | ||
+ | terminated = count = 0; | ||
+ | |||
+ | // Start processes | ||
+ | while(process) | ||
+ | { | ||
+ | // Tokenize command line | ||
+ | tokenize(process->CommandLine, ' ', &command, &count); | ||
+ | |||
+ | // Create path | ||
+ | snprintf(path, sizeof path, "%s%s", "/bin/", command[0]); | ||
+ | |||
+ | // Create child process | ||
+ | pid = fork(); | ||
+ | |||
+ | // Check PID | ||
+ | switch(pid) | ||
+ | { | ||
+ | // Error | ||
+ | case -1: | ||
+ | perror("fork()"); | ||
+ | exit(EXIT_FAILURE); | ||
+ | // Child process | ||
+ | case 0: | ||
+ | // Execute command | ||
+ | if (execv(path, command) == -1) | ||
+ | { | ||
+ | perror("execv()"); | ||
+ | exit(EXIT_FAILURE); | ||
+ | } | ||
+ | break; | ||
+ | // Parent process | ||
+ | default: | ||
+ | process->Pid = pid; | ||
+ | } | ||
+ | process = process->Next; | ||
+ | } | ||
+ | |||
+ | // Wait processes | ||
+ | do | ||
+ | { | ||
+ | // Check if a child process has terminated | ||
+ | pid = waitpid(-1, &status, WNOHANG); | ||
+ | switch(pid) | ||
+ | { | ||
+ | // Error | ||
+ | case -1: | ||
+ | perror("waitpid()"); | ||
+ | exit(EXIT_FAILURE); | ||
+ | // All child processes are still running | ||
+ | case 0: | ||
+ | break; | ||
+ | // A child process has terminated | ||
+ | default: | ||
+ | terminated++; | ||
+ | printf("Finished #%d: %s\n", terminated, findCommand(pid)); | ||
+ | } | ||
+ | } | ||
+ | while(terminated < ProcessCount); | ||
+ | |||
+ | exit(EXIT_SUCCESS); | ||
+ | } | ||
+ | |||
+ | // Entry point | ||
+ | int main(int argc, char *argv[]) | ||
+ | { | ||
+ | // Get input | ||
+ | readMultipleLines(); | ||
+ | |||
+ | // Set output | ||
+ | runProcesses(); | ||
+ | |||
+ | return EXIT_SUCCESS; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Soluzione di Aula=== | ||
+ | |||
+ | <source lang="C"> | ||
+ | #include < stdio.h > | ||
+ | #include < unistd.h > | ||
+ | |||
+ | #define CHAR 1 | ||
+ | #define SPACE 0 | ||
+ | |||
+ | execs2(char * s, int argc) { | ||
+ | char * argv[argc + 1]; | ||
+ | char * t = s; | ||
+ | int status = SPACE; | ||
+ | argc = 0; | ||
+ | while ( * t) { | ||
+ | switch ( * t) { | ||
+ | case ' ': | ||
+ | case '\t': | ||
+ | case '\n': | ||
+ | case 0: | ||
+ | if (status == CHAR) argc++; * t = 0; | ||
+ | status = SPACE; | ||
+ | break; | ||
+ | default: | ||
+ | if (status == SPACE) printf("%s\n", t); | ||
+ | if (status == SPACE) argv[argc] = t; | ||
+ | status = CHAR; | ||
+ | break; | ||
+ | } | ||
+ | t++; | ||
+ | } | ||
+ | argc++; | ||
+ | argv[argc] = 0; | ||
+ | int i; | ||
+ | for (i = 0; i < argc + 1; i++) | ||
+ | printf("%d %p\n", i, argv[i]); | ||
+ | execvp(argv[0], argv); | ||
+ | } | ||
+ | |||
+ | execs(char * s) { | ||
+ | char * t = s - 1; | ||
+ | int argc = 0; | ||
+ | int status = SPACE; | ||
+ | do { | ||
+ | t++; | ||
+ | switch ( * t) { | ||
+ | case ' ': | ||
+ | case '\t': | ||
+ | case '\n': | ||
+ | case 0: | ||
+ | if (status == CHAR) argc++; | ||
+ | status = SPACE; | ||
+ | break; | ||
+ | default: | ||
+ | status = CHAR; | ||
+ | break; | ||
+ | } | ||
+ | } while ( * t); | ||
+ | execs2(s, argc); | ||
+ | } | ||
+ | |||
+ | int main(int argc, char * argv[]) { | ||
+ | char buf[1024]; | ||
+ | fgets(buf, 1024, stdin); | ||
+ | execs(buf); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | === Soluzione di Federico Giuggioloni === | ||
+ | |||
+ | <source lang="c"> | ||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <string.h> | ||
+ | #include <unistd.h> | ||
+ | #include <errno.h> | ||
+ | #include <sys/types.h> | ||
+ | #include <poll.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | struct list_el | ||
+ | { | ||
+ | pid_t pid; | ||
+ | char* comando; | ||
+ | struct list_el* next; | ||
+ | }; | ||
+ | |||
+ | void insert_el(struct list_el** head, char* command, pid_t id) | ||
+ | { | ||
+ | struct list_el *new_el = malloc(sizeof(struct list_el)); | ||
+ | new_el->comando = malloc(sizeof(char) * strlen(command) + 1); | ||
+ | strcpy(new_el->comando, command); | ||
+ | new_el->next = NULL; | ||
+ | new_el->pid = id; | ||
+ | |||
+ | |||
+ | if(*head == NULL) | ||
+ | { | ||
+ | *head = new_el; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | struct list_el* tmp = (*head)->next; | ||
+ | (*head)->next = new_el; | ||
+ | new_el->next = tmp; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | int strspl(char*** split, char* string, const char* delim) | ||
+ | { | ||
+ | char* result; | ||
+ | char* parsed = malloc(strlen(string)+1); | ||
+ | char* tofree = parsed; | ||
+ | int size = 2; | ||
+ | |||
+ | char* ptr = string; | ||
+ | while(*ptr != 0) | ||
+ | { | ||
+ | if(*ptr == *delim) size++; | ||
+ | ptr++; | ||
+ | } | ||
+ | |||
+ | if(*split == NULL) | ||
+ | { | ||
+ | *split = malloc(sizeof(char*) * size); | ||
+ | } | ||
+ | |||
+ | strcpy(parsed, string); | ||
+ | |||
+ | int i = 0; | ||
+ | while((result = strtok(parsed, delim)) != NULL) | ||
+ | { | ||
+ | //subsequent calls to strtok must have NULL in the first | ||
+ | //parameter | ||
+ | parsed = NULL; | ||
+ | |||
+ | //(*split)[i] = result; | ||
+ | (*split)[i] = malloc(strlen(result) * sizeof(char) + 1); | ||
+ | strcpy((*split)[i], result); | ||
+ | |||
+ | i++; | ||
+ | } | ||
+ | |||
+ | (*split)[i] = (char*) 0; | ||
+ | |||
+ | free(tofree); | ||
+ | return i; | ||
+ | } | ||
+ | |||
+ | struct list_el* head = NULL; | ||
+ | |||
+ | char* printNamePid(pid_t pid) | ||
+ | { | ||
+ | struct list_el* p = head; | ||
+ | while(p != NULL) | ||
+ | { | ||
+ | if(p->pid == pid) return p->comando; | ||
+ | p = p->next; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | int main(int argc, char* argv[]) | ||
+ | { | ||
+ | int n; | ||
+ | char *string; | ||
+ | string = NULL;//malloc(MAX_BUFF * sizeof(char)); | ||
+ | int bytes_read; | ||
+ | pid_t pid; | ||
+ | char** splitargs = NULL; | ||
+ | char delim = ' '; | ||
+ | int nFork = 0; | ||
+ | int err; | ||
+ | int pipe_read = 0; | ||
+ | char pipe_char = ' '; | ||
+ | |||
+ | int pipefd[2]; | ||
+ | pipe(pipefd); | ||
+ | |||
+ | struct pollfd pipe_read_poll; | ||
+ | pipe_read_poll.fd = pipefd[0]; | ||
+ | pipe_read_poll.events = POLLIN; | ||
+ | |||
+ | while((bytes_read = getline(&string, &n, stdin)) != 0) | ||
+ | { | ||
+ | if(strcmp(string, "\n") == 0) break; | ||
+ | |||
+ | string[strlen(string)-1] = 0; | ||
+ | strspl(&splitargs, string, &delim); | ||
+ | |||
+ | pid = fork(); | ||
+ | switch(pid) | ||
+ | { | ||
+ | case -1: | ||
+ | printf("Error fork: %s (%d)", strerror(errno), errno); | ||
+ | exit(2); | ||
+ | break; | ||
+ | case 0: | ||
+ | //pipe_read = read(pipefd[0], &pipe_read, 1); | ||
+ | poll(&pipe_read_poll, 1, -1); | ||
+ | err = execvp(splitargs[0], splitargs); | ||
+ | if(err < 0) | ||
+ | { | ||
+ | printf("Error exec: %s (%d)", strerror(errno), errno); | ||
+ | exit(1); | ||
+ | } | ||
+ | exit(0); | ||
+ | break; | ||
+ | default: //PADRE, continua pure | ||
+ | nFork++; | ||
+ | insert_el(&head, string, pid); | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | |||
+ | //free(splitargs); //TODO anche di tutte le stringhe all'interno | ||
+ | splitargs = NULL; | ||
+ | } | ||
+ | |||
+ | int status = 0; | ||
+ | char buf = 'g'; | ||
+ | char* comando = NULL; | ||
+ | int ordineArrivo[nFork]; | ||
+ | int i = 0; | ||
+ | |||
+ | write(pipefd[1], &buf, 1); | ||
+ | |||
+ | while(i < nFork) | ||
+ | { | ||
+ | pid = wait(&status); | ||
+ | ordineArrivo[i] = pid; | ||
+ | i++; | ||
+ | } | ||
+ | |||
+ | printf("\n\n"); | ||
+ | for(i = 0; i < nFork; i++) | ||
+ | { | ||
+ | comando = printNamePid(ordineArrivo[i]); | ||
+ | printf("%d : %s Terminated\n", i, comando); | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | ===Soluzione di Claudio Kerov === | ||
+ | Questa è la versione dell'esercizio 1 senza sincronizzazione della partenza dei processi. | ||
+ | |||
+ | <source lang="c"> | ||
+ | |||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <unistd.h> | ||
+ | #include <sys/types.h> | ||
+ | #include <sys/wait.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | |||
+ | struct lista{ | ||
+ | struct lista *next; | ||
+ | char* stringa; | ||
+ | }; | ||
+ | |||
+ | void leggiArgomenti(char* comando) //prendo il comando dalla stringa, la divido in programma e argomenti, poi la eseguo | ||
+ | { | ||
+ | char* temp; | ||
+ | char delim= ' '; | ||
+ | char* args[64]; //alla fine uso questo | ||
+ | char** next = args; //ma questo e' quello che riempio | ||
+ | temp= strtok(comando, &delim ); | ||
+ | |||
+ | while (temp != NULL) | ||
+ | { | ||
+ | *next++ = temp; | ||
+ | temp = strtok(NULL, &delim); | ||
+ | } | ||
+ | *next = NULL; | ||
+ | execvp(args[0], args); | ||
+ | } | ||
+ | |||
+ | void ins(struct lista *l, char* comando) | ||
+ | { | ||
+ | struct lista *tmp = malloc(sizeof(struct lista)); | ||
+ | tmp->stringa = malloc(sizeof(char)*strlen(comando)+1); | ||
+ | tmp->next= l->next; | ||
+ | strcpy(tmp->stringa, comando); | ||
+ | l->next = tmp; | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | int main (int argc, char *argv[]) | ||
+ | { | ||
+ | |||
+ | size_t n; | ||
+ | int status = 0; | ||
+ | char *riga= (char*)malloc(sizeof(char)); | ||
+ | struct lista *lista_arrivi=(struct lista*) malloc(sizeof(struct lista)); | ||
+ | struct lista *tmp = lista_arrivi; | ||
+ | lista_arrivi->next = NULL; | ||
+ | |||
+ | while( (getline(&riga, &n, stdin)!=0)) | ||
+ | { | ||
+ | if (strcmp(riga, "\n")==0) | ||
+ | break; | ||
+ | |||
+ | ins(lista_arrivi, riga); | ||
+ | counter++; | ||
+ | |||
+ | } | ||
+ | |||
+ | while(lista_arrivi!=NULL) | ||
+ | { | ||
+ | pid_t pid = fork(); | ||
+ | switch(pid) | ||
+ | { | ||
+ | case -1: exit(2); | ||
+ | break; | ||
+ | case 0: //processo figlio che prende in input i comandi | ||
+ | |||
+ | leggiArgomenti(lista_arrivi->stringa); | ||
+ | break; | ||
+ | default: //processo padre che stampera' la lista | ||
+ | lista_arrivi= lista_arrivi->next; | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | tmp = tmp->next; | ||
+ | |||
+ | while(tmp!=NULL) | ||
+ | { | ||
+ | wait(&status); | ||
+ | printf("Terminato: %s\n", tmp->stringa); | ||
+ | tmp= tmp->next; | ||
+ | } | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | </source> | ||
+ | == Esercizio 3 == | ||
+ | |||
+ | ===Soluzione di Tommaso Ognibene=== | ||
[Python 3] | [Python 3] | ||
Line 51: | Line 673: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | ===Soluzione di Fede=== | ||
− | |||
− | |||
− | |||
<syntaxhighlight lang="Python"> | <syntaxhighlight lang="Python"> | ||
Line 83: | Line 703: | ||
print("Invalid Directory!") | print("Invalid Directory!") | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | ||
+ | ===Altra soluzione di Tommaso Ognibene=== | ||
Leggendo la tua versione ho pensato che in effetti se i file sono """pochi""" l'hash-table non e' necessaria. E' sufficiente un controllo iterativo. | Leggendo la tua versione ho pensato che in effetti se i file sono """pochi""" l'hash-table non e' necessaria. E' sufficiente un controllo iterativo. | ||
Line 140: | Line 761: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | ===Soluzione di Fede in bash === | ||
− | |||
− | |||
− | |||
Ecco la mia versione in bash | Ecco la mia versione in bash | ||
Line 171: | Line 790: | ||
BornAgainFede "$1" "$2" | BornAgainFede "$1" "$2" | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | ==Osservazioni== | + | ===Versione by Daniele Cortesi=== |
+ | <syntaxhighlight lang="Python"> | ||
+ | |||
+ | from sys import argv | ||
+ | import os | ||
+ | |||
+ | #controllo se il programma e' stato chiamato correttamente | ||
+ | if len(argv)<3: | ||
+ | print "uso: programma cartella1 cartella2" | ||
+ | exit(1) | ||
+ | |||
+ | dir1=argv[1] | ||
+ | dir2=argv[2] | ||
+ | |||
+ | #controllo che gli argomenti siano effettivamente cartelle | ||
+ | if not os.path.isdir(dir1) or not os.path.isdir(dir2): | ||
+ | print "cartelle non valide" | ||
+ | exit(1) | ||
+ | |||
+ | cartelle=[os.getcwd()+"/"+dir1] #lista che conterra' mano a mano tutte le sottocartelle | ||
+ | files={} #dizionario con nomefile: [lista con tutti i file che si chiamano "nomefile"] | ||
+ | |||
+ | while len(cartelle)>0: | ||
+ | c=cartelle.pop() | ||
+ | for f in os.listdir(c): #analizzo tutti i file nella cartella c | ||
+ | #se f non e' una cartella, allora lo inserisco nel dizionario se non c'e', altrimenti aggiungo il suo percorso alla lista | ||
+ | if not os.path.isdir(c+"/"+f): | ||
+ | if not files.has_key(f): | ||
+ | files[f]=[c+"/"+f] | ||
+ | else: files[f].append(c+"/"+f) | ||
+ | #se f invece e' una cartella, la aggiungo alla lista cosi' alla prossima iterazione (o dopo in caso di piu' cartelle) verra' analizzata | ||
+ | else: cartelle.append(c+"/"+f) | ||
+ | |||
+ | #creo i link simbolici | ||
+ | for k in files.keys(): | ||
+ | for i,f in enumerate(files[k]): | ||
+ | link=k | ||
+ | if (i>0): link+=str(i) | ||
+ | os.symlink(f, dir2+"/"+link) | ||
+ | |||
+ | exit(0) | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Osservazioni di Amonaldini=== | ||
Per prima cosa, bel lavoro!<br/> | Per prima cosa, bel lavoro!<br/> | ||
Di seguito riporto alcune osservazioni che mi sono venute in mente, prendetele assolutamente con soli fini "costruttivi"! | Di seguito riporto alcune osservazioni che mi sono venute in mente, prendetele assolutamente con soli fini "costruttivi"! | ||
− | * Se non sbaglio, i due programmi (quello di Tommaso e quello di Fede) hanno un comportamento diverso per quanto concerne l'interpretazione del nome file e, in particolare, | + | * Se non sbaglio, i due programmi (quello di Tommaso e quello di Fede) hanno un comportamento diverso per quanto concerne l'interpretazione del nome file e, in particolare, dell'estensione: |
** Per Tommaso: | ** Per Tommaso: | ||
*** dir1/example.pdf --> example | *** dir1/example.pdf --> example | ||
Line 186: | Line 848: | ||
*** dir1/dirX/example.pdf --> example.pdf1 | *** dir1/dirX/example.pdf --> example.pdf1 | ||
** interpretando in modo "stringente" del testo dell'esercizio avrei ipotizzato un comportamento come quello di Fede. | ** interpretando in modo "stringente" del testo dell'esercizio avrei ipotizzato un comportamento come quello di Fede. | ||
− | * Nel codice sorgente c'è in generale poco "commento". Commentare il codice è essenziale: permette ad altri di capire immediatamente le scelte implementative fatte e permette a voi di capire al volo il perché di queste scelte nel caso dobbiate riprendere in mano il vostro codice dopo un po' di tempo. | + | * Nel codice sorgente c'è in generale poco "commento". Commentare il codice è essenziale: permette ad altri di capire immediatamente le scelte implementative fatte e permette a voi di capire al volo il perché di queste scelte nel caso dobbiate riprendere in mano il vostro codice dopo un po' di tempo. Quindi: commentate!!! |
+ | * Bash si presta molto all'esercizio | ||
+ | |||
+ | ===Soluzione di fede&pirata=== | ||
+ | |||
+ | <syntaxhighlight lang="C"> | ||
+ | /* | ||
+ | ESERCIZIO 3. | ||
+ | */ | ||
+ | #include<unistd.h> | ||
+ | #include<stdio.h> | ||
+ | #include<stdlib.h> | ||
+ | #include<string.h> | ||
+ | #include<dirent.h> | ||
+ | #include <sys/types.h> | ||
+ | #include <sys/stat.h> | ||
+ | |||
+ | void collectandlink(char *arg1, char *carg2) | ||
+ | { | ||
+ | struct dirent **namelist; | ||
+ | int n; | ||
+ | n = scandir( arg1 , &namelist, 0, alphasort); | ||
+ | |||
+ | if (n < 0) | ||
+ | perror("scandir"); | ||
+ | else | ||
+ | { | ||
+ | while(n--) | ||
+ | { | ||
+ | int i; | ||
+ | char* istr; | ||
+ | int datest; | ||
+ | char *pathnametmp; | ||
+ | char *pathwithname=(char *)malloc(512); | ||
+ | char *pathwithname2=(char *)malloc(512); | ||
+ | strcpy(pathwithname,arg1); | ||
+ | strcpy(pathwithname2,carg2); | ||
+ | strcat(pathwithname,"/"); | ||
+ | strcat(pathwithname2,"/"); | ||
+ | strcat(pathwithname,namelist[n]->d_name); | ||
+ | strcat(pathwithname2,namelist[n]->d_name); | ||
+ | struct stat s; | ||
+ | if( stat(pathwithname,&s) == 0 ) | ||
+ | { | ||
+ | if( s.st_mode & S_IFDIR ) //è un dir | ||
+ | { | ||
+ | if ( strcmp( namelist[n]->d_name , ".." ) == 0 )//si deve escludere ".." | ||
+ | { | ||
+ | continue; | ||
+ | } | ||
+ | if( strcmp( namelist[n]->d_name , "." ) == 0 )//si deve escludere "." | ||
+ | { | ||
+ | continue; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | collectandlink(pathwithname,carg2); | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | if( s.st_mode & S_IFREG ) //è un file | ||
+ | { | ||
+ | datest=symlink(pathwithname,pathwithname2);//torna 0 al successo -1 altrimenti | ||
+ | if(datest==-1) //se simlink fallisce => link esiste | ||
+ | { | ||
+ | i=1; | ||
+ | while(datest!=0)//finchè simlink non ha successo | ||
+ | { | ||
+ | istr=(char *)malloc(32); | ||
+ | pathnametmp=(char *)malloc(544); | ||
+ | strcpy(pathnametmp,pathwithname2); | ||
+ | sprintf(istr, "%d", i); | ||
+ | strcat(pathnametmp,istr); | ||
+ | datest=symlink(pathwithname,pathnametmp); | ||
+ | free(istr); | ||
+ | free(pathnametmp); | ||
+ | i=i+1; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | free(pathwithname); | ||
+ | free(pathwithname2); | ||
+ | } | ||
+ | } | ||
+ | free(namelist); | ||
+ | } | ||
+ | |||
+ | int main(int argc, char *argv[]){ | ||
+ | collectandlink(argv[1],argv[2]); | ||
+ | return 1; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Soluzione di Krusty=== | ||
+ | <source lang="python"> | ||
+ | import os, sys | ||
+ | from stat import * | ||
+ | |||
+ | exist={} | ||
+ | |||
+ | def Scan(pathname): | ||
+ | |||
+ | for f in os.listdir(pathname): | ||
+ | path = os.path.join(pathname,f) | ||
+ | s = os.stat(path) | ||
+ | if S_ISREG(s.st_mode): | ||
+ | if f not in exist: | ||
+ | exist[f] = 1 | ||
+ | os.symlink(path,f) | ||
+ | else: | ||
+ | n = exist[f] | ||
+ | exist[f] = exist[f] + 1 | ||
+ | os.symlink(path,(f+str(n))) | ||
+ | |||
+ | elif S_ISDIR(s.st_mode): | ||
+ | Scan(path) | ||
+ | |||
+ | #main | ||
+ | |||
+ | if not os.path.isdir(sys.argv[2]): | ||
+ | os.makedirs(sys.argv[2]) | ||
+ | |||
+ | os.chdir(sys.argv[2]) | ||
+ | Scan(sys.argv[1]) | ||
+ | |||
+ | </source> | ||
+ | |||
+ | int main(int argc, char * argv[]) { | ||
+ | char buf[1024]; | ||
+ | fgets(buf, 1024, stdin); | ||
+ | execs(buf); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | ===Soluzione di MV=== | ||
+ | <source lang="bash"> | ||
+ | #! /bin/bash | ||
+ | |||
+ | if (( $# != 2 )) | ||
+ | then | ||
+ | echo "Usage: nameindex dir1 dir2" | ||
+ | exit 1 | ||
+ | fi | ||
+ | |||
+ | if [[ $1 = /* ]] # verifico se $1 è un path assoluto o relativo (è necessario assoluto per i link) | ||
+ | then | ||
+ | dir1=$1 | ||
+ | else | ||
+ | dir1=`pwd`/$1 | ||
+ | fi | ||
+ | |||
+ | for i in `find $dir` # scandisco l'albero | ||
+ | do | ||
+ | if [ -f $i ] | ||
+ | then | ||
+ | filename=`basename $i` # ricavo il nome del file senza percorso | ||
+ | |||
+ | if [ ! -f $2/$filename ] # se è il primo file trovato con quel nome | ||
+ | then # creo il link con lo stesso nome | ||
+ | ln -s $dir1/$i $2/$filename | ||
+ | else # altrimento cerco il primo numero n>0 non ancora usato come suffisso | ||
+ | n=1 | ||
+ | while [ -f $2/${filename}${n} ] | ||
+ | do | ||
+ | (( n=$n+1 )) | ||
+ | done | ||
+ | ln -s $dir1/$i $2/$filename$n | ||
+ | fi | ||
+ | fi | ||
+ | done | ||
+ | </source> |
Latest revision as of 12:21, 9 May 2017
Esercizio 1
Soluzione di Tommaso Ognibene
/*
Prova Pratica di Laboratorio di Sistemi Operativi
18 luglio 2013
Esercizio 1
URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf
@author: Tommaso Ognibene
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
// Constants
#define MaxNumArguments 10
#define MaxLenArguments 50
#define MaxLenPath 100
#define MaxLenLine MaxLenArguments * MaxNumArguments
#define MaxLenCommands 500
// Structure for a process element
typedef struct processElem
{
char CommandLine[MaxLenCommands];
pid_t Pid;
struct processElem *Next;
} ProcessElem;
// Function prototypes
ProcessElem *appendElement (ProcessElem *tail);
char *findCommand (pid_t pid);
void countTokens (const char *string, const char delimiter, int *count, int *longest);
int tokenize (char *string, char delimiter, char ***tokens, int *count);
void readMultipleLines(void);
void runProcesses (void);
// Global variables
static ProcessElem *ProcessList = NULL;
int ProcessCount = 0;
// Given a PID retrieve the relative command
char *findCommand(pid_t pid)
{
ProcessElem *process;
for(process = ProcessList; process->Pid != pid; process = process->Next);
return (process)? (process->CommandLine) : (NULL);
}
// Create a new element
ProcessElem *appendElement(ProcessElem *tail)
{
ProcessElem *newElem = (ProcessElem *)malloc(sizeof(ProcessElem));
newElem->Next = NULL;
(tail)? (tail->Next = newElem) : (tail = newElem);
return newElem;
}
/*
* Count tokens and find the longest one
* Example:
* Input:
* string = "ping -c 4 google.com"
* delimiter = ' '
* Output:
* count = 4
* longest = 10
*/
void countTokens(const char *string, const char delimiter, int *count, int *longest)
{
int iterator, lenght;
lenght = *longest = *count = 0;
// Count the first (n - 1) tokens
for(iterator = 0; string[iterator]; iterator++)
{
if(string[iterator] == delimiter)
{
if(*longest < lenght)
*longest = lenght;
lenght = 0;
(*count)++;
}
lenght++;
}
// Count the last token
if(string[iterator - 1] != delimiter)
{
lenght--;
if(*longest < lenght)
*longest = lenght;
(*count)++;
}
}
/*
* Tokenize a string accordingly to a given delimiter
* Example:
* Input:
* string = "ping -c 4 google.com"
* delimiter = ' '
* Output:
* tokens = ["ping", "-c", "4", "google.com"]
* count = 4
*/
int tokenize(char *string, char delimiter, char ***tokens, int *count)
{
if(!(tokens && string && count)) return 0;
int token, i, j, longest;
*count = longest = 0;
countTokens(string, delimiter, count, &longest);
// Allocate space for array of strings
*tokens = (char **)malloc(*count * sizeof(char *));
if(!*tokens)
{
perror("malloc()");
exit(EXIT_FAILURE);
}
// Allocate space for each string in the array and tokenize it
i = 0;
for(token = 0; token < *count; token++)
{
(*tokens)[token] = (char *)malloc(sizeof(char) * (longest + 1));
j = 0;
while(string[i] != delimiter && string[i])
{
(*tokens)[token][j] = string[i];
j++;
i++;
}
// Null-terminated string
(*tokens)[token][j] = (char)0;
i++;
}
return 1;
}
// Read multiple input lines
void readMultipleLines(void)
{
ProcessElem *process = NULL;
char input[MaxLenLine];
char *iterator;
printf("Enter commands. Press enter on blank line to start them.\n");
while(1)
{
// Get input string
if(!fgets(input, MaxLenLine, stdin))
{
perror("fgets()");
exit(EXIT_FAILURE);
}
// Skip blank lines
for(iterator = input; *iterator == ' '; iterator++);
// Check if enter was pressed on blank line
if(*iterator == '\n') break;
// Append a new input element
if(!(ProcessList))
process = ProcessList = appendElement(ProcessList);
else
{
process->Next = appendElement(process);
process = process->Next;
}
ProcessCount++;
// Eliminate "\n" from the input string
iterator = strtok(iterator, "\n");
strcpy(process->CommandLine, iterator);
}
}
/*
* Run child processes ->
* Print when a child process terminates
*/
void runProcesses(void)
{
pid_t pid;
int status, terminated, count;
char path[MaxLenPath];
ProcessElem *process = ProcessList;
char **command = NULL;
terminated = count = 0;
// Start processes
while(process)
{
// Tokenize command line
tokenize(process->CommandLine, ' ', &command, &count);
// Create path
snprintf(path, sizeof path, "%s%s", "/bin/", command[0]);
// Create child process
pid = fork();
// Check PID
switch(pid)
{
// Error
case -1:
perror("fork()");
exit(EXIT_FAILURE);
// Child process
case 0:
// Execute command
if (execv(path, command) == -1)
{
perror("execv()");
exit(EXIT_FAILURE);
}
break;
// Parent process
default:
process->Pid = pid;
}
process = process->Next;
}
// Wait processes
do
{
// Check if a child process has terminated
pid = waitpid(-1, &status, WNOHANG);
switch(pid)
{
// Error
case -1:
perror("waitpid()");
exit(EXIT_FAILURE);
// All child processes are still running
case 0:
break;
// A child process has terminated
default:
terminated++;
printf("Finished #%d: %s\n", terminated, findCommand(pid));
}
}
while(terminated < ProcessCount);
exit(EXIT_SUCCESS);
}
// Entry point
int main(int argc, char *argv[])
{
// Get input
readMultipleLines();
// Set output
runProcesses();
return EXIT_SUCCESS;
}
Soluzione di Aula
#include < stdio.h >
#include < unistd.h >
#define CHAR 1
#define SPACE 0
execs2(char * s, int argc) {
char * argv[argc + 1];
char * t = s;
int status = SPACE;
argc = 0;
while ( * t) {
switch ( * t) {
case ' ':
case '\t':
case '\n':
case 0:
if (status == CHAR) argc++; * t = 0;
status = SPACE;
break;
default:
if (status == SPACE) printf("%s\n", t);
if (status == SPACE) argv[argc] = t;
status = CHAR;
break;
}
t++;
}
argc++;
argv[argc] = 0;
int i;
for (i = 0; i < argc + 1; i++)
printf("%d %p\n", i, argv[i]);
execvp(argv[0], argv);
}
execs(char * s) {
char * t = s - 1;
int argc = 0;
int status = SPACE;
do {
t++;
switch ( * t) {
case ' ':
case '\t':
case '\n':
case 0:
if (status == CHAR) argc++;
status = SPACE;
break;
default:
status = CHAR;
break;
}
} while ( * t);
execs2(s, argc);
}
int main(int argc, char * argv[]) {
char buf[1024];
fgets(buf, 1024, stdin);
execs(buf);
}
Soluzione di Federico Giuggioloni
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <poll.h>
#include <string.h>
struct list_el
{
pid_t pid;
char* comando;
struct list_el* next;
};
void insert_el(struct list_el** head, char* command, pid_t id)
{
struct list_el *new_el = malloc(sizeof(struct list_el));
new_el->comando = malloc(sizeof(char) * strlen(command) + 1);
strcpy(new_el->comando, command);
new_el->next = NULL;
new_el->pid = id;
if(*head == NULL)
{
*head = new_el;
}
else
{
struct list_el* tmp = (*head)->next;
(*head)->next = new_el;
new_el->next = tmp;
}
}
int strspl(char*** split, char* string, const char* delim)
{
char* result;
char* parsed = malloc(strlen(string)+1);
char* tofree = parsed;
int size = 2;
char* ptr = string;
while(*ptr != 0)
{
if(*ptr == *delim) size++;
ptr++;
}
if(*split == NULL)
{
*split = malloc(sizeof(char*) * size);
}
strcpy(parsed, string);
int i = 0;
while((result = strtok(parsed, delim)) != NULL)
{
//subsequent calls to strtok must have NULL in the first
//parameter
parsed = NULL;
//(*split)[i] = result;
(*split)[i] = malloc(strlen(result) * sizeof(char) + 1);
strcpy((*split)[i], result);
i++;
}
(*split)[i] = (char*) 0;
free(tofree);
return i;
}
struct list_el* head = NULL;
char* printNamePid(pid_t pid)
{
struct list_el* p = head;
while(p != NULL)
{
if(p->pid == pid) return p->comando;
p = p->next;
}
}
int main(int argc, char* argv[])
{
int n;
char *string;
string = NULL;//malloc(MAX_BUFF * sizeof(char));
int bytes_read;
pid_t pid;
char** splitargs = NULL;
char delim = ' ';
int nFork = 0;
int err;
int pipe_read = 0;
char pipe_char = ' ';
int pipefd[2];
pipe(pipefd);
struct pollfd pipe_read_poll;
pipe_read_poll.fd = pipefd[0];
pipe_read_poll.events = POLLIN;
while((bytes_read = getline(&string, &n, stdin)) != 0)
{
if(strcmp(string, "\n") == 0) break;
string[strlen(string)-1] = 0;
strspl(&splitargs, string, &delim);
pid = fork();
switch(pid)
{
case -1:
printf("Error fork: %s (%d)", strerror(errno), errno);
exit(2);
break;
case 0:
//pipe_read = read(pipefd[0], &pipe_read, 1);
poll(&pipe_read_poll, 1, -1);
err = execvp(splitargs[0], splitargs);
if(err < 0)
{
printf("Error exec: %s (%d)", strerror(errno), errno);
exit(1);
}
exit(0);
break;
default: //PADRE, continua pure
nFork++;
insert_el(&head, string, pid);
break;
}
//free(splitargs); //TODO anche di tutte le stringhe all'interno
splitargs = NULL;
}
int status = 0;
char buf = 'g';
char* comando = NULL;
int ordineArrivo[nFork];
int i = 0;
write(pipefd[1], &buf, 1);
while(i < nFork)
{
pid = wait(&status);
ordineArrivo[i] = pid;
i++;
}
printf("\n\n");
for(i = 0; i < nFork; i++)
{
comando = printNamePid(ordineArrivo[i]);
printf("%d : %s Terminated\n", i, comando);
}
return 0;
}
Soluzione di Claudio Kerov
Questa è la versione dell'esercizio 1 senza sincronizzazione della partenza dei processi.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
struct lista{
struct lista *next;
char* stringa;
};
void leggiArgomenti(char* comando) //prendo il comando dalla stringa, la divido in programma e argomenti, poi la eseguo
{
char* temp;
char delim= ' ';
char* args[64]; //alla fine uso questo
char** next = args; //ma questo e' quello che riempio
temp= strtok(comando, &delim );
while (temp != NULL)
{
*next++ = temp;
temp = strtok(NULL, &delim);
}
*next = NULL;
execvp(args[0], args);
}
void ins(struct lista *l, char* comando)
{
struct lista *tmp = malloc(sizeof(struct lista));
tmp->stringa = malloc(sizeof(char)*strlen(comando)+1);
tmp->next= l->next;
strcpy(tmp->stringa, comando);
l->next = tmp;
}
int main (int argc, char *argv[])
{
size_t n;
int status = 0;
char *riga= (char*)malloc(sizeof(char));
struct lista *lista_arrivi=(struct lista*) malloc(sizeof(struct lista));
struct lista *tmp = lista_arrivi;
lista_arrivi->next = NULL;
while( (getline(&riga, &n, stdin)!=0))
{
if (strcmp(riga, "\n")==0)
break;
ins(lista_arrivi, riga);
counter++;
}
while(lista_arrivi!=NULL)
{
pid_t pid = fork();
switch(pid)
{
case -1: exit(2);
break;
case 0: //processo figlio che prende in input i comandi
leggiArgomenti(lista_arrivi->stringa);
break;
default: //processo padre che stampera' la lista
lista_arrivi= lista_arrivi->next;
break;
}
}
tmp = tmp->next;
while(tmp!=NULL)
{
wait(&status);
printf("Terminato: %s\n", tmp->stringa);
tmp= tmp->next;
}
return 0;
}
Esercizio 3
Soluzione di Tommaso Ognibene
[Python 3]
'''
Prova Pratica di Laboratorio di Sistemi Operativi
18 luglio 2013
Esercizio 3
URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf
@author: Tommaso Ognibene
'''
import os, sys
def Main(argv):
# Check number of arguments
if len(argv) != 3:
print("The function requires two arguments to be passed in.")
return
# Check parameters
srcDir = str(argv[1])
dstDir = str(argv[2])
if not os.path.isdir(srcDir):
print("First argument should be an existing directory.")
return
if not os.path.isdir(dstDir):
print("Second argument should be an existing directory.")
return
# Build a dictionary with key-value pair {file base name - occurrences}
nameFreq = { }
for dirPath, dirNames, fileNames in os.walk(srcDir):
for fileName in fileNames:
fileBaseName, _ = os.path.splitext(fileName)
nameFreq[fileBaseName] = nameFreq.get(fileBaseName, -1) + 1
# Create a soft link
freq = nameFreq[fileBaseName]
linkName = "{0}{1}".format(fileBaseName, str(freq) if freq > 0 else "")
srcPath = os.path.join(os.path.abspath(dirPath), fileName)
dstPath = os.path.join(dstDir, linkName)
if not os.path.lexists(dstPath):
os.symlink(srcPath, dstPath)
print("Done!")
if __name__ == "__main__":
sys.exit(Main(sys.argv))
Soluzione di Fede
import os, sys
def collectfiles(arg1,arg2):
fcd = os.listdir('{0}'.format(arg1))
while fcd != []:
B=str(fcd.pop())
C='{0}/{1}'.format(arg1,B)
if os.path.isdir('{0}'.format(C)):
collectfiles(C,arg2)
elif os.path.isfile('{0}'.format(C)):
try:
os.symlink('{0}'.format(C), '{0}/{1}'.format(arg2,B))
except OSError:
i=1
while True:
try:
os.symlink('{0}'.format(C), '{0}/{1}{2}'.format(arg2,B,i))
break
except OSError:
i=i+1
try:
collectfiles(str(sys.argv[1]),str(sys.argv[2]))
except OSError:
print("Invalid Directory!")
Altra soluzione di Tommaso Ognibene
Leggendo la tua versione ho pensato che in effetti se i file sono """pochi""" l'hash-table non e' necessaria. E' sufficiente un controllo iterativo.
'''
Prova Pratica di Laboratorio di Sistemi Operativi
18 luglio 2013
Esercizio 3
URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf
@author: Tommaso Ognibene
'''
import os, sys
def Main(argv):
# Check number of arguments
if len(argv) != 3:
print("The function requires two arguments to be passed in.")
return
# Check parameters
srcDir = str(argv[1])
dstDir = str(argv[2])
if not os.path.isdir(srcDir):
print("First argument should be an existing directory.")
return
if not os.path.isdir(dstDir):
print("Second argument should be an existing directory.")
return
# Traverse the directory tree and create a soft link for each file
for dirPath, _, fileNames in os.walk(srcDir):
for fileName in fileNames:
# 'example.pdf' -> 'example'
# 'example.xml' -> 'example'
fileBaseName, _ = os.path.splitext(fileName)
linkName = fileBaseName
srcPath = os.path.join(os.path.abspath(dirPath), fileName)
dstPath = os.path.join(dstDir, linkName)
i = 0
while os.path.isfile(dstPath):
# 'example' will point to 'example.pdf'
# 'example1' will point to 'example.xml'
i += 1
linkName = fileBaseName + str(i)
dstPath = os.path.join(dstDir, linkName)
if not os.path.lexists(dstPath):
os.symlink(srcPath, dstPath)
print("Done!")
if __name__ == "__main__":
sys.exit(Main(sys.argv))
Soluzione di Fede in bash
Ecco la mia versione in bash
#! /bin/bash
BornAgainFede () {
for f in "$1"/*; do
bn=$(basename "$f")
if [[ -f $f ]] ; then
if [[ -h "$2"/"$bn" ]] ; then
i=1
while [[ -h "$2"/"$bn$i" ]] ; do
let "i += 1"
done
ln -s "$1"/"$bn" "$2"/"$bn$i"
else
ln -s "$1"/"$bn" "$2"/"$bn"
fi
fi
if [[ -d $f ]] ; then
BornAgainFede "$1"/"$bn" "$2"
fi
done
}
BornAgainFede "$1" "$2"
Versione by Daniele Cortesi
from sys import argv
import os
#controllo se il programma e' stato chiamato correttamente
if len(argv)<3:
print "uso: programma cartella1 cartella2"
exit(1)
dir1=argv[1]
dir2=argv[2]
#controllo che gli argomenti siano effettivamente cartelle
if not os.path.isdir(dir1) or not os.path.isdir(dir2):
print "cartelle non valide"
exit(1)
cartelle=[os.getcwd()+"/"+dir1] #lista che conterra' mano a mano tutte le sottocartelle
files={} #dizionario con nomefile: [lista con tutti i file che si chiamano "nomefile"]
while len(cartelle)>0:
c=cartelle.pop()
for f in os.listdir(c): #analizzo tutti i file nella cartella c
#se f non e' una cartella, allora lo inserisco nel dizionario se non c'e', altrimenti aggiungo il suo percorso alla lista
if not os.path.isdir(c+"/"+f):
if not files.has_key(f):
files[f]=[c+"/"+f]
else: files[f].append(c+"/"+f)
#se f invece e' una cartella, la aggiungo alla lista cosi' alla prossima iterazione (o dopo in caso di piu' cartelle) verra' analizzata
else: cartelle.append(c+"/"+f)
#creo i link simbolici
for k in files.keys():
for i,f in enumerate(files[k]):
link=k
if (i>0): link+=str(i)
os.symlink(f, dir2+"/"+link)
exit(0)
Osservazioni di Amonaldini
Per prima cosa, bel lavoro!
Di seguito riporto alcune osservazioni che mi sono venute in mente, prendetele assolutamente con soli fini "costruttivi"!
- Se non sbaglio, i due programmi (quello di Tommaso e quello di Fede) hanno un comportamento diverso per quanto concerne l'interpretazione del nome file e, in particolare, dell'estensione:
- Per Tommaso:
- dir1/example.pdf --> example
- dir1/example.txt --> example1
- dir1/dirX/example.pdf --> example2
- Per Fede:
- dir1/example.pdf --> example.pdf
- dir1/example.txt --> example.txt
- dir1/dirX/example.pdf --> example.pdf1
- interpretando in modo "stringente" del testo dell'esercizio avrei ipotizzato un comportamento come quello di Fede.
- Per Tommaso:
- Nel codice sorgente c'è in generale poco "commento". Commentare il codice è essenziale: permette ad altri di capire immediatamente le scelte implementative fatte e permette a voi di capire al volo il perché di queste scelte nel caso dobbiate riprendere in mano il vostro codice dopo un po' di tempo. Quindi: commentate!!!
- Bash si presta molto all'esercizio
Soluzione di fede&pirata
/*
ESERCIZIO 3.
*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
void collectandlink(char *arg1, char *carg2)
{
struct dirent **namelist;
int n;
n = scandir( arg1 , &namelist, 0, alphasort);
if (n < 0)
perror("scandir");
else
{
while(n--)
{
int i;
char* istr;
int datest;
char *pathnametmp;
char *pathwithname=(char *)malloc(512);
char *pathwithname2=(char *)malloc(512);
strcpy(pathwithname,arg1);
strcpy(pathwithname2,carg2);
strcat(pathwithname,"/");
strcat(pathwithname2,"/");
strcat(pathwithname,namelist[n]->d_name);
strcat(pathwithname2,namelist[n]->d_name);
struct stat s;
if( stat(pathwithname,&s) == 0 )
{
if( s.st_mode & S_IFDIR ) //è un dir
{
if ( strcmp( namelist[n]->d_name , ".." ) == 0 )//si deve escludere ".."
{
continue;
}
if( strcmp( namelist[n]->d_name , "." ) == 0 )//si deve escludere "."
{
continue;
}
else
{
collectandlink(pathwithname,carg2);
}
}
else
{
if( s.st_mode & S_IFREG ) //è un file
{
datest=symlink(pathwithname,pathwithname2);//torna 0 al successo -1 altrimenti
if(datest==-1) //se simlink fallisce => link esiste
{
i=1;
while(datest!=0)//finchè simlink non ha successo
{
istr=(char *)malloc(32);
pathnametmp=(char *)malloc(544);
strcpy(pathnametmp,pathwithname2);
sprintf(istr, "%d", i);
strcat(pathnametmp,istr);
datest=symlink(pathwithname,pathnametmp);
free(istr);
free(pathnametmp);
i=i+1;
}
}
}
}
}
free(pathwithname);
free(pathwithname2);
}
}
free(namelist);
}
int main(int argc, char *argv[]){
collectandlink(argv[1],argv[2]);
return 1;
}
Soluzione di Krusty
import os, sys
from stat import *
exist={}
def Scan(pathname):
for f in os.listdir(pathname):
path = os.path.join(pathname,f)
s = os.stat(path)
if S_ISREG(s.st_mode):
if f not in exist:
exist[f] = 1
os.symlink(path,f)
else:
n = exist[f]
exist[f] = exist[f] + 1
os.symlink(path,(f+str(n)))
elif S_ISDIR(s.st_mode):
Scan(path)
#main
if not os.path.isdir(sys.argv[2]):
os.makedirs(sys.argv[2])
os.chdir(sys.argv[2])
Scan(sys.argv[1])
int main(int argc, char * argv[]) {
char buf[1024]; fgets(buf, 1024, stdin); execs(buf);
} </source>
Soluzione di MV
#! /bin/bash
if (( $# != 2 ))
then
echo "Usage: nameindex dir1 dir2"
exit 1
fi
if [[ $1 = /* ]] # verifico se $1 è un path assoluto o relativo (è necessario assoluto per i link)
then
dir1=$1
else
dir1=`pwd`/$1
fi
for i in `find $dir` # scandisco l'albero
do
if [ -f $i ]
then
filename=`basename $i` # ricavo il nome del file senza percorso
if [ ! -f $2/$filename ] # se è il primo file trovato con quel nome
then # creo il link con lo stesso nome
ln -s $dir1/$i $2/$filename
else # altrimento cerco il primo numero n>0 non ancora usato come suffisso
n=1
while [ -f $2/${filename}${n} ]
do
(( n=$n+1 ))
done
ln -s $dir1/$i $2/$filename$n
fi
fi
done