├── Tasks ├── README.md ├── 02 │ └── README.md └── 01 │ └── README.md ├── week7 ├── online ├── copypdf └── README.md ├── week8 ├── solutions │ ├── task0 │ ├── task1 │ ├── task4 │ ├── task2 │ └── task3 └── README.md ├── week12 ├── Solutions │ ├── zad1_sol │ ├── zad2_sol │ ├── zad1_sol.c │ └── zad2_sol.c ├── parent-2children.c ├── parent-3children.c ├── shared_filedesc.c └── README.md ├── week14 ├── task2 ├── task3 ├── task5 ├── task4_var1 ├── task4_var2 ├── tras └── README.md ├── week13 ├── Solutions │ ├── zad3 │ ├── zad2 │ ├── zad4 │ └── tras └── README.md ├── week9 ├── zad2 ├── zad1 └── README.md ├── week11 ├── Examples │ ├── writeExample.c │ ├── writeWith2FileDesc.c │ ├── readExample.c │ └── lseekExample.c ├── Solutions │ ├── zad2.c │ ├── myCP.c │ └── zad3.c └── README.md ├── week10 ├── task1 └── README.md ├── week6 ├── solutions └── README.md ├── week15 ├── README.md ├── task2.c ├── task1.c └── task4.c ├── week16 └── README.md ├── week2 ├── solutions.sh └── README.md ├── README.md ├── week5 └── README.md ├── week1 └── README.md └── week3-4 └── README.md /Tasks/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /week7/online: -------------------------------------------------------------------------------- 1 | date | cut -d ' ' -f 2-3,6 2 | who | wc -l 3 | -------------------------------------------------------------------------------- /week8/solutions/task0: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sort $1 | write $2 3 | -------------------------------------------------------------------------------- /week8/solutions/task1: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | read concatedfile 3 | cat $1 $2 > $concatedfile 4 | -------------------------------------------------------------------------------- /week7/copypdf: -------------------------------------------------------------------------------- 1 | mkdir my_pdfs 2 | cp ~/*.pdf my_pdfs 3 | echo "Files are $(ls my_pdfs | wc -l)" 4 | -------------------------------------------------------------------------------- /week8/solutions/task4: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | read file str 4 | 5 | grep $file $str 6 | 7 | echo "PID of grep is $?" 8 | -------------------------------------------------------------------------------- /week12/Solutions/zad1_sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carolinepetrova/OperatingSystems_2019-2020/HEAD/week12/Solutions/zad1_sol -------------------------------------------------------------------------------- /week12/Solutions/zad2_sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carolinepetrova/OperatingSystems_2019-2020/HEAD/week12/Solutions/zad2_sol -------------------------------------------------------------------------------- /week14/task2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for user 4 | do 5 | if who | grep $user 6 | then 7 | cat /etc/passwd | grep $user 8 | fi 9 | done 10 | -------------------------------------------------------------------------------- /week13/Solutions/zad3: -------------------------------------------------------------------------------- 1 | thirdLine=`head -n 3 $3 | tail -n 1` 2 | name=`expr substr $thirdLine 1 6` 3 | 4 | find $1 -name $name -user $2 2>/dev/null | wc -l 5 | -------------------------------------------------------------------------------- /week14/task3: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | read str 4 | 5 | for user 6 | do 7 | if who -u | grep $user | grep "." 8 | then 9 | echo $str | write $user 10 | fi 11 | done 12 | 13 | -------------------------------------------------------------------------------- /week9/zad2: -------------------------------------------------------------------------------- 1 | read dirname 2 | 3 | if [ ! -d ~/$dirname ] 4 | then 5 | mkdir ~/$dirname 6 | fi 7 | 8 | for file in $(ls ~) 9 | do 10 | if [ ! -d "$file" -a $(wc -c < "$file") -gt 50 ] 11 | then 12 | cp $file ~/$dirname 13 | echo $file 14 | fi 15 | done 16 | 17 | -------------------------------------------------------------------------------- /week13/Solutions/zad2: -------------------------------------------------------------------------------- 1 | if [ ! -d ~/$1 ] 2 | then 3 | mkdir ~/$1 4 | fi 5 | 6 | counter=0 7 | 8 | for f in * 9 | do 10 | if [ -f "$f" -a -r "$f" -a -w "$f" ] 11 | then 12 | cp $f ~/$1 13 | else 14 | counter=`expr $counter + 1` 15 | fi 16 | done 17 | echo "Number files not copied $counter" 18 | -------------------------------------------------------------------------------- /week11/Examples/writeExample.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | int fd1 = open("file2.txt", O_WRONLY|O_CREAT, 0777); 9 | write(fd1, "Hello ", 6); 10 | write(fd1, "something", 9); 11 | close(fd1); 12 | return 0; 13 | } -------------------------------------------------------------------------------- /week13/Solutions/zad4: -------------------------------------------------------------------------------- 1 | lastLine=`tail -n 1 $2` 2 | findIndex=`expr index $lastLine 1` 3 | 4 | substrName=`expr substr $lastLine 1 $findIndex` 5 | 6 | counter=`find ~/.. -name $substrName 2>/dev/null | wc -l` 7 | 8 | if [ $counter -eq 0 ] 9 | then 10 | echo "Didnt find files" | write $1 11 | else 12 | echo $numOfFiles 13 | fi 14 | -------------------------------------------------------------------------------- /week14/task5: -------------------------------------------------------------------------------- 1 | if [ -z $3 ] 2 | then 3 | set $1 $2 "`cat ff`" 4 | fi 5 | 6 | counter=0 7 | 8 | for file in ./* 9 | do 10 | if [ $file == *.c ] 11 | then 12 | mv $file $1 13 | elif [ $file == *.out ] 14 | then 15 | mv $file $2 16 | else 17 | counter=`expr $counter + 1` 18 | fi 19 | done 20 | 21 | echo "not moved $counter" 22 | -------------------------------------------------------------------------------- /week14/task4_var1: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # finding the size of the files in the directory without browsing the subdirectories 4 | 5 | counter=0 6 | 7 | for file in $1/* 8 | do 9 | if [ -f $file ] 10 | then 11 | counter=$(expr $counter + $(wc -c < $file)) 12 | fi 13 | done 14 | 15 | if who -u | grep $2 | grep "." 16 | then 17 | echo $counter | write $2 18 | fi 19 | -------------------------------------------------------------------------------- /week8/solutions/task2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | read str 3 | # ако имаме специфициран брой файлове (примерно 2) 4 | number=$(expr $(grep $str $1 $2 | wc -l)) 5 | echo "Number of occurance of $str in the files $@ is $number" 6 | 7 | # без значение броя на подадените файлове 8 | 9 | number2=$(expr $(grep $str $@ | wc -l)) 10 | echo "Number of occurance of $str in the files $@ is $number" 11 | -------------------------------------------------------------------------------- /week11/Examples/writeWith2FileDesc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char * argv[]) { 8 | int fd1 = open(argv[1], O_WRONLY|O_CREAT|O_EXCL, 0777); 9 | int fd2 = open(argv[1],O_WRONLY); 10 | 11 | write(fd1, "hello\n", 6); 12 | write(fd2, "akula\n", 6); 13 | close(fd1); 14 | close(fd2); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /week9/zad1: -------------------------------------------------------------------------------- 1 | read f1 f2 2 | num1=$(file $f1/* | grep "ASCII text" | wc -l) 3 | num2=$(file $f2/* | grep "ASCII text" | wc -l) 4 | 5 | if [ $(expr $num1 + $num2) -ge 20 ] 6 | then 7 | touch sources.txt 8 | file $f1/* | grep "ASCII text" | cut -d " " -f1 > sources.txt 9 | file $f2/* | grep "ASCII text" | cut -d " " -f1 >> sources.txt 10 | chmod a=r sources.txt 11 | else 12 | echo "some msg $(expr $num1 + $num2)" 13 | fi 14 | 15 | -------------------------------------------------------------------------------- /week10/task1: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$(who -T|grep $1|grep +)" ] 4 | then 5 | echo "Files are $(expr $# - 2)"| write $1 6 | 7 | shift 2 8 | 9 | if [ ! -d ~/c_sources ] 10 | then 11 | mkdir ~/c_sources 12 | fi 13 | 14 | counter=0 15 | 16 | for i in $@ 17 | do 18 | if [[ $i == *".c" && -r $i || -w $i ]] 19 | then 20 | mv $i ~/c_sources 21 | else 22 | counter=$(expr $counter + 1) 23 | fi 24 | done 25 | echo "Files left $counter" 26 | fi 27 | 28 | -------------------------------------------------------------------------------- /week11/Examples/readExample.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | char buff1[4]; 9 | char buff2[4]; 10 | int fd1 = open("file.txt", O_RDONLY); 11 | int bytesRead1 = read(fd1, buff1, 2); 12 | int bytesRead2 = read(fd1, buff2, 4); 13 | write(1, "buff1: ", 7); 14 | write(1, buff1, 2); 15 | write(1, "\nbuff2: ", 8); 16 | write(1, buff2, 4); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /week11/Solutions/zad2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char* argv[]) { 8 | int fd1, buff[1]; 9 | if ((fd1 = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0755)) == -1) { 10 | perror(“open”); exit(-1); 11 | } 12 | while(read(0, buff, 1) > 0) { 13 | write(fd1, buff, 1); 14 | if (buff[0] == '\t') { 15 | write(2, “>>>”, 3); 16 | } 17 | else { 18 | write(2, buff, 1); 19 | } 20 | } 21 | close(fd1); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /week6/solutions: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # task1 4 | 5 | find / -user `whoami` 2>/dev/null 6 | 7 | # task2 8 | 9 | read file 10 | sort $file >> $file 11 | 12 | # !!! > не работи заради реда на изпълнение на операторите - тук пренасочването се изпълнява преди sort, а това пренасочване изтрива съдържанието на файла и съответно нямаме какво да сортираме и запишем 13 | 14 | # task3 15 | 16 | read file num 17 | head -n $num | tail -n 1 18 | 19 | # task4 20 | 21 | read file1 file2 22 | w > $file1 23 | size=$(expr $(wc -c < $file2) \* 2) 24 | echo $size >> $file1 25 | -------------------------------------------------------------------------------- /week12/parent-2children.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | 8 | Parent 9 | / \ 10 | Child1 Child2 11 | 12 | */ 13 | 14 | int main() { 15 | int status = 0; 16 | // creates the first child 17 | int pid = fork(); 18 | // we isolate code which will be done only from the parent 19 | // so we create only one child 20 | if(pid>0) { 21 | int pid2 = fork(); 22 | } 23 | // print 3 times hello 24 | printf("Hello!!!\n"); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /week14/task4_var2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # finding the size of the files in the directory without browsing the subdirectories 4 | 5 | counter=0 6 | 7 | allfiles=$(du $1) 8 | 9 | for line in $allfiles 10 | # the output from du is parsed by a whitespace and passed to "line" 11 | do 12 | if [ $line -eq $line 2>/dev/null ] 13 | # this way we can separate the integers (operators do only integer comparisons) 14 | then 15 | counter=$(expr $counter + $line) 16 | fi 17 | done 18 | 19 | if who -u | grep $2 | grep "." 20 | then 21 | echo $counter | write $2 22 | fi 23 | 24 | -------------------------------------------------------------------------------- /week15/README.md: -------------------------------------------------------------------------------- 1 | # Задачи върху програми на С 2 | 3 | 1. Да се напише програма на C, която реализира `mv file1 file2` 4 | 2. Да се напише програма на С, която реализира `cat [файл] [...] ` 5 | 3. Да се напише програма на C, която реализира `expr substr ... ` 6 | 4. Да се напише програма на C, която получава като параметри в командния ред 2 команди (без параметри). Програмата реализира конструкцията: `команда1 && команда2` 7 | 5. Да се напише програма на C, която получава като параметри в командния ред 2 команди (без параметри). Програмата реализира конструкцията: `команда1 || команда2` 8 | -------------------------------------------------------------------------------- /week15/task2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | int main(int argc, char* argv[]) 7 | { 8 | 9 | for(int i = 1; i < argc; i++) { 10 | int fd = open(argv[i],O_RDONLY); 11 | if(fd==-1) { 12 | printf("There was an error\n"); 13 | return 1; 14 | } 15 | char byteBuff[1]; 16 | while(read(fd,byteBuff,1) > 0) 17 | { 18 | write(1, byteBuff,1); 19 | } 20 | close(fd); 21 | } 22 | return 0; 23 | } -------------------------------------------------------------------------------- /week11/Solutions/myCP.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char * argv[]) { 8 | int fd1 = open(argv[1],O_RDONLY); 9 | if(fd1==-1) { 10 | printf("There was an error\n"); 11 | return 1; 12 | } 13 | int fd2 = open(argv[2],O_CREAT|O_WRONLY, 0664); 14 | if(fd2==-1) { 15 | printf("There was an error\n"); 16 | return 1; 17 | } 18 | char byteBuff[1]; 19 | while(read(fd1, byteBuff, 1) > 0) { 20 | write(fd2, byteBuff, 1); 21 | } 22 | close(fd1); 23 | close(fd2); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /week12/Solutions/zad1_sol.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char * argv[]) { 8 | int pid = fork(); 9 | if(pid == -1) { 10 | perror("fork error"); 11 | exit(-1); 12 | } 13 | else if(pid > 0) { 14 | int status = 0; 15 | wait(&status); 16 | printf("%d", status); 17 | if(status == 0) 18 | printf("Command name %s\n", argv[1]); 19 | } 20 | else { 21 | if(execlp(argv[1], argv[1], NULL) == -1) { 22 | perror("exec error"); 23 | exit(-1); 24 | } 25 | } 26 | return 0; 27 | } -------------------------------------------------------------------------------- /week15/task1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) { 8 | int fd1 = open(argv[1],O_RDONLY); 9 | if(fd1 == -1) { 10 | perror("unexpected error") 11 | exit(-1) 12 | } 13 | int fd2 = open(argv[2],O_CREAT|O_TRUNC|O_WRONLY), 0777); 14 | if(fd2 == -1) { 15 | printf("unexpected error"); 16 | return 1; 17 | } 18 | char byteBuff[1]; 19 | while(read(fd1, byteBuff, 1) > 0) { 20 | write(fd2,byteBuff,1); 21 | } 22 | remove(argv[1]); 23 | close(fd1); 24 | close(fd2); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /week12/parent-3children.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | 8 | Parent 9 | / \ 10 | Child2 Child1 11 | \ 12 | Child3 13 | */ 14 | 15 | int main() { 16 | int status = 0; 17 | // creates the first child 18 | int pid = fork(); 19 | /* as we created the first child everything from here is executed 20 | by the parent and the child so the parent will create another child 21 | and the first child of the parent will create it's own child too 22 | */ 23 | int pid2 = fork(); 24 | // print 4 times hello 25 | printf("Hello!!!\n"); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /week15/task4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char * argv[]) { 9 | int pid = fork(); 10 | int status; 11 | if(pid == -1) { 12 | perror("fork error"); 13 | exit(-1); 14 | } 15 | else if(pid > 1) { 16 | // parent 17 | wait(&status); 18 | if(status == 0) { 19 | execlp(argv[2], argv[2], NULL); 20 | } 21 | } 22 | else { 23 | //child 24 | if(execlp(argv[1], argv[1], NULL) == -1) { 25 | perror("exec errror"); 26 | exit(-1); 27 | } 28 | } 29 | return 0; 30 | } -------------------------------------------------------------------------------- /week8/solutions/task3: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | read dirname 4 | # тук зависи как тълкуваме задачата 5 | # ако искаме общия брой 6 | 7 | echo "Number of files in directory $dirname is $(ls $dirname | wc -l)" 8 | 9 | # ако искаме по отделно 10 | 11 | files_count=$(find $dirname -type f -maxdepth 1 2>/dev/null | wc -l) 12 | directory_count=$(find $dirname -type d -maxdepth 1 2>/dev/null | wc -l) 13 | 14 | echo "Number of files in $dirname are $files_count and directories are $directory_count" 15 | 16 | # IMPORTANT !!! 17 | 18 | # Ако подадете от stdin ~ (специалният символ за началната потребителска директория) 19 | # той ще бъде интерпретиран като литерал (не се интерпретира със специалното си значение) и ls и find ще хвърлят грешка (няма да видите грешката на find, защото сме пренасочили изхода за грешки) 20 | -------------------------------------------------------------------------------- /week14/tras: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | br=1 3 | br=`expr $br \* $2` # br=1 4 | a=$3 # a =3 5 | set ab bc cd de # $1 = ab ; $2 = bc ; $3 = cd ; $4 = de 6 | shift # $1 = bc; $2 = cd; $3 = de $4 = "" 7 | while true 8 | do echo $* bc cd de 9 | for j 10 | do 11 | if test $# -lt $br 12 | then 13 | br=` expr $br / 2` 14 | echo $br $j >> file 15 | else 16 | br=`expr $br + $a` #br = 3+2 17 | echo $br $j >> file 18 | fi 19 | done 20 | break 21 | done 22 | read a1 a2 # $a1=c $a2=d 23 | while cat file | grep $a1 # output of the command will be printed to stdout! 24 | do echo $a $a2 25 | wc -l file 26 | tail -5c file # tail -c 5 file 27 | exit 28 | echo FIN # this will not be printed because of exit 29 | done 30 | # this below will not be printed because of exit 31 | echo $a $a1 32 | wc -c file 33 | tail -2l file 34 | -------------------------------------------------------------------------------- /week11/Examples/lseekExample.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char * argv[]) { 8 | int fd1 = open(argv[1], O_RDONLY); 9 | 10 | int pos = lseek(fd1, 2, SEEK_SET); 11 | 12 | int pos2 = lseek(fd1, 0, SEEK_CUR); // current position 13 | 14 | char tmp[4] = {0}; 15 | sprintf(tmp, "%d", pos2); //print to buffer 16 | write(1, "Cursor is at: ", sizeof("Cursor is at: ")); 17 | write(1, tmp, sizeof(tmp)); 18 | 19 | int pos3 = lseek(fd1, 0, SEEK_END); // size of file in bytes 20 | char tmp2[4] = {0}; 21 | sprintf(tmp2, "%d", pos3); //print to buffer 22 | write(1, "\nSize of file is ", sizeof("\nSize of file is ")); 23 | write(1, tmp2, sizeof(tmp2)); 24 | close(fd1); 25 | 26 | return 0; 27 | } -------------------------------------------------------------------------------- /week16/README.md: -------------------------------------------------------------------------------- 1 | # Задачи върху програми на С - втора част 2 | 3 | 1. Да се напише програма на C, която реализира `head f1` - извежда първите 10 реда от съдържанието на f1 на стандартния изход. 4 | 2. Да се напише програма на С, която получава като параметър име на файл. Ако файлът не съществува се създава, а ако същестува се изтрива съдържанието му. Програмата чете редове от стандартния вход, заменя всяка цифра с * и записва реда във файла. 5 | 3. Да се напише програма на C, която извежда номера на процеса и номера на родителя му. Сменя образа му с UNIX команда (например ps) и извежда резултата от exec(). 6 | 4. Да се напише програма на С, която получава като параметър име на файл. Създава процес син, който записва стринга `foobar` във файла (ако не съществува, го създава, в противен случай го занулява), след което процеса родител прочита записаното във файла съдържание и го извежда на стандартния изход, добавяйки по един интервал между всеки два символа. 7 | -------------------------------------------------------------------------------- /Tasks/02/README.md: -------------------------------------------------------------------------------- 1 | 1. Напишете серия от команди, които четат от стандартния вход име на директория. Извеждат на стандартния изход информация за всички файлове в текущата директория, чиито име е точно три символа, като последният е цифрата 1,2 или 3. Записват във файла file_type първите 5 файла от прочетената директория, които съдържат ASCII текст, а за тези, които съдържат програми на Си, извеждат на екрана броя им с подходящо съобщение. 2 | 3 | 2. Напишете серия от команди, които четат от стандартния вход име на файл, който съдържа символен низ, и име на празен файл. Запишете в празния файл всички редове на файловете, които не съдържат този низ, от цялата файлова система и са притежание на текущия потребител. 4 | 5 | 3. Прочетете име на файл от стандартния вход. В него запишете информация за всички процеси в системата и изпратете съдържанието на файла до себе си с подходящо съобщение. (за да получите съобщението може да се наложи да използвате sudo login your_username) 6 | -------------------------------------------------------------------------------- /week12/Solutions/zad2_sol.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* IDEA: 8 | Child process is being substituted by the exec command but the 9 | parent process can still execute the for loop. Thus we can execute the 10 | parameters successively. On every iteration the for loop spawns a new child and waits for it to finish. 11 | The child does it's work and finishes (dies :D) while the parent process is still alive. 12 | */ 13 | 14 | int main(int argc, char * argv[]) { 15 | int i; 16 | for(i = 1; i < argc; i++) { 17 | int pid = fork(); 18 | int status = 0; 19 | if(pid == -1) { 20 | perror("fork error"); 21 | exit(-1); 22 | } 23 | else if (pid > 0) { 24 | wait(&status); 25 | printf("Process %s with pid=%d exited with status %d\n", argv[i],pid, status); 26 | } 27 | else { 28 | execlp(argv[i], argv[i],NULL); 29 | perror("exec error"); 30 | exit(-1); 31 | } 32 | } 33 | return 0; 34 | } -------------------------------------------------------------------------------- /week12/shared_filedesc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | /* 9 | Shared file descriptor 10 | */ 11 | 12 | int main() { 13 | int fd1 = open("filedesc", O_CREAT|O_TRUNC|O_WRONLY, 0777); 14 | int seek_ptr = 0; 15 | if(fd1 == -1) { 16 | perror("Couldn't open file"); 17 | exit(-1); 18 | } 19 | int pid = fork(); 20 | if(pid>0) { 21 | printf("Parent: file descriptor %d\n", fd1); 22 | seek_ptr = lseek(fd1, 0, SEEK_CUR); 23 | printf("Parent: File pointer is at %d\n", seek_ptr); 24 | write(fd1, "Hello from parent\n", strlen("Hello from parent\n")); 25 | 26 | } 27 | else if(pid == 0) { 28 | printf("Child: file descriptor %d\n", fd1); 29 | seek_ptr = lseek(fd1, 0, SEEK_CUR); 30 | printf("Child: File pointer is at %d\n", seek_ptr); 31 | write(fd1, "Hello from child\n", strlen("Hello from child\n")); 32 | } 33 | else { 34 | perror("Couldn't fork"); 35 | exit(-1); 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /week11/Solutions/zad3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | Чете последователност от символи от файл, чието име е подадено като първи параметър. 9 | Извежда ги на стандартния изход. 10 | Първите 3 символа от всеки ред добавя след края на файл, чието име е подадено като втори параметър. 11 | */ 12 | 13 | int main(int argc, char * argv[]) { 14 | int fd1 = open(argv[1], O_RDONLY); 15 | int fd2 = open(argv[2], O_CREAT|O_APPEND|O_WRONLY, 0644); 16 | if(fd1 == -1) { 17 | perror("Error opening file 1"); 18 | exit(-1); 19 | } 20 | if(fd2 == -1) { 21 | perror("Error opening file 2"); 22 | exit(-1); 23 | } 24 | char buff[1]; 25 | int byteCount = 0; 26 | while(read(fd1,buff,1)>0) { 27 | write(1,buff,1); 28 | if(byteCount <3) { 29 | ++byteCount; 30 | write(fd2, buff, 1); 31 | } 32 | else { 33 | if(buff[0] == '\n') { 34 | byteCount = 0; 35 | } 36 | } 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /week2/solutions.sh: -------------------------------------------------------------------------------- 1 | # --- task 1 --- 2 | 3 | tee f1 4 | touch f2 5 | cp f1 f3 6 | mkdir dir1 7 | cd dir1 8 | mv ../f1 ff1 9 | mv ../f2 ff2 10 | mv ../f3 ff3 11 | 12 | # --- task 2 --- 13 | 14 | mkdir del 15 | mv f* del 16 | rm -ir del #this asks for every file in del. -Ir asks only once 17 | 18 | # --- task 3 --- 19 | 20 | grep "Georgi" /etc/passwd #this searches for the pattern Georgi, it will find also "Georgiev" 21 | #grep -w /etc/passwd "Georgi" - this maches whole word 22 | 23 | # --- task 4 --- 24 | grep -v "s8" /etc/passwd 25 | 26 | # --- task 5 --- 27 | find / -name dir* -type d 2>/dev/null 28 | 29 | # --- task 6 --- 30 | find ~ -name *.txt -exec wc -c {} \; 2>/dev/null 31 | 32 | #OR 33 | 34 | cd 35 | find . -name *.txt -exec wc -c {} \; 2>/dev/null 36 | 37 | # --- task 7 --- 38 | 39 | find / -group student -exec tail -n 5 {} \; 2>/dev/null 40 | 41 | # --- task 8 --- 42 | 43 | file ~/* 44 | 45 | #OR 46 | 47 | cd 48 | file * 49 | 50 | # --- task 9 --- 51 | 52 | cut -d ":" -f 5 /etc/passwd 53 | 54 | # --- task 10 --- 55 | 56 | sort /etc/passwd -o passwd_sorted 57 | cmp /etc/passwd passwd_sorted 58 | 59 | -------------------------------------------------------------------------------- /week13/Solutions/tras: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Позиционните ни параметри са: $1 = b1, $2 = b2; $3 = b3 => $5 ни е празна 3 | if test –z $5 # проверката е вярна (-z проверява за празен низ) 4 | then echo $1 # принтираме съдържанието на $1 5 | for var # loop-ваме през списъка от позиционни параметри 6 | do echo $var >> fniz # ако файла не е празен съдържанието се append-ва в края 7 | done 8 | else 9 | echo $2 10 | while true 11 | do echo LOOP 12 | break 13 | done 14 | fi 15 | cat fniz # принтираме съдържанието на файла 16 | read string # по условие прочитаме b2 17 | until cat fniz | grep $string 18 | # тъй като горе сме записали b2 във файла условието е вярно (изходния код е 0) и тъй като until се изпълнява, докато условието 19 | # е грешно то ние няма да влезем в тялото на цикъла, НО!!! на стандартния изход ще се принтира output-a на командата в условието 20 | do 21 | set $2 b1 22 | echo `grep $2 fniz ` 23 | echo END 24 | exit 25 | done 26 | set $3 $1 1 27 | # тук променямае съдържанието на променливите $1 $2 ... 28 | # $1 става със съдържание b3 29 | # $2 става със съдържание b3 30 | # $3 става със съдържание 1, останалите са празни 31 | echo OK $3 # принтира се ОК 1 32 | echo `grep $1 fniz` # принтираме output-a на командата 33 | exit # командната процедура приключва 34 | echo OK # не се изпълнява 35 | -------------------------------------------------------------------------------- /Tasks/01/README.md: -------------------------------------------------------------------------------- 1 | ## Задачи 2 | 1. Създайте директории с име dir1 и dir2 . Влезте в dir2. Копирайте всички файлове, чието име е точно два символа, като последния символ е цифра от 0 до 9 от родителската директория на dir1 в dir2 (без да излизате от dir2). Намерете броя на всички файлове с разширение .txt в началната ви потребителска директория и всички нейни поддиректории и запишете резултата във файл txt_count. Към този файл прикачете и последните 2 създадени файла в родителската директория на началната потребителска директория (използвайте `man ls`, за да видите опциите). Също така прикачете и **само** 100-тният ред от passwd.txt, който съм ви прикачила. 3 | 2. Изведете на екрана и във файл fff, редовете, в които се среща символния низ **line** в първите 10 реда на всеки от файловете с име, състоящо се от поне 2 символа, в цялата файлова директория. 4 | 3. Създайте празен файл chgmode. Запишете във файл с име processes информация за процесите в системата, в които е стартиран редакторът vim. Изведете на стандартния изход броя на процесите, които са притежание на `root`. Във файла processes добавете системната дата. Също така добавете началното времe и времето изразходвано от процесора за изпълнението на процес,притежавани от `root`. От файла chgmode премахнете право за четене от групата и останалите и добавете право за четене,писане и изпълнение към потребителя, притежаващ файла. 5 | -------------------------------------------------------------------------------- /week14/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Задачи върху командни процедури на Bash (2-ра част) 3 | 4 | 1. **(Държавен изпит КН 2016)** Текстов файл с име ​**comproc1**​ съдържа зададената по­долу последователностот команди на bash за Linux. Да се подчертаят операторите, които извеждат текст настандартния изход и за всеки от тях да се напише вдясно какво ще бъде изведено следстартиране на файла със следния команден ред: **bash comproc 1 1 3 5** ако на стандартния вход бъде подадена последователността от символи **​c d** 5 | ```bash 6 | br=1 7 | br=`expr $br \* $2` 8 | a=$3 9 | set ab bc cd de 10 | shift 11 | while true 12 | do echo $* 13 | for j 14 | do 15 | if test $# -lt $br 16 | then 17 | br=` expr $br / 2` 18 | echo $br $j >> file 19 | else 20 | br=`expr $br + $a` 21 | echo $br $j >> file 22 | fi 23 | done 24 | break 25 | done 26 | read a1 a2 27 | while cat file | grep $a1 28 | do echo $a $a2 29 | wc -l file 30 | tail -5c file 31 | exit 32 | echo FIN 33 | done 34 | echo $a $a1 35 | wc -c file 36 | tail -2l file 37 | ``` 38 | 2. Да се състави командна процедура, която получава при стратиране в командния ред акаунти на потребители. За всеки от подадените акаунти, които са в сесия да се изведе информация от файла /etc/passwd 39 | 3. Да се състави командна процедура, която получава като параметри в командния ред при стартиране акаунти на потребители. Чете от стандартния вход символен низ го изпраща на всеки от подадените потребители, които са активни в текущия момент. 40 | 4. Да се състави командна процедура, която получава като параметри в командния ред име на директория и акаунт на потребител. Процедурата намира общия размер на всички файлове в подадената директория и изпраща получената информация на потребителя с подадения акаунт, в случай че той е стратирал сесия. 41 | 5. В текущата директория се намира файл ff със съдържание символен низ. Да aсе състави командна порцедура, която получава три позиционни параметъра – две имена на директории и един символен низ. Ако не е подаден символен низ се взима низа, от посочения по-горе файл. Процедурата прехвърля всички файлове от текушата директория с разщирение .с в първата подадена директория, а тези с разширение .out във втората. Извежда на стандартния изход с подходящо съобщение общия брой на непрехвърлените файлове. 42 | -------------------------------------------------------------------------------- /week10/README.md: -------------------------------------------------------------------------------- 1 | ## Задачи 2 | 1. Да се състави командна процедура, която получава при стартиране от командния ред име на потребител, число и имена на съществуващи текстови файлове. Ако потребителят с подадения акаунт е стартирал сесия и е разрешил получаване на съобщения, процедурата му изпраща с подходящо съобщение броя подадени файлове. Премества онези от подадените файлове, чието разширение е .c и са разрешени за четене или писане в директория c_sources, поддиректория на началната потребителска директория. Извежда с подходящо съобщение броя на останалите. 3 | 4 | **Забележка:** За да видите дали потребител е позволил писане използвайте `who -T` (във втората колонка трябва да има +, ако потребителя е разрешил писане). 5 | 6 | 2. Текстов файл с име comproc1 съдържа зададената последователност от команди на bash за Linux. Напишете какво ще бъде изведено на стандартния изход и защо след като бъде стартиран файла с команден ред **bash comproc1 xy ab cd ef**, а от стандартния вход бъде подадена последователността от символи: **1 2** 7 | ``` 8 | count=1; shift 9 | for i in 5 1 4 2 10 | do 11 | for j 12 | do 13 | if test $i -ge $# 14 | then 15 | count=`expr $count \* $i` 16 | else 17 | while true 18 | do echo $* ; break 3 ; done 19 | 20 | fi 21 | done; done 22 | read k1 k2 23 | while grep $k1 f1 24 | do 25 | set $k1 $count 26 | echo $? ; echo $2 ; echo $1 $i 27 | exit 28 | wc -w f1 29 | done 30 | tail -2l f1 ; echo FIN 31 | ``` 32 | **Забележка:** Когато имаме само for i без in това означава, че loop-ваме през позиционните параметри 33 | 34 | 3. Да се напише командна процедура, която получава в командния ред при стартиране име на потребител (ако няма, подразбира се текущия) и число (ако няма подразбира се 10000). Процедурата прочита от стандартния вход име на файл. Пуска във фонов режим безкраен цикъл, който на всяка една минута добавя във файла дата и час, както и отношението на броя на всички процеси в системата към процесите на дадения потребител. Ако отношението се е увеличило, то прекратява последните 10 процеса на текущия потребител. Ако отношението е намаляло или е останало същото, добавя всички процеси във файла. 35 | Ако броя на редовете надвиши подаденото като втори агрумент число, то се прекъсва безкрайния цикъл и се извежда подходящо съобщение. 36 | 37 | **Забележка:** за да спрем даден процес за някакво време използваме sleep n, където n е броят секунди. 38 | -------------------------------------------------------------------------------- /week13/README.md: -------------------------------------------------------------------------------- 1 | # Упражнение - командни процедури на Bash 2 | 3 | 1. (ДИ Информатика 2008) Текстов файл с име comprocB съдържа зададената по-долу последователност от команди на bash за Linux. Да се напише какво ще бъде изведено на стандартния изход след стартиране на файла с команден ред: **bash comprocB b1 b2 b3**, ако на стандартния вход бъде подадена следната последователност от символи: **b2** 4 | 5 | ```Bash 6 | if test –z $5 7 | then echo $1 8 | for var 9 | do echo $var >> fniz 10 | done 11 | else 12 | echo $2 13 | while true 14 | do echo LOOP 15 | break 16 | done 17 | fi 18 | cat fniz 19 | read string 20 | until cat fniz | grep $string 21 | do 22 | set $2 b1 23 | echo `grep $2 fniz ` 24 | echo END 25 | exit 26 | done 27 | set $3 $1 1 28 | echo OK $3 29 | echo `grep $1 fniz` 30 | exit 31 | echo OK 32 | ``` 33 | 2. Да се състави командна процедура, която получава в командния ред при стартиране един параметър – символен низ. Ако несъшествува директория с подаденото име в началната потребителска директория, процедурата я създава. Копира в тази директория всички обикновени файлове от текушата директория, които са достъпни за четене и писане и извежда на стандартния изход броя на останалите. 34 | 35 | 3. Да се състави командна процедура, която получава като параметри в командния ред име на директория, акаунт на потребител и имe на съществуващ файл. Да се изведе броят на всички файлове с име, което се взима от първите 6 символа от третия ред на подадения файл, чиито собственик е подедения потребител в цялата файлова система с корен подадената директория. 36 | 37 | 4. Да се състави командна процедура, която приема като параметър в командния ред име на потребител и име файл. Взима от последния ред на подадния файл думата от началото на реда до първото срещане на символа 1 и проверява дали във файловата система с корен родителската директория на началната потребителска директория има файлове в указаното име и ако да –извежда на екрана броя им, а ако не – изпраща подходящо съобщение на потребителя подаден като параметър. 38 | 39 | 5. Да се състави командна процедура, която получава в командния ред при стартиране един параметър – име на съществуваща директория. За всеки файл в тази директория съдържащ програма на Си, процедурата стартира компилация във фонов ражим, задавайки за име на получавания при успешна компилация изпълним файл основното име на текстовия файл и разширение .exe. 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # OperatingSystems_2019-2020 3 | Notes on basic shell commands, bash scripting and C code for the Operating Systems course 2019-2020 at @fmi 4 | 5 | ## Съдържание 6 | 7 | - [Работа с файловата система в Linux](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week1) 8 | 9 | - [Команди за работа с файлове](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week2) 10 | 11 | - [Информационни команди. Команди за многопотребителския режим, комуникация. Команди за работа с процеси. Пренасочване на вход/изход. Конвейер между процеси.](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week3-4) 12 | 13 | - [Метасимволи и генериране на имена на файлове. Стартиране във фонов дял.](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week5) 14 | 15 | - [Променливи - дефиниране, инициализиране, присвояване. Системни променливи. Profiles.](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week6) 16 | 17 | - [Редактор vi](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week7) 18 | 19 | - [Командни процедури, командни процедури с позиционни параметри](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week8) 20 | 21 | - [Командни процедури - Условия и цикли](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week9) 22 | 23 | - [Системни примитиви за работа с файлове в Linux](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week11) 24 | 25 | - [Системни примитиви за работа с процеси в Linux](https://github.com/carolinepetrova/OperatingSystems_2019-2020/tree/master/week12) 26 | 27 | 28 | 29 | ## Линукс среда 30 | На упражнения ще ползвате PuTTy, чрез което ще се свързвате до сървъра, на който ще работите. Той е достъпен **само** в мрежата на ФМИ. 31 | 32 | Ако PuTTy не ви харесва, може да се свързвате със сървъра чрез SSH (протокол за сигурна връзка към отдалечен сървър). Естествено, командата е вградена в Linux/MacOS, за Windows трябва да се свали допълнително и да се използва PowerShell. 33 | 34 | **Как да използваме SSH:** 35 | 36 | В терминала пишем 37 | `ssh s81xxx@os-server.fmi.uni-sofia.bg`, където израза преди @ е вашето потребителско име, а след @ е името или IP-то на сървъра (на сървъра на ФМИ IP адреса е 62.44.100.23) и натискаме Enter. След това ще ви даде да си въведете паролата. 38 | 39 | За да се упражнявате вкъщи може да: 40 | 41 | - си инсталирате Linux :) 42 | 43 | - ако сте на MacOS просто отваряте терминала и сте вие. 44 | 45 | - Ако сте на Windows има няколко варианта: 46 | 47 | -- Подкарвате си виртуална машина 48 | 49 | -- От Microsoft Store си сваляте и инсталирате [това](https://www.microsoft.com/en-us/p/ubuntu/9nblggh4msv6?activetab=pivot:overviewtab), което ви позволява да пишете bash команди под Windows. 50 | 51 | -------------------------------------------------------------------------------- /week5/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Метасимволи и генериране на имена на файлове. Стартиране във фонов дял. 3 | ## Метасимволи 4 | WAT? - Метасимволите са символи със специално значение за shell. 5 | 6 | Метасимволи, с които сте се запознали до сега: 7 | 8 | |Символ|Значение | 9 | |--|--| 10 | | > | Пренасочване на изхода (пренаписва) | 11 | | >> | Пренасочване на изхода (закача) | 12 | | < | Пренасочване на входа | 13 | | \| | Конвейер. Изхода на една команда става вход на друга | 14 | 15 | ## Генериране на имена на файлове с метасимволи 16 | 17 | |Символ|Значение | 18 | |--|--| 19 | | * | нула или повече символи | 20 | | ? | точно един символ | 21 | | [] | някой символ измежду тези в скобите | 22 | | [^]| всичко друго освен това в скобите | 23 | 24 | Примери: 25 | 26 | - `а*` - всичко, което започва с а 27 | 28 | - `??*` - всичко, което има поне два символа в името си 29 | 30 | - `[a-c]*` - всичко, което започва с a,b или c 31 | 32 | - `[afs]?` - всичко, което започва с a,f или s и съдържа точно 2 символа 33 | 34 | - `[a-z][0-9].txt` - текстови файлове, съдържащи се точно от 2 символа - първият е буква, вторият е цифра 35 | 36 | ## Escape-ване на метасимволи 37 | Понякога не искате метасимволите да имат специално значение. Примерно ако ви се наложи да умножите нещо използвайки само `*` няма да се получи. 38 | 39 | За да премахнем специалното значение на метасимволите поставяме `\` пред тях. Примерно: `\?`, `\*`, `\>` ... 40 | 41 | В стрингове не е нужно да използвате навсякъде `\` за да escape-нете метасимволите: 42 | 43 | - Единичните кавички `' '` - защитават всички символи без \ 44 | 45 | - Двойните кавички `" "` - защитават всичко, без \, $ и ` 46 | 47 | ## Стартиране на процес във фонов режим 48 | 49 | Понякога като стартирате процес, терминала ви става "завладян" от него и не можете да продължите работата си с него, а като затворите терминала убивате процеса. Това налага използването на фонов режим за процес. 50 | 51 | За да стартирате процес във фонов режим просто пишете `&` в края на командата. 52 | 53 | Пример: `vim &` Когато изпълните vim без амперсант влизате в текстовия редактор vim. С амперсанта терминала ви остава свободен, като се изписва само pid-то на стартиралия процес. 54 | 55 | За да върнете процес, който сте изпратили във фонов режим ползвате `fg`. 56 | 57 | За да спрете процес във фонов режим използвате `kill` и pid на процеса. 58 | 59 | ### Други метасимволи (ще ги използваме следващия път) 60 | |Символ|Значение | 61 | |--|--| 62 | | \`cmd\` | Субституция на команда | 63 | | $(cmd) | Субституция на команда | 64 | | ; | Последователност от команди | 65 | | \#| Коментар | 66 | |$|достъпва стойността на променлива| 67 | 68 | 69 | ## Задачи: 70 | 1. Създайте директория copied и преместете всички файлове от текущата директория, които са с поне 2 символа, като първия е а,h или f. След това изтрийте всички файлове в директорията copied. 71 | 2. Колко файла, започващи с буква a-c и завършващи с d-e имате в цялата файлова директория? 72 | 3. Проверете дали всички файлове с разширение txt и с поне един символ в текущата ви директория са само текстови файлове 73 | -------------------------------------------------------------------------------- /week1/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Работа с файловата система в Linux 3 | Но преди това ... 4 | ## Малко знания 5 | **Операционна система** - основният софтуер, който управлява целия хардуер и друг софтуер на компютър. 6 | 7 | **Команден интерпретатор (shell)** - Още наричан обвивка; Осигурява връзката между потребителя и ядрото на операционната система 8 | 9 | **Bash vs Shell** - Bourne Shell е оригиналния команден интерпретатор в UNIX. Bash е също команден интерператор, който е написан за да замести Bourne Shell. 10 | 11 | **Логическо включване и изключване** - преди да започнем работа, трябва да се "логнем" към сървъра, което става, като напишем нашето потребителско име и парола. Ако сме се логнали успешно системата извежда т.нар prompt ($ в UNIX) и можем да започнем работа. След като приключим работа можем да използваме `logout` 12 | функцията, за да прекратим сесията ни. 13 | 14 | **Сигнатура на командите** 15 | `cmd [-oпции] [аргументи]` 16 | Като най-добрия ви приятел по ОС e `man` командата. Тя ви дава информация за всяка команда и нейните опции. 17 | 18 | `man cmd` 19 | 20 | ## Нека продължим 21 | Linux се характеризира с това, че в него "всичко е файл". Файловете се групират в директории, които могат също така да съдържат други поддиректории и така се сформира дървовидната файлова структура. 22 | 23 | ![](http://newkis.fmi.uni-sofia.bg/~svi/os/ex/fs.gif) 24 | 25 | Така изглежда част от файловата система, с която ние ще работим. (Вашите акаунти ще се намират в students директорията). 26 | 27 | Коренът на това дърво се нарича главна директория (root directory) и се бележи с наклонена черта. 28 | 29 | Първоначално като се логнем ние се намираме в нашата начална потребителска директория (в случая /home/students/student). 30 | 31 | ## Абсолютен vs относителен път 32 | **Aбсолютен път** - този път, който започва от коренната директория (/), т.е. ако искаме да изпишем абсолютния път до файл/директория трябва да започнем с / и да изпишем всички директории. през които се преминава, за да се достигне до файла/директорията. 33 | 34 | **Относителен път** - Когато се използва относителен път Linux счита, че пътя започва от текущата директория (тази в която се намираме в момента). 35 | Например ако имаме директорията main, в нея имаме директориите dir1 dir2 dir3 и сме в /main/dir1, за да преминем от dir1 в dir3 трябва да използваме `../dir3` 36 | 37 | ### Забележка 38 | С `.` се означава текуща директория, а с `..` се означава предишната (родителска) директория. 39 | 40 | ## Команди за работа с файловата система 41 | 1. `pwd` - дава абсолютния път на директорията, в която се намираме в момента. 42 | 2. `date` - дава ни системната дата 43 | 3. `cd` - чрез cd сменяме директорията. Можем да направим това чрез относителен или абсолютен път до директорията. 44 | -- `cd /home/students/student/aa` 45 | -- `cd` без аргумент ни води към началната ни потребителска директория 46 | 4. `ls` - тази команда без аргументи ни дава съдържанието на текущата директория (само имената на файловете). Също така, ако искаме да видим съдържанието на друга директория без да сменяме текущата можем да направим `ls dirpath`. 47 | Oпции, които ще използваме: 48 | 49 | -- `-l` подрежда файловете в списък, като ни дава и повече информация за файловете. 50 | 51 | -- `-a` извежда освен всички файлове и скритите (скритите са тези с точка пред името си) 52 | 53 | -- `-lh` извежда информацията за файловете в human-readable format 54 | 55 | **Какво забелязваме като изпълним ls -l** 56 | 57 | След като изпълним `ls -l` в първата колона се появяват правата за достъп на файла: 58 | 59 | - На първата позиция имаме `-` или `d`, което съответно ни индикира, че това е файл или директория. 60 | - Следващите три тройки от символи съответно ни индикират правата за четене ( r ), писане ( w ) и изпълнение ( x ) за текущия потребител, групата, в която се намира и останалите потребители. Ако някое право е забранено съответно на мястото му присъства `-`. 61 | -------------------------------------------------------------------------------- /week6/README.md: -------------------------------------------------------------------------------- 1 | # Променливи - дефиниране, инициализиране, присвояване. Системни променливи. Profiles. 2 | 3 | Имената на променливите в bash се състоят от букви, цифри и "_" като **не** могат да започват с цифра. Типът на една променлива е символен низ, затова декларирането й не е задължително (стойността е празен низ). 4 | 5 | ### Присвояване на стойност на променлива 6 | - чрез оператора за присвояване `променлива=[стойност]` 7 | 8 | Пример: 9 | 10 | num=12345 11 | str=hello 12 | long_str="hello world" 13 | 14 | От миналия път: 15 | 16 | Ако симолния низ е заграден с двойни кавички (" ") то то се показват всички метасимволи без \`, $ и \ 17 | 18 | Ако символния низ е заграден от единични кавички (' ') то то се показват всички метасимволи без \ 19 | 20 | - чрез командата read: `read [име/на на променлива/и] 21 | Чете се един ред от стандартния вход и се разделя на думи (разделителя е интервал) като всяка дума се съпоставя на съответната променлива. 22 | 23 | ### Извеждане на стойност на променлива 24 | Извеждането на стойността на променливата става като поставим символа "$" пред нея. 25 | 26 | Примери: 27 | 28 | x=123 29 | echo $x 30 | name="Pesho" 31 | echo "My name is $name" 32 | 33 | 34 | ### Command Substitution 35 | Позволява изхода на командата да замени самата команда. За да задействаме субституцията използваме \`command\` или $(command) 36 | 37 | Примери: 38 | 39 | path=`pwd` или path=$(pwd) 40 | name=`whoami` или name=$(whoami) 41 | count=`who | wc -l` или count=$(who | wc -l) 42 | 43 | Могат да бъдат и вложени 44 | 45 | 46 | num=$(ps aux | grep $(whoami) | wc -l) 47 | 48 | И тука ко прайм??? 49 | ``` 50 | s=123 51 | echo "hello $( s=world; echo "$s" )" 52 | echo "$s" 53 | ``` 54 | 55 | ### Команди за променливи 56 | - echo 57 | 58 | - set - показва всички дефинирани променливи и техните стойноти 59 | 60 | - `unset променлива1 ...` - изключва дадена променлива от обкръжението на процеса 61 | 62 | - `export променлива1 ...` - указаните променливи стават видими за процесите-деца (процесите, породени от текущия процес) 63 | 64 | ### Аритметични изчисления 65 | Осъществяват се чрез командата **expr** 66 | 67 | **Какво прави expr?** 68 | Изчислява се значението на подадения целочислен израз и резултатът се извежда на стандартния изход. Изразът се конструира цели числа, променливи и целочислените аритметични операции: +, -, *, /, %. 69 | 70 | Примери: 71 | 72 | expr 2 + 1 //stdout 3 73 | x=5 74 | expr $x - 1 //stdout 4 75 | expr $x * 2 // stdout ??? 76 | expr $x \ 2 // stdout ??? 77 | 78 | 79 | Можем да присвояваме резултата към променливи 80 | 81 | 82 | result=`expr 5+1` 83 | broi=$(expr $(ls -l | wc -l) - 1) 84 | ### Работа със символни низове 85 | - `expr length низ` - дава ни дължината на низа 86 | 87 | - `expr index низ символи` - дава ни позицията на първото срещане на някои от символите, които сме указали 88 | 89 | - `expr substr низ нач.позиция n` - извлича n на брой символа от дадения низ, започващ от нач.позиция 90 | 91 | ### Системни променливи 92 | По-важни променливи: 93 | 94 | - `HOME` - aбсолютният път към личната директория на потребителя 95 | 96 | - `PATH` - списъкът на директориите, където се търсят командите 97 | 98 | - `PS1` - първичен промпт 99 | 100 | - `PS2` - вторичен промпт 101 | 102 | - `USER` - името на текущия потребител 103 | 104 | - `SHELL` - абсолютният път на използвания команден интерпретатор 105 | 106 | Как да видим всички системни променливи? `printenv` 107 | 108 | Как да си дефинираме системна променлива? `export VARNAME=value` 109 | 110 | ### Инициализиращи командни процедури (profiles) 111 | 112 | Тези процедури се изпълняват автоматично при стартиран shell. 113 | Има няколко инициализиращи командни процедури, изпълняващи се от няколко вида shells: 114 | 115 | - Profiles за login shell процес 116 | 117 | - - **/etc/profile** 118 | 119 | Глобален profile. Изпълнява се първи, ако съществува. 120 | 121 | - След това се изпълнява **~/.bash_profile** или **~/.bash_login** или **~/.profile** - настройва се сесията на потребителя, стартирал логин процеса 122 | 123 | - Profiles за интерактивен не-login shell процес 124 | 125 | - изпълнява се **~/.bashrc** 126 | 127 | 128 | ## Задачи 129 | 1. Намерете броя на всички файлове, които са притежание на текущия потребител. 130 | 2. Прочетете файл от стандартния вход. Сортирайте го и изхода запишете в същия файл. 131 | 3. Прочетете файл и число от стандартния вход. Изведете на екрана n-тия ред на този файл. 132 | 4. Прочетете от стандартния вход два файла. Запишете в първия файл информация за всички потребители и какво правят в момента. Намерете размера на втория файл, умножете го по 2 и резултата запишете в първия файл без да изтривате съдържанието му. 133 | 5. Изрежете думата **from** от стринга "Hello from the other side" 134 | 6. Премахнете **Hello (и интервала след него)** от стринга "Hello from the other side" 135 | -------------------------------------------------------------------------------- /week11/README.md: -------------------------------------------------------------------------------- 1 | # Системни примитиви за работа с файлове в Linux 2 | 3 | **Как да компилираме C програма?** 4 | ``` 5 | cc file.c -o nameof_output_executable 6 | ``` 7 | 8 | **Какво е системен примитив?** 9 | 10 | Системните примитиви (системни извиквания (system calls)) са фундаменталния интерфейс между програма и ядрото на Linux-a (ядрото е програма, която предоставя основни услуги на другите програми). Т.е чрез системните примитиви ядрото предоставя услуги на приложните програми. 11 | 12 | **Защо на C?** 13 | 14 | Освен, че Linux e написан на С, за всеки системен примитив има поне една функция в стандартната библиотека на C. Ние ще пишем програми, които съдържат обръщения към тези функции. 15 | 16 | ## Oсновни понятия 17 | **Файлов дескриптор** - Неотрицателно цяло число, което служи за уникален идентификатор на отворен файл. Файловите дескриптори имат локално значение за процесите – всеки процес разполага с N файлови дескриптора. Всеки процес стандартно има отворени три дескриптора: 18 | - 0 (стандартен вход) 19 | 20 | - 1 (стандартен изход) 21 | 22 | - 2 (стандартен изход за грешки) 23 | 24 | **Текуща позиция във файл** (**file offset**) - Определя позицията на файла за четене и писане (един указател за двете действия). 25 | 26 | **Режим на отваряне** - Указва режима, в който е отворен даден дескриптор. Това може да е четене, писане, четене и писане. 27 | 28 | ## Системни примитиви за работа с (обикновени) файлове 29 | 30 | ### Създаване на файл 31 | ``` 32 | int creat(const char *filename, mode_t mode); 33 | ``` 34 | 35 | - Създава обикновен файл с име **filename** с режим **mode**. 36 | 37 | - Връща дескриптора на файла или -1 при грешка. 38 | 39 | Ако такъв файл вече съществува, то старото му съдържание се унищожава при условие, че процесът има право за писане във файла. Създаденият файл се отваря само за писане и creat връща файлов дескриптор свързан с файла. 40 | 41 | 42 | ### Отваряне на файл 43 | ``` 44 | #include 45 | int open(const char *filename, int oflag [, mode_t mode]); 46 | ``` 47 | 48 | - Отваря файл с име **filename** в режим **oflag**, а ако не съществува го създава с режим **mode**. 49 | 50 | - връща файловия дескриптор или -1 при неуспех 51 | 52 | **oflag** указва режима на отваряне и/или действия, които да се извършат след отваряне: 53 | 54 | - O_RDONLY - само за четене 55 | 56 | - O_WRONLY - само за писане 57 | 58 | - O_RDWR - за четене и писане 59 | 60 | - O_CREAT - създава файла 61 | 62 | - O_EXCL - заедно с O_CREAT: ако файлът **не съществува**, той се създава, иначе се връща грешка 63 | 64 | - O_TRUNC - старото съдържание на файла се изтрива след отваряне 65 | 66 | - O_APPEND - старото съдържание се запазва, а новото се вписва в края на файла 67 | 68 | - O_SYNC - всяко писане е синхронно 69 | 70 | 71 | ### Четене от файл 72 | 73 | ``` 74 | #include 75 | ssize_t read(int _fildes_**, void ***_buf_**, size_t** _nbyte_**); 76 | ``` 77 | - **fd** - номер на файлов дескриптор 78 | 79 | - **buffer** - указател към областта от програмата, където се записват данните 80 | 81 | - **nbytes** - указва броя байтове за четене 82 | 83 | - връща броя на **реално** прочетените байтове, иначе връща -1 84 | 85 | ### Писане във файл 86 | 87 | ``` 88 | ssize_t write(int fd, void *buffer, size_t nbytes); 89 | ``` 90 | - **fd** - номер на файлов дескриптор 91 | 92 | - **buffer** - указател към областта от програмата, където се записват данните 93 | 94 | - **nbytes** - указва броя байтове за писане 95 | 96 | - връща броя на **реално** записаните байтове, иначе връща -1 97 | 98 | ### Позициониране във файл 99 | 100 | ``` 101 | off_t lseek(int fd, off_t offset, int flag); 102 | ``` 103 | 104 | - **fd** - номер на файлов дескриптор 105 | 106 | - **offset** - самото отместване 107 | 108 | - **flag** - указва как се интерпретира отместването 109 | 110 | - **SEEK_SET** - премества указателя от началото до offset-байта 111 | 112 | - **SEEK_CUR** - премества указателя от сегашната му позиция до offset-байта 113 | 114 | - **SEEK_END** - премества указателя от края на файла (отзад-напред) до offset-байта (отрицателно число) 115 | 116 | **Как да намерим къде се намира указателя в момента?** 117 | 118 | ``` 119 | lseek(fd, 0, SEEK_CUR); 120 | ``` 121 | 122 | **Как да намерим размера на файла? ** 123 | 124 | ``` 125 | lseek(fd, 0, SEEK_END); 126 | ``` 127 | 128 | ### Затваряне на файл 129 | 130 | ``` 131 | int close(int fd); 132 | ``` 133 | 134 | ## Задачи: 135 | 1. Реализирайте cp командата т.е приема от командния ред имена на 2 файла и копира съдържанието на първия във втория. 136 | 2. Чете последователност от символи от стандартния вход. Записва ги във файл, чието име е подадено като първи параметър. Замества символите за табулация с '>>>' и резултата извежда на стандартния изход за грешки. 137 | 3. Чете последователност от символи от файл, чието име е подадено като първи параметър. Извежда ги на стандартния изход. Първите 3 символа от всеки ред добавя след края на файл, чието име е подадено като втори параметър. 138 | -------------------------------------------------------------------------------- /week8/README.md: -------------------------------------------------------------------------------- 1 | # Командни процедури, командни процедури с позиционни параметри 2 | ### Какво е командна процедура? 3 | - поредица от команди, поместена в текстов файл. 4 | 5 | ### Какво е специфично за тях? 6 | - командната процедура се изпълнява в отделен subshell, който се поражда от терминала, от който е извикана. 7 | 8 | - Когато процедурата приключи, тя има код на приключване (число от 0 до 255), като той може да бъде указан явно чрез `exit код`. 9 | 10 | - ако използваме exit без параметър, то кодът на завършване на КП = кода на завършване на последната изпълнена команда преди exit. 11 | 12 | - Ако не е указан exit, то кодът на завършване е кодът на **последно изпълнената** команда от КП. 13 | 14 | - коментарите на един ред се означават с # 15 | 16 | ### Как да изпълним командна процедура? 17 | 18 | 1.Aко нямаме права за права за изпълнение 19 | 20 | `bash path-to/command_procedure` 21 | 22 | `bash -x path_to/command_procedure` - дава ни информация кои команди се изпълняват 23 | 24 | 2. Добавяме право за изпълнение: 25 | 26 | `chmod a+x path_to/command_procedure` 27 | 28 | И за да изпълним командната процедура изписваме абсолютния й път 29 | 30 | ### Защо в някои командни процедури има ` #!/bin/bash`? 31 | 32 | Чрез `#! path_to_interpreter` задаваме кой команден интерпретатор да използваме при изпълняване на командната процедура. 33 | 34 | **Пример:** 35 | 36 | `#!/bin/csh` - използваме C shell интерпретатора 37 | 38 | `#!/usr/bin/python3` - използваме python3 интерпретатор 39 | 40 | **Забележка:** 41 | 42 | Този ред сe изпълнява **само** ако сме изпълнили файла по този начин: `./script_name` 43 | 44 | ### Каква е разликата между ` #!/bin/bash` и ` #!/bin/sh`? 45 | 46 | От първото упражнение знаем че Shell и Bash са различни командни интерпетатори. Но в повечето ОС `/bin/sh` е **символна връзка**, която няма да "събуди" шел интерпретатора, а ще изпълни това, с което е свързана. 47 | 48 | 49 | ## Комадни процедури с позиционни параметри 50 | 51 | Когато изпълняваме една командна процедура, можем да и дадем и някакви параметри: 52 | 53 | `./our_script param1 param2 ...` 54 | 55 | ### Как да ги достъпим в нашата командна процедура? 56 | 57 | Командният интерпретатор присвоява тези параметри на специални **системни променливи** 0, 1, 2 ... като всяко число n отговаря на n-тия подаден позиционен параметър. 58 | 59 | !!! $0 винаги пази името на командата 60 | 61 | Така ако изпълним командната процедура our_script по този начин: 62 | 63 | `./our_script param1 param2 param3` 64 | 65 | То позиционните параметри ще за запазени по този начин: 66 | 67 | ``` 68 | еcho $0 # our_script 69 | echo $1 # param1 70 | echo $2 # param2 71 | echo $3 # param3 72 | ``` 73 | 74 | ### Как можем да получим повече информация за позиционните параметри? 75 | 76 | - `*` - дава символен низ с параметрите от командния ред 77 | 78 | - `@` - дава масив с параметрите от командния ред 79 | 80 | - `#` - дава броя на параметрите от командния ред 81 | 82 | Следователно относно по-горния пример: 83 | ``` 84 | еcho $* # param1 param2 param3 85 | echo $@ # param1 param2 param3 86 | echo $# # 3 87 | ``` 88 | 89 | **Каква друга информация можем да получим в КП?** 90 | - `$` - PID на текущия процес 91 | 92 | - `?` - код на завършване на последния завършил процес 93 | 94 | - `!` - PID на последния завършил процес във фонов режим 95 | 96 | ### Променяне на стойностите на 0, 1, 2 ... 97 | 98 | 1. В нашата командна процедура можем да променим стойностите на променливите 0, 1, 2 ... 99 | 100 | Използваме командата `set new_pos_arg1 new_pos_arg2` 101 | 102 | Съответно ако сме имали: 103 | 104 | `echo $1 $2 $3 # param1 param2 param3` 105 | 106 | Ако някъде в КП имаме: 107 | 108 | `set new1 new2` 109 | 110 | то 111 | 112 | `echo $1 $2 $3 # new1 new2` 113 | 114 | 2. Също така можем да "преместваме" стойностите на позиционните параметри наляво 115 | 116 | `shift n` - измества стойностите на позиционните параметри с n позиции наляво 117 | 118 | Съответно ако: 119 | 120 | `echo $1 $2 $3 # param1 param2 param3` 121 | 122 | и някъде в КП сме изпълнили 123 | 124 | `shift 2` 125 | 126 | то `echo $1 $2 $3 # param3` 127 | 128 | ## Задачи 129 | 0. Да се напише командна процедура, която получава при стартиране име на файл и име на потребител. Сортира лексикографски файла и изпраща съдържанието му на подадения потребител. 130 | 1. Да се напише командна процедура, която получава при стартиране два позиционни параметъра - имена на файлове. Конкатенирайнте съдържанието на двата файла и го запишете в трети, чието име сте прочели от стандартния вход. 131 | 2. Да се състави командна процедура, която получава като параметри в командния ред при стартиране имена на съществуващи текстови файлове. Процедурата прочита от стандартния вход символен низ и за всеки от зададените файлове извежда по подходящ начин на стандартния изход броя на редовете, които съдържат низа. 132 | 3. Да се напише shell скрипт, който приканва потребителя да въведе пълното име на директория и извежда на стандартния изход подходящо съобщение за броя на всички файлове и всички директории в нея. 133 | 4. Да се напише shell скрипт, който чете от стандартния вход име на файл и символен низ, проверява дали низа се съдържа във файла и извежда на стандартния изход кода на завършване на командата с която сте проверили наличието на низа. 134 | -------------------------------------------------------------------------------- /week7/README.md: -------------------------------------------------------------------------------- 1 | # Редактор vi. 2 | Редакторът Vi (съкращение от visual) е един от най-популярните текстови редактори в Linux света. Можете да го намерите във всички Unix ОС, като той работи по един и същ начин на тях. 3 | 4 | ## Стартиране 5 | 6 | - `vi <нов_файл/съществуващ_файл>`- ако файлът съществува го отваря за редактиране, иначе може да създадете нов файл 7 | 8 | - може да стартирате vi и без да му подавате име на файл и да пишете информация в редактора. Тук разликата е, че при записването трябва да укажете име на файла. 9 | 10 | ## Режим на работа 11 | Vi има два режима на работа - команден режим (command mode) и въвеждащ режим (insert mode). 12 | 13 | ### Команден режим 14 | При стартиране на Vi винаги влизате в този режим. Тук можете само да изпълнявате команди, чрез които да , движите курсора и да копирате, поставяте и изрязвате текст. 15 | 16 | ### Въвеждащ режим 17 | Като влезете във въвеждащ режим вече можете да пишете и триете, като всичко се третира като "набор на текст", който накрая (ако желаете) се записва във файл. 18 | 19 | 20 | ## Команди на редактора vi 21 | 22 | ### Навигация (движение на курсора) 23 | - k - премества курсора нагоре (може да се използва стрелка нагоре) 24 | 25 | - j - премества курсора надолу (може да се използва стрелка надолу) 26 | 27 | - h - премества курсора наляво (може да се използва стрелка наляво) 28 | 29 | - l - премества курсора надясно (може да се използва стрелка надясно) 30 | 31 | - b - към първия символ на думата 32 | 33 | - е - към последния символ на дума 34 | 35 | - w - към първия символ на следващата дума 36 | 37 | - 0 - към началото на текущия ред 38 | 39 | - ^ - към първият символ от текущия ред 40 | 41 | - $ - към последния символ на текущия ред 42 | 43 | - Enter - премества курсора на първия символ на следващия ред 44 | 45 | - nG - премества курсора на n-тия ред. Само G премества курсора на последния ред 46 | 47 | ### Движение по екрани 48 | 49 | - CTRL+d - Придвижва се напред с половин екран. 50 | - CTRL+f - Придвижва се напред с един екран. 51 | - CTRL+u - Придвижва се назад с половин екран. 52 | - CTRL+b - Придвижва се назад с един екран. 53 | 54 | 55 | ### Въвеждане на текст 56 | 57 | Когато въведем тези команди влизаме в режим на въвеждане 58 | 59 | - i - въвеждане преди мястото на курсора 60 | 61 | - a - въвеждане след мястото на курсора 62 | 63 | - A - въвеждане в края на реда 64 | 65 | - o - добавя нов, празен ред след текущия 66 | 67 | - О - добавя нов, празен ред преди текущия 68 | 69 | - ESC - прекратява въвеждащия режим 70 | 71 | ### Промяна на текст 72 | - r - заменя символа, на който се намира курсора 73 | 74 | - R - заменя, колкото символи въведем 75 | 76 | - cw - променя думата от текущото положение на курсора до края на думата 77 | 78 | - c^ - променя думата от текущото положение на курсора до първия символ на реда 79 | 80 | - c$ - променя думата от текущото положение на курсора до последния символ на реда 81 | 82 | - cc - изменя целия ред, на който се намираме 83 | 84 | - u - премахва последната промяма 85 | 86 | - U - премахва абсолютно всички промени 87 | 88 | ### Изтриване на текст 89 | 90 | - x - изтрива символа, на който се намира курсора 91 | 92 | - dw - изтрива дума от позицията, на която се намира курсора до края 93 | 94 | - d^ - изтрива всичко от позицията на курсора до първия символ на реда (включително) 95 | 96 | - dd - изтрива редът, на който се намира курсора 97 | 98 | - d$ - изтрива всичко от позицията на курсора до последния символ на реда (включително) 99 | 100 | **Промяната и изтриването на текст може да се извърши върху няколко символа/думи/редове, като укажете число, примерно** 5dd, 5x,5c, d5w 101 | 102 | ### Koпиране и поставяне в текст 103 | 104 | - yw - копира думата 105 | 106 | - yy - копира ред 107 | 108 | - p - поставя копираните символи 109 | 110 | **Примери:** 111 | 112 | 5yw (или y5w) - копира следващите 5 думи 113 | 114 | yy и 5p - копира текущия ред и го поставя 5 пъти 115 | 116 | ### Преместване в текст 117 | 118 | - dw + p - преместване на дума 119 | 120 | - dd + p преместване на ред 121 | 122 | 123 | ### Tърсене в текст 124 | - /низ - търсене на низ надолу от текущия ред във файла 125 | 126 | - ?низ - търсене на низ нагоре от текущия ред във файла 127 | 128 | - n - търсене на следващ резултат в същата посока 129 | 130 | - N - търсене на следващ резултат в предишната посока 131 | 132 | ### Запис и изход от vi 133 | ![enter image description here](https://miro.medium.com/max/800/1*vhsWW0X4IZpq1B1bUA4awg.jpeg) 134 | 135 | JK 136 | 137 | - :w - записва промените във файла. Aко сме отворили редактора без да указваме име на файл трябва да го укажем тук. 138 | 139 | - :q - излиза от редактора 140 | 141 | - :q! - излиза от редактора без да запише промените 142 | 143 | - :wq - записване и изход 144 | 145 | - :e file - започва редактирането на нов файл 146 | 147 | - :е! file - започва редактирането на нов файл, без да се запазват промените по стария редактиран 148 | 149 | - :r file - прочита файлът file и добавя съдържанието му след курсора 150 | 151 | ## Как да изпълним една командна процедура? 152 | 1.Aко нямаме права за права за изпълнение 153 | 154 | `bash path-to/command_procedure` 155 | 156 | `bash -x path_to/command_procedure` - дава ни информация кои команди се изпълняват 157 | 158 | 2. Добавяме право за изпълнение: 159 | 160 | `chmod a+x path_to/command_procedure` 161 | 162 | И за да изпълним командната процедура изписваме абсолютния й път 163 | 164 | ## Задачи: 165 | 1. Съставете командна процедура online, която изписва на стандартния изход текущата дата и броя на логнатите потребители. 166 | 2. Съставете командна процедура, която копира всички файлове с разширение .pdf от началната ви потребителска директория в новосъздадената от вас директория с име my_pdfs, която се намира в текущата директория. Изведете с подходящо съобщение колко са файловете в тази директория. 167 | -------------------------------------------------------------------------------- /week9/README.md: -------------------------------------------------------------------------------- 1 | # Условия и цикли 2 | 3 | **Каква е разликата?** 4 | 5 | If, while и until проверяват изходното състояние на команда. Ако то е нула командите в телата им се изпълняват. 6 | Т.е ако условието ви е: 7 | ``` if ls -l somedir ``` 8 | ако изходния код на командата е 0, то то ще се изпълни това, което е в тялото на if-a. 9 | 10 | **Забележка:** if, while, until не пренасочва стандартния изход на командата, която сте подали като "условие". Това означава, че резултатът на командата ще се изпринтира на стандартния изход. 11 | 12 | ## Командата test 13 | 14 | За да можем да правим промерки (каквито сме свикнали по принцип) използваме командата test. 15 | 16 | Синтаксис: `test <израз>` 17 | 18 | Особености: 19 | 20 | - командата не връща нищо, но има код на изход: 21 | 22 | - 0: истина (тестът е бил успешен) 23 | 24 | - 1: лъжа (тестът е бил неуспешен) 25 | 26 | 27 | - взимаме кода чрез $? 28 | 29 | - за сравняване на стойности главно се използват **опции**, а за низове се използват **oператори** 30 | 31 | ### Оператори и опции, които се използват за сравнения: 32 | 33 | | Сравняване за цели числа | Функция | 34 | |--|--| 35 | | -gt (greater than) | по-голямо от | 36 | | -lt (less than) | по-малко от | 37 | | -ge (greater or equal) | по-голямо или равно | 38 | | -le (less or equal) | по-малко или равно | 39 | | -eq (equal) | равно | 40 | | -ne (not equal) | неравно | 41 | 42 | | Сравняване на низове | Функция | 43 | |--|--| 44 | | -z | проверява за празен низ | 45 | | -n | проверява за непразен низ | 46 | | = | равни низове | 47 | | != | различни низове | 48 | | < и > | сравнява лексикографски низовете | 49 | 50 | | Проверки за файлове | Функция | 51 | |--|--| 52 | | -f | файлът съществува | 53 | | -s | файлът не е празен | 54 | | -d | файлът е директория | 55 | | -r | файлът може да се чете | 56 | | -w | във файлът може да се записва | 57 | | -x | файлът може да се изпълнява | 58 | 59 | | Логически оператор | Функция | 60 | |--|--| 61 | | ! | логическо отрицание | 62 | | -а | логическо И | 63 | | -o | логическо ИЛИ | 64 | 65 | 66 | **Пример:** 67 | ``` 68 | $ test value1 -option value2 69 | $ test string operator string 70 | ``` 71 | 72 | **За по-четлив и прост запис вместо командата test може да се използват квадратните скоби ([ ]).** Приемете, че "[" е "друго име" на командата **test**, затова, когато пишете проверка трябва да има място пред и зад [. Затварящата квадратна скоба играе роля на финален аргумент за "[". 73 | 74 | 75 | **Пример:** 76 | ``` 77 | $ [ value1 -option value2 ] 78 | $ [ string operator string ] 79 | ``` 80 | 81 | ## Условен оператор if 82 | 83 | **Синтаксис:** 84 | ``` 85 | if команда then 86 | действие (команда 2) 87 | [elif 88 | команда3 89 | then 90 | команда4] 91 | ... 92 | [else 93 | командаN] 94 | fi 95 | ``` 96 | **Пример:** 97 | ``` 98 | file=/etc/passwd 99 | if grep Georgi $file 100 | then 101 | echo "There are names containing Georgi in $file" 102 | else 103 | echo "No matches were found" 104 | fi 105 | ``` 106 | ``` 107 | read num1 num2 108 | if [ $num1 -eq $num2 ] 109 | then 110 | echo "Numbers from stdin are equal" 111 | elif [ $num1 -lt $num2 ] 112 | then 113 | echo " $num1 < $num2 " 114 | else 115 | echo " $num1 > $num2 " 116 | fi 117 | ``` 118 | 119 | ## Оператор за избор case 120 | 121 | **Синтаксис:** 122 | 123 | ``` 124 | case стойност in 125 | шаблон1 | шаблон2 | ...) 126 | команда 127 | ;; 128 | […] 129 | esac 130 | ``` 131 | 132 | **Пример:** 133 | 134 | Създаване на командна процедура, която по подадено име на държава от стандартния изход, дава информация, кой е официалният език на държавата. 135 | ```sh 136 | read country 137 | case $country in 138 | USA | UK | Australia ) 139 | echo "The official language of $country is English" 140 | ;; 141 | Romania | Moldova) 142 | echo "The official language of $country is Romanian" 143 | ;; 144 | China) 145 | echo "The official language of China is Mandarin" 146 | *) 147 | echo "We don't have data about $country 148 | ;; 149 | esac 150 | ``` 151 | 152 | ## Цикли 153 | 154 | ### while цикъл 155 | 156 | **Синтаксис:** 157 | ```sh 158 | while условие(команда) 159 | do 160 | команда1 161 | команда2 162 | команда3 163 | ... 164 | done 165 | ``` 166 | 167 | Пример: 168 | ```sh 169 | x=0 170 | while [ $x -le 5 ] 171 | do 172 | echo $x 173 | x=$(expr $x + 1) 174 | done 175 | ``` 176 | ### until цикъл 177 | **Синтаксис:** 178 | ```sh 179 | until условие(команда) 180 | do 181 | команда1 182 | команда2 183 | команда3 184 | ... 185 | done 186 | ``` 187 | **Пример:** 188 | ``` 189 | read user 190 | until who | grep $user 191 | do 192 | echo "Waiting for user $user to login" 193 | sleep 10 194 | done 195 | ``` 196 | 197 | **Каква е разликата между while и until?** 198 | 199 | Противоположни са си. While се изпълнява докато условието е вярно, а until се изпълнява, докато условието е грешно. 200 | 201 | ### for цикъл 202 | 203 | **Синтаксис:** 204 | ``` 205 | for променлива in [списък] 206 | do 207 | команда1 208 | команда2 209 | ... 210 | done 211 | ``` 212 | 213 | **Примери:** 214 | ``` 215 | for i in 1 2 3 4 5 216 | do 217 | echo $i 218 | done 219 | ``` 220 | Изход: 221 | 222 | 1 223 | 2 224 | 3 225 | 4 226 | 5 227 | 228 | ``` 229 | read user1 user2 user3 230 | file=/etc/passwd 231 | for user in $user1 $user2 $user3 232 | write $user < $file 233 | done 234 | ``` 235 | Изход: изпраща съдържанието на файла /etc/passwd на потребителите, прочетени от стандартния вход 236 | 237 | ``` 238 | x=1 239 | for args in $@ 240 | echo "command line argument $x is $args" 241 | x=$(expr $x + 1) 242 | done 243 | ``` 244 | Изход: принтира на стандартния изход позиционните параметри подадени на командната процедура 245 | 246 | ``` 247 | for i 248 | do 249 | echo $i 250 | done 251 | ``` 252 | е същото като 253 | ``` 254 | for i in $@ 255 | do 256 | echo $i 257 | done 258 | ``` 259 | ## break, continue и sleep 260 | 261 | ### break [n] 262 | - Прекъсва n-тият цикъл отвътре-навън 263 | 264 | - ако не е зададен n то се прекъсва цикъла, в който е сложен break 265 | 266 | ### continue [n] 267 | 268 | - skip-ват се всички команди след него и се продължава следващата итерация на n-тия цикъл отвътре-навън 269 | 270 | - ако не е зададен n то се продължава с 1 итерация напред 271 | 272 | ### sleep n 273 | 274 | Паузира процеса за n секунди 275 | 276 | 277 | ## Задачи: 278 | 1. Да се състави командна процедура, която получава при стартиране в командния ред два параметъра - имена на съществуващи файлове. В случай, че общият брой на файловете, съдържащи ASCII текст в двете директории надвишава 20, процедурата създава в текущата директория файл sources.txt съдържащ имената им, който да е достъпен само за четене от всички потребители. В противен случай извежда с подходящо съобщение броя на тези файлове. 279 | 2. Да се състави командна процедура, която получава в командния ред при стартиране един параметър - символен низ. Ако не съществува директория с подаденото име в началната потребителска директория, процедурата я създава. Копира в нея тези файлове от началната потребителска директория (само от там), чиито размер е по-голям от 50 байта като в същото време изписва името на копирания файл. 280 | 3. Да се напише командна процедура, който получава произволен брой аргументи файлове, които изтрива при дадени условия: 281 | Ако бъде подадена празна директория, тя бива изтрита. Ако подадения файл е директория с поне 1 файл, тя не се изтрива. 282 | За всеки изтрит файл (директория) скриптът добавя ред във файл с име logs с подходящо съобщение. 283 | -------------------------------------------------------------------------------- /week2/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Команди за работа с файлове и още команди за файлова система :)) 4 | 5 | **Но отново преди това** 6 | 7 | `echo "some nice string"` - принтира на терминала текста в кавичките (неочаквано, нали?) 8 | 9 | `echo -n "some nice string"` - прави същото, но не поставя нов ред (т.е. промп-та ще се залепи след това в кавичките), (да, полезно е, ще ви трябва за контролното, след 1-2 упражнения ще видите защо). 10 | 11 | ## Работа с файлове и директории 12 | 1. `cat file1 file2 ...` - показва съдържанието на файл/овете 13 | 14 | 2. `touch f1 f2 f3 ...` - създава празни файлове 15 | 16 | 3. `tee f1 f2 ...` - създава файловете f1 f2 и ни позволява да пишем в тях едновременно 17 | 18 | 4. `cp [source] [destination]` - копира файлове 19 | 20 | `cp f1 f2 f3 path_to_dir` - примерно използване 21 | 22 | Също така можем да го използваме да копираме съдържанието от един файл в друг: 23 | 24 | `cp f1 f2` - копираме съдържанието на f1 във f2 25 | 26 | 5. `mv f1 dir_to_be_moved` - премества файла f1 в указаната директория 27 | 28 | `mv f1 f2` - преименува файла f1 на f2 29 | 30 | 6. `mkdir f1 f2 ...` - създава празни директории 31 | 32 | 7. `rmdir f1 f2 ...` - трие **само** празни директории 33 | 34 | 8. `rm f1 f2 ...` - трие файлове 35 | 36 | `rm -i f1 f2 ...` - пуска ни запитване дали искаме да изтрием файловете 37 | 38 | `rm -r f1 dir ..` - рекурсивно триене, чрез него можем да изтрием непразна директория 39 | 40 | ### FYI 41 | 42 | 1. Ако искате да копирате цялата директория използвате опция `-r` 43 | (recursive) 44 | 2. След време ще се налага чрез един готин редактор да пишете bash скриптове на сървъра. Сигурно ще искате да си ги пращате, за да си ги имате във вкъщи. За да копирате нещо от сървъра до компютъра ви ползвате scp (secure copy): 45 | 46 | `scp s81xxx@os-server.fmi.uni-sofia.bg: /some/local/directory` 47 | 48 | За да използвате командата не трябва да се включени към сървъра, затова ще ви трябва някой от вариантите, които споменах първата седмица 49 | 50 | 3. `mkdir -p dir1/dir2/dir3` - създава целия указан път, т.е. създава dir1, в нея създава dir2 и в dir2 създава dir3 51 | 52 | 53 | ## Работа със съдържанието на файловете 54 | 1. `file f1` - дава информация за типа на файла 55 | 56 | 2. `wc f1 f2 ...` - брои: 57 | 58 | Опции: 59 | 60 | - `-l` - редове 61 | 62 | - `-c` - байтове 63 | 64 | - `-w` - думи 65 | 66 | Ако не зададем опция командата изписва: бр. редове, бр. символи, бр. думи и името на файла 67 | 68 | 3. `head f1 f2 ...` - командата без аргументи по подразбиране дава първите 10 реда от указаните файлове 69 | 70 | Опции: 71 | - `-n` - така командата ни дава първите num реда от файловете 72 | 73 | - `-c` - дава ни първите num байта от файла 74 | 75 | 4. `tail f1 f2 ...` - без аргументи ни дава последните 10 реда от указаните файлове 76 | 77 | Опции: 78 | - `-n`- така командата ни дава последните num реда от файловете 79 | 80 | - `-c` - дава ни последните num байта от файла 81 | 82 | 5. `more f1` - ако имаме голям файл го показва екран по екран 83 | 84 | **FYI:** `less f1` - подобно на more, но докато more показва файла само отгоре-надолу, less ни позволява да се движим и в двете посоки. 85 | 86 | 6. `sort f1` - сортира f1 по редове 87 | 88 | Опции: 89 | - `-o output_file` - вместо резултата да се покаже на екрана се записва в output_file 90 | 7. `comm f1 f2` - сравнява два сортирани файла ред по ред. Изходът е 3 колони - 1-ва колона е уникалните редове за f1, 2-ра е уникалните редове за f2, а третата е редове, които са еднакви в двата файла 91 | 8. `diff f1 f2` - сравнява два файла ред по ред. Дава ни кои редове и по какъв начин трябва да бъдат променени в единия файл, за да бъдат двата файла идентични. 92 | 93 | 9. `cmp f1 f2` - сравнява 2 файла байт по байт 94 | 95 | - ако файловете са еднакви то командата не връща нищо 96 | 97 | - ако файловете се различават, командата ни връща първата позиция, на която се различават 98 | 10. `cut [options] [files]` - реже части от всеки ред на файл 99 | 100 | Опции: 101 | 102 | - `-c` - извлича специфично указани символи, примерно: 103 | 104 | `cut -c 1-3,8-10 f1` - показва ни първите 3 символа от всеки ред на файла, прескача до 8-мия и показва от 8-мия до 10-тия 105 | 106 | `cut -c 1,5,7 f1` - показва ни 1-вия, 5-тия и 7-мия символ от всеки ред на файла f1 107 | 108 | **Важно** - на пръв поглед `-c` изглежда прави същото като `-b` (`-b` реже по байтове), но не е така, защото някои символи са повече от един байт. 109 | 110 | Примерно "♣" e 3 байта. Ако имаме файл със съдържание "♣abc" `cut -c 1,4` ще ни даде "♣c", докато `cut -b 1,4` няма да успее да ни принтира "♣" . 111 | 112 | - `-f` - реже по номер на колона. Ако не е указан разделител реже по whitespace 113 | 114 | - `-d` - указва по какъв разделител да се реже 115 | 116 | **Note:** `-f` и `-d` често се ползват заедно 117 | 118 | `cut -d ":" -f 1-3 f1` - ще ни покаже първите 3 колони от файла f1 119 | 120 | 11. `tr [options] [SET1] [SET2]` - заменя или изтрива специфични символи в подаден низ, където SET1 е множеството от символи, които трябва да се заменят, SET2 е множеството, с което да заменим символите от SET1 в низа 121 | 122 | - tr без опции прави точно гореспоменатото 123 | 124 | - `-c` - сменя всички символи в низа, които **не са** в SET1, с тези от SET2. 125 | 126 | - `-d` - изтрива всички срещания на символите от SET1 127 | 128 | - `-s` - замества повтарящите се символи, изброени в SET1, само с един символ 129 | 130 | 13. `grep str file` - търси низ/рег израз във файл. Като резултат командата връща редовете от файла, в които се съдържа низа/рег. израза 131 | 132 | `grep -v str file` - връща редовете, в които **не се** съдържа низа/рег. израз 133 | 134 | ## Бонус работа с файловата система 135 | 136 | `find` - командата без аргументи извежда на екрана абсолютно всички файлове (дори и тези в поддиректориите) на текущата директория, в която се намирате 137 | 138 | Синтаксис: `find [dir-to-be-searched] [arguments]` 139 | 140 | Аргументи: 141 | 142 | - `-name` - търси по име на файл 143 | 144 | - `-type` - търси по тип на файл 145 | 146 | - `-user` - търси по притежател на файла 147 | 148 | - `-group` - търси по групата, притежател на файла 149 | 150 | - `-size` - търси по размер на файла (трябва да специфицирате мерната единица) 151 | 152 | - `-exec` - изпълнява команда върху всеки един намерен резултат 153 | 154 | **Пример:** `find / -name *.txt -exec wc -c {} \;` Тук ще намерим размера на всеки файл с разширение txt в цялата файлова директория. 155 | 156 | **Защо ни трябва {} \;** - find ще изпълни нашата команда и ще замести {} с намерените резултати, а **\;** гарантира, че командата ще се изпълни точно веднъж върху всеки един от резултатите. 157 | 158 | 159 | 160 | ## Задачи 161 | 162 | 1. Създайте файл f1 и напишете в него "abc". Създайте друг, празен файл, f2. Копирайте съдържанието на f1 във файл с име f3. Създайте директория dir1 и влезте в нея. Преместете f1, f2, f3 в директорията без да излизате от нея, като в същото време ги преименувате на ff1, ff2, ff3. 163 | 2. Преместете всички файлове, започващи с "f" в нова директория "del" и изтрийте тази директория, като преди това изведете на терминала запитване дали искате да изтриете директорията. 164 | 3. Потърсете дали в /etc/passwd има хора с името "Георги". 165 | 4. Принтирайте на екрана информация за всички студенти от /etc/passwd, чиито факултетни номера **не** започват с "8" 166 | 5. Потърсете в цялата файлова система дали има директории, започващи с dir. 167 | 6. Изведете на екрана размера на всеки .txt файл в байтове, който притежавате във вашата начална потребителска директория. 168 | 7. Изведете на екрана последните 5 реда на всички файлове, които са притежание на групата student 169 | 8. Изведете на екрана типовете на всички файлове, които имате в началната ви потребителска директория. 170 | 9. Принтирайте **само** имената на хората, записани в /etc/passwd 171 | 10. Проверете дали /etc/passwd е сортиран. 172 | 173 | -------------------------------------------------------------------------------- /week12/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Системни примитиви за работа с процеси 3 | 4 | Инстанция на работеща програма се нарича **процес.** Процесите могат да създават други процеси, като оригиналният процес се нарича **родител**, а новосъздадения се нарича **дете**.Един родител може да има много процеси-деца, но едно дете може да има най-много един родител. По този начин се създават йерархични групи от процеси, които могат да комуникират помежду си и да споделят ресурси. 5 | 6 | ![enter image description here](https://i.stack.imgur.com/DfzHf.png) 7 | 8 | ## Създаване на процес-дете 9 | ```C 10 | #include 11 | #include 12 | pid_t fork(void); 13 | ``` 14 | След изпълняване на **fork()** вече имаме два процеса - съществуващия (създал детето) се нарича родител, а новосъздадения е процесът-дете. 15 | 16 | **fork() връща:** 17 | 18 | - -1 при неуспешно създаване на процес-дете 19 | 20 | - 0 за процес-дете 21 | 22 | - pid-то на новосъздадения процес-дете 23 | 24 | 25 | Новосъздадения процес е почти точно копие на родителя си. След като сме изпълнили **fork()** от тук-насетне всичкия код, който сме написали се изпълнява и от родителя и от детето. 26 | 27 | **Пример:** 28 | ```C 29 | #include 30 | #include 31 | #include 32 | int main() { 33 | printf("Hello there!"); 34 | fork(); 35 | printf("Called fork()"); 36 | return 0; 37 | } 38 | ``` 39 | **Изход:** ??? 40 | 41 | **Кой се изпълнява първи - родителя или детето?** 42 | 43 | Всеки път различно - и двата процеса работят **асинхронно**. 44 | 45 | **Как да направим така, че да има код, който ще се изпълни само от родителя/детето?** 46 | 47 | Използваме резултатът от fork(). 48 | 49 | ```C 50 | #include 51 | #include 52 | #include 53 | int main() { 54 | int pid = fork(); 55 | if(pid == -1) { 56 | perror("Couldn't fork!); 57 | exit(-1); 58 | } 59 | else if(pid > 0) { 60 | //this is the only parent part 61 | printf("Hello from the parent"); 62 | } 63 | else { 64 | //this is the only child part 65 | printf("Hello from the child"); 66 | } 67 | printf("Called fork()"); 68 | return 0; 69 | } 70 | ``` 71 | 72 | **Примерен изход:** 73 | ``` 74 | Hello from the parent 75 | Called fork() 76 | Hello from the child 77 | Called fork() 78 | ``` 79 | 80 | ### Пример 81 | ```C 82 | #include 83 | #include 84 | #include 85 | int main() { 86 | int a = 1; 87 | int pid = fork(); 88 | if(pid == -1) { 89 | perror("Couldn't fork!"); 90 | exit(-1); 91 | } 92 | else if(pid > 0) { 93 | ++a; 94 | } 95 | else { 96 | --a; 97 | } 98 | printf("a=%d\n",a); 99 | return 0; 100 | } 101 | ``` 102 | 103 | **Изход:** ??? 104 | 105 | ### Получаване на pid за процесът-дете и процесът-родител 106 | 107 | ```C 108 | #include 109 | #include 110 | pid_t getpid(void); 111 | ``` 112 | Дава ни pid-то на **текущия** процес. 113 | 114 | ```C 115 | #include 116 | #include 117 | pid_t getppid(void); 118 | ``` 119 | Дава ни pid-то на **процесът-родител** на съответния процес. 120 | 121 | **Пример:** 122 | ```C 123 | #include 124 | #include 125 | #include 126 | int main() { 127 | int pid = fork(); 128 | if(pid == -1) { 129 | perror("Couldn't fork!); 130 | exit(-1); 131 | } 132 | else if(pid > 0) { 133 | printf("My process ID is %d and my parent is %d\n",getpid(),getppid()); 134 | printf("My child is %d\n", pid); 135 | } 136 | else { 137 | printf("My process ID is %d and my parent is %d",getpid(),getppid()); 138 | } 139 | printf("something ..."); 140 | return 0; 141 | } 142 | ``` 143 | 144 | **Примерен изход:** 145 | ``` 146 | My process ID is 32157 and my parent is 9981 147 | My child is 32158 148 | something ... 149 | My process ID is 32158 and my parent is 32157 150 | something ... 151 | ``` 152 | 153 | ## Завършване на процес - exit() 154 | 155 | ```C 156 | #include 157 | void exit(int return_code); 158 | ``` 159 | - прекратява процеса, който е извикал примитива незабавно. 160 | 161 | - параметърът return_code указва на процесът-родител с какъв код е завършил процеса. 162 | 163 | - системния примитив не връща нищо 164 | 165 | - Всички отворени вхдни-изходни потоци, притежание на процеса, се затварят, унищожават се временните файлове, създадени от процеса, процесите-деца на текущия процес стават деца на **init** процеса 166 | 167 | ## Системен примитив wait() 168 | 169 | ```C 170 | #include 171 | #include 172 | pid_t wait(int * status); 173 | ``` 174 | - чрез **wait()** процеса-родител изчаква своето дете да приключи. 175 | 176 | - примитива връща pid на завършилия процес-дете. 177 | 178 | - status параметъра ни дава кода на завършване на процесът-дете. 179 | 180 | ### Пример 181 | ```C 182 | #include 183 | #include 184 | #include 185 | #include 186 | #include 187 | int main() { 188 | int status = 0; 189 | int pid = fork(); 190 | if(pid == -1) { 191 | perror("Couldn't fork!"); 192 | exit(-1); 193 | } 194 | else if(pid > 0) { 195 | write(1,"Hello from parent",20); 196 | printf("I'll wait now ..."); 197 | wait(&status); 198 | printf("My child has finished with status %d", status); 199 | } 200 | else { 201 | printf("Hello from child"); 202 | } 203 | return 0; 204 | } 205 | ``` 206 | 207 | **Допълнителна информация:** Чрез **wait()** процеса-родител изчаква първото дете, което завършва. Чрез **waitpid()** ние можем да кажем на родителя кой специфичен процес-дете да изчака. 208 | 209 | ```C 210 | #include 211 | #include 212 | pid_t waitpid(pid_t pid, int * status, int options); 213 | ``` 214 | 215 | - чрез **pid** указваме кой процес-дете да чака родителя: 216 | 217 | - pid == -1 - чака, което и да е дете да завърши 218 | 219 | - pid > 0 - чака дете с идентификатор pid 220 | 221 | - pid == 0 - чака, което и да е дете от същата група процеси 222 | 223 | - pid < -1 - чака дете от групата с процеси, чиито идентификатор е |pid| 224 | 225 | - **status** параметъра ни дава кода на завършване на процесът-дете. 226 | 227 | - чрез **options** може да се предотврати блокирането на родителя. При значение WHOHANG процесът-родител не се блокира, ако синът не е завършил и функцията връща 0. 228 | 229 | - функцията връща pid на завършилия процес-дете. 230 | 231 | ## Смяна на образ на процес 232 | 233 | **exec** се използва за промяна на програмата, която един процес изпълнява. При успех **еxec** не връща нищо, иначе връща -1. Той има няколко варианта: 234 | ```C 235 | #include 236 | int execv(const char *path, char *const argv[]); 237 | int execvp (const char *file, char *const argv[]); 238 | ``` 239 | - И двете фунции приемат **масив** от параметри на изпълнимия файл. 240 | 241 | - **execv** приема пътя до изпълнимия файл 242 | 243 | - **еxecvp** приема името на изпълнимия файл и я търси във директорията, която е зададена в PATH системната променлива 244 | 245 | ```C 246 | #include 247 | int execl(const char *path, const char *arg, ...) 248 | int execlp(const char *file, const char *arg, ...) 249 | ``` 250 | - И двете функции приемат параметри на изпълнимия файл, **изброени един по един** 251 | 252 | - **execl** приема пътя до изпълнимия файл 253 | 254 | - **еxeclp** приема името на изпълнимия файл и я търси във директорията, която е зададена в PATH системната променлива 255 | 256 | ### Пример: 257 | ```C 258 | #include 259 | 260 | int main(void) { 261 | char * args1[] = {"/bin/ls", "-lh", "/home", NULL}; 262 | char * args2[] = {"ls", "-lh", "/home", NULL}; 263 | 264 | execv("/bin/ls", args1); 265 | execvp("ls", args2); 266 | 267 | execl("/bin/ls", "/bin/ls", "-lh", "/home", NULL); 268 | execlp("ls", "ls", "-lh", "/home", NULL); 269 | 270 | return 0; 271 | } 272 | ``` 273 | 274 | ## Задачи 275 | 1. Да се напише програма на С, която получава като параметър команда (без параметри) и при успешното и изпълнение извеежда на стандартния изход името на командата. 276 | 2. Да се напише програма на С, която получава като параметри три команди (без параметри), изпълнява ги последователно, като изчаква края на всяка и извежда на стандартния изход pid на завършилия процес, както и неговия код на завършване. 277 | -------------------------------------------------------------------------------- /week3-4/README.md: -------------------------------------------------------------------------------- 1 | # Информационни команди. Команди за многопотребителския режим, комуникация. Команди за работа с процеси. Пренасочване на вход/изход. Конвейер между процеси. 2 | 3 | ## Информационни команди 4 | 5 | - `ls [-опции] [път до директория]` 6 | 7 | - `date` - дава системно време 8 | 9 | - `cal` - Принтира календар 10 | - без аргументи принтира текущия месец 11 | 12 | - `cal [месец] [година]` - принтира месеца и годината, които сме задали 13 | 14 | Пример: `cal 02 2016` 15 | 16 | - `du [-опции] [файл/директория] ` - показва дисково пространство, заето от файлове или директории. 17 | 18 | - без указан файл/директория показва заеманото дисково пространство на всички файлове, директории и поддиректории на текущата директория в която се намиране 19 | 20 | 21 | Опции: 22 | 23 | - `-a` показва информацията и за скритите файлове 24 | 25 | - `-h` показва размера в human readable format 26 | 27 | - `-s` показва **само** размера на подадената директория 28 | 29 | - `df [oпции] [файл]` показва кратка информация за заеманото дисково пространство на файловата система 30 | 31 | - ако бъде специфициран файл то то се показва информация за файловата система, в която се намира той 32 | 33 | Опции: 34 | 35 | - `-h` показва размерите в human readable format 36 | 37 | - `-k` показва размерите в килобайти 38 | 39 | - `-m` показва размерите в мегабайти 40 | 41 | - `-h` показва размерите в гигабайти 42 | 43 | - `tty` - показва името на файла на терминала, свързан към стандартния вход. 44 | 45 | WTF нали ... Тъй като всичко в Линукс е файл то тогава и всички свързани устройства са представени чрез специални файлове => терминала също е представен като файл. 46 | 47 | 48 | ## Команди за многопотребителския режим 49 | - `login` 50 | 51 | - `su [username]` - сменяме потребителя или ставаме суперпотребител 52 | 53 | - `chown [потребител] [файл/ове]` - смяна на собственик на файла 54 | 55 | - `chgrp [група] [файл/ове] ` - смяна на групата на файла 56 | 57 | - `chmod [режим] [файл/ове] ` - промяна на правата за достъп до даден файл или директория 58 | 59 | Режимът може да е: 60 | 61 | - Зададен чрез число в 8-мична бройна система: 000-777. 62 | 63 | **Пример:** chmod 777 f1 64 | 65 | **Как можем да изчислим всяка цифра?** 66 | 67 | От първото упражнение знаем, че правата за достъп на файловете изглеждат така: 68 | 69 | `drwxr-xr-x 2 user user 4096 окт 5 2018 directory` 70 | 71 | ` -rw-r--r-- 1 user user 2243935 дек 8 2017 file` 72 | 73 | Като на първата позиция стои съответно индикатор дали това е директория (d) или файл (-). Следват 3 групи от 3 символа **r**ead, **w**rite, e**x**ecute, които указват правата за достъп съответно на текущия потребител, групата му и всички останали. Ако някое право е забранено съответно на мястото му присъства `-`. 74 | 75 | За да получим 3-цифрения код за правата за достъп просто заместваме r,w,x с 1-ца, а `-` с 0. 76 | 77 | **Примерно** `-rw-r--r--` е файл, който може да се чете и пише от текущия потребител и само да се чете от групата и всички останали. 78 | След като заместим символите с 0 и 1 получаваме: `110 100 100` и така след преобразуване в 8-мична бр. система получаваме `644`. 79 | 80 | - Зададен чрез букви: следва следния синтаксис: [Кой] [Действие] [Какво] 81 | - Кой: **u**ser, **g**roup, **o**thers, **a**ll 82 | 83 | - Действие: **+** добавя право, **-** премахва право, **=** сменя изцяло правата за достъп с тези, който стоят от дясната страна на равенството 84 | 85 | - Какво: **r**ead, **w**rite, e**x**ecute 86 | 87 | **Примери:** 88 | 89 | `chmod u=rw,og=r file.txt` - текущия потребител получава правото само да чете и да пише, а групата и всички останали само да четат 90 | 91 | `chmod a+wx script.sh` - всички получават право да пишат и изпълняват файла 92 | 93 | `chmod go+w *` - групата и всички останали получават право да пишат по всички файлове в текущата директория 94 | 95 | ### Комуникация между потребители 96 | - `who` - показва информация за логнатите потребители 97 | 98 | - `-u` дава повече информация за логнатите потребители - ако потребителят е разрешил писане се появява + във втората колонка; ако потребителят е бил активен в последната 1 минута се появява . в 6-тата колонка. 99 | 100 | - `-H` - дава хедърите на колонките 101 | 102 | - `whoami` - показва името на потребителя, изпълнил командата 103 | 104 | - `w` - показва информация за логнатите потребители и какво правят в момента 105 | 106 | - `finger [потребител]` - показва информация за даден потребител 107 | 108 | - ако не е указано потребителско име показва информация за всички потребители 109 | 110 | - `wall` - пишем съобщение до всички 111 | 112 | - `mesg [y|n]` - разрешава/забранява получаването на съобщения от други потребители 113 | 114 | - без аргументи, командата показва информация дали сме разрешили или забранили съобщения 115 | 116 | - `mesg y` - разрешава съобщения 117 | 118 | - `mesg n` - забранява съобщения 119 | 120 | 121 | - `write [user] [tty]` - пишем съобщение до даден user като можем да укажем и по кой терминал да му се прати, ако user-a е логнат в повече от един. Ако потребителя е забранил съобщенията си излиза грешка. 122 | 123 | ## Команди за работа с процеси 124 | 125 | - `ps` - показва всички текущи процеси на текущия потребител 126 | 127 | - `ps aux` - показва информация за всички процеси на всички потребители 128 | 129 | **Каква информация виждаме?** 130 | 131 | - USER - на кой потребител принадлежи процеса 132 | 133 | - PID - идентификационен номер на процеса 134 | 135 | - %CPU - използваното време на процесора, разделено на времето, в което е стартиран процесът. 136 | 137 | - %MEM - процент на реалната памет, използвана от процеса. 138 | 139 | - VSZ - използване на виртуална памет за целия процес (в KiB) 140 | 141 | - RSS - незаменяемата физическа памет, която е използвана в задачата (в KiB) 142 | 143 | - TTY - контролиращ терминал 144 | 145 | - STAT - кодът на състоянието на процеса, който може да бъде Z (зомби), S (спящ), R (работещ) и т.н. 146 | 147 | - START - начално време на процеса 148 | 149 | - TIME - количество време на процесора, изразходвано за изпълнение на процеса 150 | 151 | - COMMAND - името на изпълнената команда с нейните опции 152 | 153 | - `kill [опции] [pid на процес] ` - изпраща сигнал на процес 154 | 155 | **Какво е сигнал?** 156 | 157 | Сигналите са предупреждения за важни събития, изпращани към процесите от ядрото или от друг процес. Те прекъсват дейността на процеса и го принуждават да ги обработи веднага. Всички сигнали могат да бъдат изведени чрез `kill -l` 158 | 159 | **По-важни сигнали:** 160 | 161 | - SIGHUP с номер 1 - изпраща се от ядрото при отписване на потребителя. 162 | 163 | - SIGINT с номер 2 - прекъсване. Изпраща се от ядрото при въвеждане **Ctrl+C** на терминала. 164 | 165 | - SIGKILL с номер 9 - принуждава процеса да завърши без да му се дава възможност за нормална завършваща дейност. 166 | 167 | - SIGTERM с номер 15 - заявка за нормално приключване на процеса. 168 | 169 | - TSTP с номер 18 - временно прекратява действието на процеса. Изпраща се от ядрото при въвеждане **Ctrl+Z** на терминала. 170 | 171 | **Пример:** 172 | 173 | `kill -9 1234` - убиваме процес с pid 1234 174 | 175 | 176 | ## Пренасочване на вход/изход 177 | 178 | При стартирането на процес той предварително е свързан с 3 [комуникационни канала](https://bg.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BC%D1%83%D0%BD%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%B5%D0%BD_%D0%BA%D0%B0%D0%BD%D0%B0%D0%BB) (файла) - stdin (стандартен вход), stdout (стандартен изход), stderr (стандартен изход за грешки). 179 | 180 | Стандартните потоци на процесите могат да бъдат пренасочвани във файлове: 181 | 182 | - Стандартният вход (stdin) се пренасочва чрез "<" към файл, откъдето процесът трябва да чете 183 | 184 | Пример: когато използваме cat без аргументи, командата чете низове от стандартния вход и ги принтира на стандартния изход. 185 | 186 | `cat < f1` - stdin за cat става файла f1, а stdout си е стандартния изход. Командата извежда съдържанието на файла. 187 | 188 | - Стандартния изход (stdout) се пренасочва с ">" към файл. Ако файлът не съществува се създава, иначе се презаписва. Ако не искаме файла да се презаписва, а да добавяме към края му, се използва ">>". 189 | 190 | `cat > f1` - стандартния вход е клавиатурата, а стандартния изход става файлът f1, т.е. пишем последователно във файла f1. 191 | 192 | `ps aux >> f1` - стандартния изход за ps aux става файла f1, като сме указали информацията да се добави към края на съдържанието му. 193 | 194 | - можем да пренасочим и двата потока едновременно 195 | 196 | `cat < f1 > f2` - stdin за cat е f1, a stdout е f2, т.е. симулирахме cp командата 197 | 198 | **Какво става със стандартния поток за грешки?** 199 | 200 | Ако изпълним командата `find / -name f1 > ff` виждаме че stdout е пренасочен към файла ff, a на екрана ни излизат само съобщения за грешки. Най-често стандартния поток за грешки се пренасочва чрез **файловия му дескриптор** 201 | 202 | **Какво е файлов дескриптор?** 203 | 204 | Файловият дескриптор е цяло, неотрицателно число, което служи за идентифициране на отворен файл. 205 | 206 | Както споменах по-горе всеки процес има 3 предварително отворени файла: 207 | - stdin е с дескриптор 0 208 | - stdout е с дексриптор 1 209 | - stderr е с дескриптор 2 210 | 211 | Всеки процес може да отваря и други файлове, като на тях ще им се присвоява съответно най-малкото свободно число ... но това е тема, която ще се разглежда по Системно програмиране. 212 | 213 | Та горните примери съответно могат да изглеждат по този начин: 214 | 215 | `cat 0f1` - записваме низове, подадени от стандартния вход в f1 218 | 219 | `ps aux 1>>f1` - записваме информацията от ps aux в края на f1 220 | 221 | И съответно, за да пренасочим грешките в друг файл: 222 | 223 | `find / -name f1 > ff 2>errors.txt` - така имаме файл ff, който съдържа желаните резултати и файл errors.txt, който съдържа всички грешки от изпълнението на find. 224 | 225 | ## Конвейер между процеси. 226 | 227 | Конвейерът е последователност от процеси, свързани чрез техните потоци, така че стандартния изход от единия процес става стандартен вход на следващия процес. 228 | 229 | Синтаксисът е следният: `command1 | command 2 | command 3` 230 | 231 | Пример: Искаме да преброим колко файла имаме в текущата директория. Това може да стане по следния начин: 232 | 233 | ls -l > temp 234 | wc -l < temp 235 | rm temp 236 | 237 | Вместо да създаваме временен файл можем да свържем стандартния изход на ls със стандартния вход на wc: 238 | 239 | ls -l | wc -l 240 | 241 | 242 | ## Задачи 243 | 1. Да се изтрият всички празни файлове от текущата ви директория и всички нейни поддиректории 244 | 2. Да се добавят права за изпълнение на всички .sh файлове в текущията директория и всички нейни поддиректории към текущия потребител, групата му и всички останали. Погрижете се грешките да не излизат на стандартния изход, а във файл errors. 245 | 3. Запишете във файл current_proccess системната дата. Запишете в същия файл **само** pid на текущите процеси на всички потребители. Забележка: Разделителите в таблицата с информация за процесите са повече от един whitespace. Трябва да се погрижите за махането на повтарящите се whitespace, за да получите правилната информация. 246 | 4. Напишете в терминала `vim &`. Намерете pid на процеса (не скролвайте през информацията за всички процеси) и го убийте. 247 | 5. Създайте 3 файла със съдържание съответно aaa, bbb и ccc. Конкатенирайте съдържанието на трите файла в четвърти файл, т.е. съдържанието на четвъртия файл трябва да е: 248 | ``` 249 | aaa 250 | bbb 251 | ccc 252 | ``` 253 | 254 | 6. Запишете първите два реда от файла /etc/passwd във файл h1, а последните 2 във файл t1. Отрежете първите 3 символа от двата файла и ги добавете в файл ht1. 255 | 7. Запишете във файл size **само** размера в байтове на най-големия .txt файл, който притежавате в текущата директория и всички нейни поддиректории. Забележка: използвайте `sort -n` за сортиране на числа. 256 | --------------------------------------------------------------------------------