Difference between revisions of "Prova pratica 2015.01.21"

From Sistemi Operativi
Jump to navigation Jump to search
m (Aggiunte soluzioni da altre pagine, uniformato)
m (Aggiunta soluzione di un'altro studente)
 
Line 57: Line 57:
  
 
--[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF
 
--[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF
 +
 +
===Soluzione di Luca===
 +
<source lang="c">
 +
#include <stdio.h>
 +
#include <unistd.h>
 +
#include <stdlib.h>
 +
#include <fcntl.h>
 +
#include <s2argv.h>
 +
#include <string.h>
 +
 +
int main(int argc, char *argv[]){
 +
int pfd[2];
 +
FILE *file=fopen(argv[1], "r");//apro file in lettura
 +
char cmd1[256];
 +
char cmd2[256];
 +
 +
fgets(cmd1, sizeof(cmd1), file);//memorizzo il primo comando in cmd1
 +
fgets(cmd2, sizeof(cmd2), file);//memorizzo il 2 comando in cmd2
 +
 +
pipe(pfd);//creo i 2 descrittori
 +
 +
switch(fork()){
 +
case 0: //figlio fornisce output
 +
dup2(pfd[1], STDOUT_FILENO);
 +
close(pfd[0]);
 +
close(pfd[1]);
 +
execsp(cmd1);
 +
exit(1);
 +
 +
case -1: exit(1);
 +
}
 +
switch(fork()){//figlio prende input
 +
case 0:
 +
dup2(pfd[0], STDIN_FILENO);
 +
close(pfd[0]);
 +
close(pfd[1]);
 +
execsp(cmd2);
 +
exit(1);
 +
 +
case -1: exit(1);
 +
}
 +
int status;
 +
close(pfd[0]);
 +
close(pfd[1]);
 +
wait(&status);
 +
wait(&status);
 +
fclose(file);
 +
}
 +
</source>
  
 
==Esercizio 2==
 
==Esercizio 2==
Line 430: Line 479:
 
--[[User:Ale|Ale]] ([[User talk:Ale|talk]]) 14:01, 25 May 2015 (CEST)
 
--[[User:Ale|Ale]] ([[User talk:Ale|talk]]) 14:01, 25 May 2015 (CEST)
  
 +
===Soluzione di Luca===
 +
<source lang="c">#include <stdio.h>
 +
#include <stdio.h>
 +
#include <unistd.h>
 +
#include <stdlib.h>
 +
#include <fcntl.h>
 +
#include <s2argv.h>
 +
#include <string.h>
 +
 +
int main(int argc, char *argv[]){
 +
int pfd[2], num_righe=0, tmp=0;
 +
FILE *file=fopen(argv[1], "r");//apro file in lettura
 +
char buff[256];
 +
pipe(pfd);
 +
 +
while(fgets(buff, sizeof(buff), file)!=NULL){//calcolo il numero di righe del file
 +
num_righe++;
 +
}
 +
char comandi[num_righe][256];//array di stringhe
 +
rewind(file);
 +
 +
for(tmp=0; tmp<num_righe; tmp++){
 +
fgets(comandi[tmp], sizeof(comandi[tmp]), file);//copio ogni comando per riga
 +
//printf("comando num %d: %s\n", tmp, comandi[tmp]);
 +
switch(fork()){
 +
case 0:
 +
if(tmp<num_righe-1){
 +
dup2(pfd[1], STDOUT_FILENO);
 +
close(pfd[0]);
 +
close(pfd[1]);
 +
execsp(comandi[tmp]);
 +
exit(1);
 +
}
 +
if(tmp==num_righe-1){
 +
dup2(pfd[0], STDIN_FILENO);
 +
close(pfd[0]);
 +
close(pfd[1]);
 +
execsp(comandi[tmp]);
 +
exit(1);
 +
}
 +
case -1: exit(1);
 +
 +
}
 +
}
 +
int status;
 +
close(pfd[0]);
 +
close(pfd[1]);
 +
for(tmp=0; tmp<num_righe; tmp++)
 +
wait(&status);
 +
fclose(file);
 +
}
 +
</source>
  
 
==Esercizio 3==
 
==Esercizio 3==
Line 572: Line 673:
  
 
'''perch&eacute; proporre una soluzione in un linguaggio che non ho ancora spiegato?'''[[User:Renzo|Renzo]] ([[User talk:Renzo|talk]]) 19:36, 21 November 2016 (CET)
 
'''perch&eacute; proporre una soluzione in un linguaggio che non ho ancora spiegato?'''[[User:Renzo|Renzo]] ([[User talk:Renzo|talk]]) 19:36, 21 November 2016 (CET)
 +
 +
===Soluzione di Luca(Bash)===
 +
<source lang="bash">
 +
#! /bin/bash
 +
trova () {
 +
  find $1 -type f -exec md5sum {} \; | sort > md5.txt #calcola l'md5 di tutto il sottoalbero, lo ordina e lo salva in un file
 +
  cat md5.txt | grep "`cut -d ' ' -f 1 md5.txt | uniq -d`" #stampa le righe del file, nelle quali in primo campo ha valore(md5) duplicato
 +
}
 +
 +
if [[ $# -eq 0 ]] ; then #se num argomenti è 0
 +
  trova
 +
else
 +
  for parametro in $* #chiamo la funzione per ogni argomento
 +
  do
 +
      trova $parametro
 +
  done
 +
fi
 +
exit
 +
</source>

Latest revision as of 08:25, 10 May 2017

Testo: [1]

Esercizio 1

Soluzione di Leonardo F

//ESERCIZIO 1
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "execs.h" // from https://github.com/rd235/s2argv-execs
#define BUFFLEN  4096 //probably there is a system constant

int main(int argc,const char* argv[]){
	//take the path name and open the file
	FILE* fd = fopen(argv[1],"r");
	//read the the file and put its content in a array of pointers
	char commands[2][BUFFLEN]; //migliorabile
	char buffer[BUFFLEN];
	int i = 0;
	while (fgets(buffer,sizeof(buffer),fd) != NULL){
		strcpy(commands[i],buffer);
		i ++;
	}
	//printf("%s\n%s\n",commands[0],commands[1] );
	//create a pipe
	int fpipe[2];
	pipe(fpipe); //0 reading,1 writing
	//fork
	int pid;
	pid = fork();
	switch (pid){
	case 0 : //children
		
		close(fpipe[0]);
		//children's stout = pipe output
		dup2(fpipe[1],STDOUT_FILENO);
		close(fpipe[1]);
		//execution of the command
		execsp(commands[0]);
		
		exit(-1); // in case of execsp failure

	default : //parent
		
		close(fpipe[1]);
		//father's stdin = pipe input
		dup2(fpipe[0],STDIN_FILENO);
		close(fpipe[0]);
		//receive the comnmand
		execsp(commands[1]);
		
		exit(-1);
	}	
}

--LeonardoF (talk) 15:39, 26 March 2017 (CEST)LeonardoF

Soluzione di Luca

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <s2argv.h>
#include <string.h>
 
int main(int argc, char *argv[]){
	int pfd[2];
	FILE *file=fopen(argv[1], "r");//apro file in lettura
	char cmd1[256];
	char cmd2[256];
 
	fgets(cmd1, sizeof(cmd1), file);//memorizzo il primo comando in cmd1
	fgets(cmd2, sizeof(cmd2), file);//memorizzo il 2 comando in cmd2
 
	pipe(pfd);//creo i 2 descrittori
 
	switch(fork()){
		case 0:	//figlio fornisce output
			dup2(pfd[1], STDOUT_FILENO);
			close(pfd[0]);
			close(pfd[1]);
			execsp(cmd1); 
			exit(1);
 
		case -1: exit(1);
	}
	switch(fork()){//figlio prende input
		case 0:	
			dup2(pfd[0], STDIN_FILENO);
			close(pfd[0]);
			close(pfd[1]);
			execsp(cmd2); 
			exit(1);
 
		case -1: exit(1);
	}
	int status;
	close(pfd[0]);
	close(pfd[1]);
	wait(&status);
	wait(&status);
	fclose(file);
}

Esercizio 2

Soluzione di LeonardoF

//ESERCIZIO 2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "execs.h" // from https://github.com/rd235/s2argv-execs
 
#define AOS_LENSTEP 8
 
/*
 * Define a struct for managing and array of pointer to strings.
 */
struct array_of_strings {
    char **strings;
    size_t currentlength; //the length of number of string in memory
    size_t arraylength; //the length of memory allocated
};
 
typedef struct array_of_strings array_of_strings;
 
void array_of_strings_add(array_of_strings *arrayOfStrings, char *string) {
    //if there is not enough space for the string increase it
    if (arrayOfStrings->currentlength >= arrayOfStrings->arraylength) {
        //increase the array length by the size of a string pointer
        size_t newlength = arrayOfStrings->arraylength + AOS_LENSTEP;
        //reallocate the arrayOfString with the new size
        char **new_string = realloc(arrayOfStrings->strings, newlength * sizeof(arrayOfStrings->strings[0]));
        //if the reallocation is successful
        if (new_string != NULL) {
            arrayOfStrings->arraylength = newlength;
            arrayOfStrings->strings = new_string;
        }
    }
    //if there is enough space for the string insert it
    if (arrayOfStrings->currentlength < arrayOfStrings->arraylength)
        //strdup return a pointer to a duplicate of the string
        arrayOfStrings->strings[arrayOfStrings->currentlength++] = strdup(string);
}
 
void array_of_strings_print(array_of_strings *v) {
    size_t i;
    for (i = 0; i < v->currentlength; i++)
        printf("[%3lu]: %s\n", i, v->strings[i]);
}

int main(int argc, char *argv[]) {
	int commandNumber= 0;
    char* line = NULL;
    size_t lineLength = 0;

    ssize_t numberOfCharactersRead;
    static array_of_strings arrayOfStrings;
    FILE* fd = fopen(argv[1],"r");

    while ((numberOfCharactersRead = getline(&line, &lineLength, fd)) >= 0) {
        if (line[numberOfCharactersRead - 1] == '\n')
            line[numberOfCharactersRead - 1] = 0;
        array_of_strings_add(&arrayOfStrings, line);
        commandNumber ++;
    }
 	free(line);
 	//array_of_strings_print(&arrayOfStrings);
 	//printf("%d\n",commandNumber );
 	//open the pipe
 	int fpipe[2];
	pipe(fpipe); //0 reading,1 writing
	int i = 0;

	
 	while(commandNumber > 0 ){
 		if(commandNumber > 1) {
 			int pid = fork();
 			switch(pid){
 				case 0: //children
 						close(fpipe[0]);
						//children's stout = pipe output
						dup2(fpipe[1],STDOUT_FILENO);
						close(fpipe[1]);
						//execution of the command
						//usleep( commandNumber* 1000000);
						execsp(arrayOfStrings.strings[i]);
				
						
 						exit(-1);
 				default: //parent 
 						commandNumber --;
 						i ++;
 						break;
 			}
 		}
 		else{ //last command
 				close(fpipe[1]);
				//father's stdin = pipe input
				dup2(fpipe[0],STDIN_FILENO);
				close(fpipe[0]);
				//receive the comnmand
				execsp(arrayOfStrings.strings[i]);
				
 		}
 	}
    
}

--LeonardoF (talk) 15:39, 26 March 2017 (CEST)LeonardoF

Soluzione di Stefano.zaniboni

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <error.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]){
   int mypipe[2];
   FILE *stream;
   char *line=NULL;
   size_t len=0;
   ssize_t read;

   /*controllo il numero degli argomenti passati*/
   if(argc != 2){
      fprintf(stderr, "no such arguments \n");
      exit(1);
   }

   /*apro il file in sola lettura*/
   stream=fopen(argv[1], "r");
   if(stream==NULL){
      exit(EXIT_FAILURE);
   }

   /*apro la pipe*/
   if(pipe(mypipe) == -1){
      fprintf(stderr, "Error pipe\n");
      exit (1);
   }

   if(fork()==0){
      close(1); /*chiudo lo stdout*/
      dup(mypipe[1]); /*rimpiazzo lo stdout con la pipe*/
      close(mypipe[0]); /*chiudo la read della pipe*/
      close(mypipe[1]);

      read=getline(&line, &len, stream);

      char *lines[2]={line, NULL};
      execvp(argv[1], lines);
      perror("execvp failed");
      exit (1);
   }
   if(fork()==0){
      close(0); /*chiudo lo stdin*/
      dup(mypipe[0]); /*rimpiazzo lo stdin con la pipe read*/
      close(mypipe[1]); /*chiudo la write della pipe*/
      close(mypipe[0]);

      read=getline(&line, &len, stream);
      execvp(argv[1], &line);
      perror("execvp 2 failed");
      exit (1);
   }
   close(mypipe[0]);
   close(mypipe[1]);
   wait(0);
   wait(0);
   free(line);
   fclose(stream);
   exit (0);
}

Il codice ho provato a testarlo ma la shell mi restituisce sempre su entrambe le exec "Permission Denied".

Nota del Prof: execvp(argv[1], &line) tenta di eseguire il file di testo (argv[1]) Renzo (talk) 16:04, 7 April 2015 (CEST)


Soluzione di AleZ

Nota: ho messo la soluzione di questo esercizio solamente perché non ne ho trovata sulla wiki una versione funzionante. Non so se sia stato corretto in classe e/o se sia stato già postato da qualche altra parte. Nel caso mi scuso.

Due versioni: una utilizzando la libreria s2argv e la funzione getline, l'altra senza entrambe.

Versione 1 (con s2argv e getline)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "/home/alessandro/Scrivania/s2argv/s2argv.h"

int main(int argc, char *argv[]) {
	//check arguments
	if (argc != 2) {
		fprintf(stderr, "Error: Expected 1 parameter.\n"
			"Usage: %s <pathname>\n", argv[0]);
		return(EXIT_FAILURE);
	}

	FILE *f;
	size_t n;
	int fd[2];
	char *command = NULL;

	f = fopen(argv[1], "rt");

	//get first command
	getline(&command, &n, f);

	//create the pipe
	if (pipe(fd) == -1) {
		perror("pipe");
		return(EXIT_FAILURE);
	}

	//create child process
	switch (fork()) {
		case -1:
		perror("fork");
		break;

		case 0:	//child process
		close(fd[0]);
		dup2(fd[1], STDOUT_FILENO); //redirect STDOUT to write to fd[1]->fd[0]
		execsp(command);
		return(EXIT_FAILURE);

		default:
		close(fd[1]);
		dup2(fd[0], STDIN_FILENO);	//redirect STDIN to read from fd[0]<-fd[1]
		wait(NULL);	//wait for child to terminate
		lseek (fd[1], 0, SEEK_SET);	//reposition STDOUT read offset to the start
		free(command);
		command = NULL;
		getline(&command, &n, f);	//get second command
		execsp(command);
		return(EXIT_FAILURE);
	}
}


Versione 2 (senza s2argv e getline)

Nota 2: Nella versione senza s2argv e getline, tutto funziona, però ho un "problema" incredibilmente strano: se cancello la variabile char sono_forse_inutile[4096] dichiarata a riga 48, a run-time il programma restituisce segmentation fault. Quella variabile era stata introdotta in precedenza inizialmente per diversa scelta implementativa, e in seguito mantenuta per scopi di debug. Terminata la sua utilità, avevo pensato di rimuoverla, ma a quanto pare non mi è permesso, e il motivo mi sfugge davvero.

La funzione fsplit è stata realizzata prendendo largamente spunto da un'altra funzione trovata su stackoverflow.

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>

char **fsplit(char **res, char str[]) {
	char *p = strtok(str, " ");
	int n_spaces = 0;

	/* split string and append tokens to "res" */

	while (p) {
		n_spaces++;
		res = realloc(res, sizeof(char*) * n_spaces);
		if (res == NULL)
			exit(EXIT_FAILURE);	//allocation failed
		res[n_spaces - 1] = p;
		p = strtok(NULL, " ");
	}

	/* realloc one extra element for the last NULL */

	res = realloc(res, sizeof(char*) * (n_spaces + 1));
	res[n_spaces] = NULL;

	// debug purpose
	/* int i;
	for (i = 0; i < (n_spaces + 1); i++) {
		printf ("res[%d] = %s\n", i, res[i]);
	}*/

	return res;
}

int main (int argc, char* argv[]) {
	//check arguments
	if (argc != 2) {
		fprintf(stderr, "Error: Expected 1 parameter.\n"
			"Usage: %s <pathname>\n", argv[0]);
		return(EXIT_FAILURE);
	}

	char *pathname = argv[1];
	FILE *f;
	struct stat f_info;
	char command_one[100], command_two[100], sono_forse_inutile[4096];
	int fd[2], file_desc_out;
	pid_t pid;

	f = fopen(pathname, "rt");

	//check if file exists
	if(lstat(pathname, &f_info) == -1) {
		perror("stat");
		return(EXIT_FAILURE);
	}

	//read the commands from the first two lines - ignore the other lines
	if ( (fgets(command_one, 100, f) == NULL) ||
		(fgets(command_two, 100, f) == NULL) ) {
		fprintf(stderr, "Error while reading text from %s.", argv[1]);
	}

	fclose(f);

	//remove the \n patterns from the command strings
	strtok(command_one, "\n");
	strtok(command_two, "\n");

	/*split the command strings in arrays, where
		- comm[0] is the command
		- comm[1], comm[2], etc, are the arguments*/

	char **commv_1 = fsplit(commv_1, command_one);
	char **commv_2 = fsplit(commv_2, command_two);

	//create the pipe
	//remember: fd[0] reads and fd[1] writes
	if (pipe(fd) == -1) {
		perror("pipe");
		return(EXIT_FAILURE);
	}

	//create the child and get its pid
	if ( (pid = fork()) == -1) {
		perror("fork");
		return(EXIT_FAILURE);
	}

	if (pid == 0) {	//child
		dup2(fd[1], STDOUT_FILENO);	//connect pipe from execvp to standard output
		close(fd[0]);	//close read side from parent
		execvp(commv_1[0], commv_1);
		perror(commv_1[0]);
		return(EXIT_FAILURE);
	} else {
		close(fd[1]);	//close write side from child
		dup2(fd[0], file_desc_out);
		char *path;

		// obtain absolute path of the reader-side file descriptor of the pipe
		realpath("/proc/self/fd/file_desc_out", path);

		commv_2[1] = path;	//set the obtained path as argument for command 2
		wait(NULL);	//wait for child to terminate
	}

	execvp(commv_2[0], commv_2);
	perror(commv_2[0]);
	return(EXIT_FAILURE);
}

--Ale (talk) 14:01, 25 May 2015 (CEST)

Soluzione di Luca

#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <s2argv.h>
#include <string.h>

int main(int argc, char *argv[]){
	int pfd[2], num_righe=0, tmp=0;
	FILE *file=fopen(argv[1], "r");//apro file in lettura
	char buff[256];
	pipe(pfd);
	
	while(fgets(buff, sizeof(buff), file)!=NULL){//calcolo il numero di righe del file
		num_righe++;
	}
	char comandi[num_righe][256];//array di stringhe
	rewind(file);
	
	for(tmp=0; tmp<num_righe; tmp++){
		fgets(comandi[tmp], sizeof(comandi[tmp]), file);//copio ogni comando per riga
		//printf("comando num %d: %s\n", tmp, comandi[tmp]);
		switch(fork()){
			case 0:	
				if(tmp<num_righe-1){
					dup2(pfd[1], STDOUT_FILENO);
					close(pfd[0]);
					close(pfd[1]);
					execsp(comandi[tmp]); 
					exit(1);
				}
				if(tmp==num_righe-1){
					dup2(pfd[0], STDIN_FILENO);
					close(pfd[0]);
					close(pfd[1]);
					execsp(comandi[tmp]); 
					exit(1);
				}
			case -1: exit(1);

		}
	}
	int status;
	close(pfd[0]);
	close(pfd[1]);
	for(tmp=0; tmp<num_righe; tmp++)
		wait(&status);
	fclose(file);
}

Esercizio 3

Soluzione di LeonardoF bash

#!/bin/bash
#ESERCIZIO 3

find $1 -exec md5sum {} \; |sort | uniq  --all-repeated=separate --check-chars=32
shift 

for i in $@ ; do
	find $1 -exec md5sum {} \; |sort | uniq  --all-repeated=separate --check-chars=32
	shift

done

--LeonardoF (talk) 15:39, 26 March 2017 (CEST)LeonardoF

Soluzione di LeonardoF script Python

#!/usr/bin/env python3
#ESERCIZIO 3
import sys
# os.syscall way to use linux syscalls
import os
import hashlib

dictionary = {}

def add(md5val,path):
	"""function that insert the given file path in a dictionary
	using as key the given md5sum"""	
	#in this way i avoid duplicates
	dictionary.setdefault(md5val,set()).add(path)
	

def md5add(path):
	"""function that takes a filepath and calculate is md5sum
	then it calls a function to insert the file in a dictionary"""
	md5val = hashlib.md5()
	with open(path, "rb") as f:
		#Note that sometimes you won't be able to fit the whole file in memory. 
		#In that case, you'll have to read chunks of 4096 bytes sequentially and feed them to the Md5 function:
		for chunk in iter(lambda: f.read(4096), b""):
			md5val.update(chunk)
	add(md5val.hexdigest(),path)


def movmd5add(path):
	"""recursive fuction that moves in the file system and call the mdadd function
	it takes a path in input (main checks the path given by the user) """
	for root, dirs, files in os.walk(path):
		for f in files:
			#if file call the function for the md5sum 
			md5add(os.path.join(root,f)) # os.path.join(root,f)



def printdict():
	"""funtion that prints the dictionary"""
	for x in dictionary:
		#doesn't print single lines
		if len(dictionary[x]) > 1 :
			print('\r')
			for y in dictionary[x]:
				print(x," : ",y)


def main(args):
	"""main checks the path and call the functions"""
	if len(args) < 1:
		args = "."
	for path in args:
		movmd5add(path)
	printdict()

if __name__ == "__main__":
		main(sys.argv[1:])

--LeonardoF (talk) 15:39, 26 March 2017 (CEST)LeonardoF

Soluzione di S.G python

#!/usr/bin/python
"""
Esercizio 3: Script bash o Python: (10 punti):
Scrivere un programma python o uno script bash che scandisca il sottoalbero relativo alle directory passate come
parametri (o alla direcotry corrente se non ci sono parametri) e fornisca in output l'elenco dei file che hanno la
stessa somma MD5 (i.e. l'output del comando md5sum).
In output ogni riga deve mostrare un elenco di pathname realtivi a file che hanno la stessa somma MD5 (che quindi
sono molto molto probabilmente uguali).
"""

import sys
import os
import hashlib

def sha1sum(root, filename):
    sha1 = hashlib.sha1()
    with open(os.path.join(root, filename), "rb") as thefile:
        buf = thefile.read()
        sha1.update(buf)
    return sha1.hexdigest()

def initSha1vect(path):
    """ Inizializza il dizionario utilizzando come chiave il sha1
    del file, e come valore il percorso del file. """
    shafiles = {}
    for root, dirs, files in os.walk(path):
        for file in files:
            shaKey = sha1sum(root, file)
            shafiles.setdefault(shaKey, [])
            shafiles[shaKey].append(file)
    return shafiles

def main(args):
    for path in args:
        msg = True
        print "\n", path
        shafiles = initSha1vect(path)
        for k in shafiles:
            if len(shafiles[k]) > 1:
                msg = False
                print k, "\t", shafiles[k]
        if msg:
            print "Nessun file con lo stesso sha1"

if __name__ == "__main__":
	main(sys.argv[1:])

S.G (talk) 14:39, 18 November 2016 (CET)
Ho scritto una possibile soluzione dell'esercizio 3

perché proporre una soluzione in un linguaggio che non ho ancora spiegato?Renzo (talk) 19:36, 21 November 2016 (CET)

Soluzione di Luca(Bash)

#! /bin/bash
trova () {
   find $1 -type f -exec md5sum {} \; | sort > md5.txt #calcola l'md5 di tutto il sottoalbero, lo ordina e lo salva in un file
   cat md5.txt | grep "`cut -d ' ' -f 1 md5.txt | uniq -d`" #stampa le righe del file, nelle quali in primo campo ha valore(md5) duplicato 
}

if [[ $# -eq 0 ]] ; then #se num argomenti è 0
   trova
else
   for parametro in $* #chiamo la funzione per ogni argomento
   do
      trova $parametro
   done
fi
exit