Prova pratica 2016.05.31
Revision as of 21:07, 21 May 2017 by GabrieleCalarota (talk | contribs) (Corretto fork al posto di subprocess.popen() che non si può usare)
Esercizio 1
Scrivere un programma che preso come parametro a linea comando il path di una directory elenchi solamente I file
che hanno un nome che ha come suffisso un numero (es. Prova.10). I file devono essere ordinati in ordine
numerico.
Esempio se la directory
test contiene I file prova5, giovanni, aaa.1000, bb.2000, ccc.dd.500 l'output del programma deve essere:
ccc.dd.500
aaa.1000
bb.2000
(in quanto 500 numericamente e' minore di 1000, prova5 non si considera: manca il punto prima del numero).
Soluzione di Alexp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <ctype.h>
#include <stdint.h>
#include <sys/stat.h>
/*
Assumes that filename contains a digit in the suffix
*/
uint64_t getSuffixNumber(const char* filename){
size_t len = strlen(filename)-1;
size_t pos = len;
uint64_t number = 0;
uint64_t decimal = 1;
//while there are digits to read
while(pos>=0 && isdigit(filename[pos])){
//number+=digit converted to int, multiplied by decimal position
number+=(filename[pos] - '0')*decimal;
decimal*=10;
pos--;
}
return number;
}
/*
Returns 1 if the given filename ends with a number, 0 otherwise
*/
int endsWithNumber(const char* filename){
size_t len = strlen(filename)-1;
size_t pos = len;
//stating from last character, go backwards until there are digits
while(pos>=0 && isdigit(filename[pos])) pos--;
//if the suffix is actually a number, preceeded by a '.'
if(pos>=0 && pos != len && filename[pos] == '.') return 1;
else return 0;
}
int sortbysuffix(const struct dirent **e1, const struct dirent **e2) {
const char *a = (*e1)->d_name;
const char *b = (*e2)->d_name;
uint64_t suffixA = getSuffixNumber(a);
uint64_t suffixB = getSuffixNumber(b);
//compare two suffixes
return suffixA < suffixB;
}
int filter(const struct dirent* ent){
//exclude "." and ".." and files not ending with a ".(number)+"
if(strcmp(ent->d_name,".") && strcmp(ent->d_name,"..") && endsWithNumber(ent->d_name)){
return 1;
}
else return 0;
}
void printFilenames(char* path){
struct dirent **namelist;
int n;
n = scandir(path, &namelist, filter, sortbysuffix);
if (n < 0)
perror("scandir");
else {
while (n--) {
printf("%s\n", namelist[n]->d_name);
free(namelist[n]);
}
free(namelist);
}
}
int isDirectory(const char *path) {
struct stat statbuf;
//if unable to get file status
if (stat(path, &statbuf) != 0) return 0;
//otherwise if we got the file status, check if it's a directory
return S_ISDIR(statbuf.st_mode);
}
int main(int argc, char* argv[]){
if(argc == 2 && isDirectory(argv[1])){
printFilenames(argv[1]);
}
else{
printf("Error, input a directory name.\n");
}
return 0;
}
Esercizio 2
Come nell'esercizio 1 occorre cercare in una directory (passata come parametro) I file che hanno come suffisso un
numero. Nell'esercizio 2 I file sono eseguibili e l numero indica il numero di millisecondi da attendere a partire dalla attivazione del programma prima di attivarli.
Nell'esempio dell'esercizio precedente occorre aspettare mezzo secondo e lanciare ccc.dd.500, poi a 1 secondo
dall'attivazione (cioe' dopo approssimativamente ulteriori 0.5 secondi) si lancia aaa.1000 e allo scadere del
secondo secondo bbb.2000.
I file eseguibili nella directory vengono eseguiti in background (non si attende la fine dell'esecuzione per
continuare). Quindi se due file hanno lo stesso prefisso numerico vengono eseguiti in modo concorrente.
Soluzione di Alexp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <ctype.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
/*
Assumes that filename contains a digit in the suffix
*/
uint64_t getSuffixNumber(const char* filename){
size_t len = strlen(filename)-1;
size_t pos = len;
uint64_t number = 0;
uint64_t decimal = 1;
//while there are digits to read
while(pos>=0 && isdigit(filename[pos])){
//number+=digit converted to int, multiplied by decimal position
number+=(filename[pos] - '0')*decimal;
decimal*=10;
pos--;
}
return number;
}
int endsWithNumber(const char* filename){
size_t len = strlen(filename)-1;
size_t pos = len;
//stating from last character, go backwards until there are digits
while(pos>=0 && isdigit(filename[pos])) pos--;
//if the suffix is actually a number, preceeded by a '.'
if(pos>=0 && pos != len && filename[pos] == '.') return 1;
else return 0;
}
int sortbysuffix(const struct dirent **e1, const struct dirent **e2) {
const char *a = (*e1)->d_name;
const char *b = (*e2)->d_name;
uint64_t suffixA = getSuffixNumber(a);
uint64_t suffixB = getSuffixNumber(b);
//compare two suffixes
return suffixA < suffixB;
}
/*
Returns 1 if the file is an executable file, 0 otherwise
*/
int isExecutable(const char* path){
struct stat buf;
//if unable to get file status
if (stat(path, &buf) != 0) return 0;
//if the file is executable by user
if (buf.st_mode & S_IXUSR) return 1;
return 0;
}
int filter(const struct dirent* ent){
//exclude "." and ".." and files not ending with a ".(number)+"
if(strcmp(ent->d_name,".") && strcmp(ent->d_name,"..") && endsWithNumber(ent->d_name)){
return 1;
}
else return 0;
}
void runExecutables(char* path){
struct dirent **namelist;
int n;
//delay time in ms
uint64_t waitingMS;
char* fullpath;
//forked child's pid
pid_t pid;
//used to wait all the children
int status = 0;
n = scandir(path, &namelist, filter, sortbysuffix);
if (n < 0) perror("scandir");
else {
while (n--) {
waitingMS = getSuffixNumber(namelist[n]->d_name);
//get the full dirname+filename path
asprintf(&fullpath, "%s%s", path, namelist[n]->d_name);
if(isExecutable(fullpath)){
printf("Calling %s\n",fullpath);
if( pid != fork() ){
//child
//wait for the required time(in microseconds)
usleep(waitingMS*1000);
char *args[] = {fullpath,(char *)0};
printf("Starting%s\n", args[0]);
execvp(fullpath,args);
}
}
free(fullpath);
free(namelist[n]);
}
//wait till all the children terminate
while ((pid = wait(&status)) > 0);
free(namelist);
}
}
int isDirectory(const char *path) {
struct stat statbuf;
//if unable to get file status
if (stat(path, &statbuf) != 0) return 0;
//otherwise if we got the file status, check if it's a directory
return S_ISDIR(statbuf.st_mode);
}
int main(int argc, char* argv[]){
if(argc == 2 && isDirectory(argv[1])){
runExecutables(argv[1]);
}
else{
printf("Error, input a directory name.\n");
}
return 0;
}
Esercizio 3
Bash
Soluzione di G.C.
#!/bin/bash
if [ $# -lt 1 ] ; then
echo "Argument error"
exit
fi
tmp_file=file_tmp
touch $tmp_file
find $1 -type f | xargs basename -a | while read line
do
#$line contains file name
extension="${line##*.}"
#suffix contains only digits
if [[ $extension =~ ^[0-9]+$ ]]
then
echo "$line:$extension" >> $tmp_file
fi
done
#sort by second column
tmp1_file=tmp1_file
cat $tmp_file | sort -t':' -nk2 > $tmp1_file
count=0
awk -F: '{print $1, $2}' $tmp1_file | while read line
do
lineCols=( $line )
#execute the first column in bg
$1/${lineCols[0]} &
#calculate the delay time from the last exec
res=$((${lineCols[1]}-$count))
count=${lineCols[1]}
sleep $(($res / 1000))
done
rm $tmp_file $tmp1_file
Python3
Soluzione di G.C.
import sys
import os
import time
import subprocess
def getListOfFileAndTiming(d):
listOfFile = [f for f in os.listdir(d) if os.path.isfile(os.path.join(d,f))]
l = []
for x in listOfFile:
s = x.split('.')
if s[0] != s[-1] and s[-1].isdigit():
l.append((os.path.join(d,x),int(s[-1])))
return l
def sleepAndExecute(l):
l = sorted(l, key=lambda x:x[1])
for x in l:
print('starting %s '% (x[0]))
if os.fork() == 0:
subprocess.run([x[0]])
sys.exit()
print('sleeping %f s' % (x[1]/1000))
time.sleep(x[1]/1000)
if __name__ == '__main__':
try:
if len(sys.argv) < 2:
raise Exception("Argument ERROR: input a directory")
directory = sys.argv[1]
l = getListOfFileAndTiming(directory)
sleepAndExecute(l)
except Exception as inst:
print(inst.args)