├── .gitignore ├── 01. GNU:Linux concepts.pdf ├── 02. File management and manipulation.pdf ├── 03. Text processing and command line.pdf ├── 04. Process management and job control.pdf ├── 05. Shell.pdf ├── 1 – FMI Tasks ├── C Processes │ ├── Additional Task 1.c │ ├── Additional Task 1.md │ ├── Additional Task 2.c │ ├── Additional Task 2.md │ ├── Exam problems.pdf │ ├── Prompt (2nd).c │ ├── Prompt.c │ ├── Prompt.md │ ├── README.md │ ├── Task 01.c │ ├── Task 02.c │ ├── Task 03.c │ ├── Task 04.c │ ├── Task 05.c │ ├── Task 06.c │ ├── Task 07.c │ ├── Task 08 (more precise).c │ ├── Task 08.c │ ├── Task 09.c │ ├── Task 10.c │ ├── Task 11.c │ ├── Task 12.c │ ├── Task 13 (2nd solution).c │ ├── Task 13.c │ ├── Task 43.c │ ├── Task 44 (1st sol).c │ ├── Task 44 (2nd sol).c │ ├── Task 45.c │ ├── Task 46.c │ ├── Task 47.c │ ├── Task 48 (1st sol).c │ ├── Task 48 (2nd sol).c │ ├── Task 48 test script for 2nd sol.sh │ ├── Task P01 (2nd solution).c │ ├── Task P01.c │ ├── Task P02.c │ ├── Task P03.c │ ├── bar.c │ ├── cat a.txt | sort | uniq (long).c │ ├── cat a.txt | sort | uniq (short).c │ ├── cat passwd.txt | cut -d ':' -f 7 | sort | uniq.c │ ├── classic deadlock example.c │ ├── foo.c │ ├── fork-loop.c │ └── Задaча 2.md ├── C │ ├── 06. C problems.pdf │ ├── Examples Task 01 Exam 12-07-2020.pdf │ ├── Makefile │ ├── README.md │ ├── Task 00 (struct padding).c │ ├── Task 01 (append - O_APPEND).c │ ├── Task 01 (append - lseek).c │ ├── Task 01 Exam 12-07-2020 Solution.c │ ├── Task 01 Exam 12-07-2020.pdf │ ├── Task 02 (swap 2 files - read & write).c │ ├── Task 02 (swap 2 files - renameat2).c │ ├── Task 02 Exam 12.07.2020.pdf │ ├── Task 03 (head without options).c │ ├── Task 04 (wc).c │ ├── Task 05 (qsort).c │ ├── Task 06 (cp with 2 args).c │ ├── Task 07 (cat with multiple args).c │ ├── Task 08 1st sol (cp with multiple args).c │ ├── Task 08 2nd sol (cp with multiple args).c │ ├── Task 08 3rd sol (cp with multiple args).c │ ├── Task 09 (passwd with '?' separator).c │ ├── Task 09.md │ ├── Task 10 (--print --min --max binfile).c │ ├── Task 10.md │ ├── Task 11 (counting sort inplace).c │ ├── Task 11 (counting sort).c │ ├── Task 31 (sort file.bin inplace).c │ ├── Task 32 (pairs extract 2nd sol).c │ ├── Task 32 (pairs).c │ ├── Task 33 (qsort + merge).c │ ├── Task 34 (2nd sol).c │ ├── Task 34.c │ ├── Task 35 (more precise).c │ ├── Task 35.c │ ├── Task 36 (more precise).c │ ├── Task 36.c │ ├── Task 37.c │ ├── Task 38 (goto).c │ ├── Task 38 (strchr, strrchr).c │ ├── Task 38.c │ ├── Task 40.c │ ├── Task 41 (uint16_t counting sort).c │ ├── Task 41 (uint16_t heapsort).c │ ├── overflow testing with counting sort.c │ ├── paste with 2 files.c │ └── paste with 2 files.md ├── Cheat sheets │ ├── Bash Redirections Cheat Sheet.pdf │ └── Vi Reference Card.pdf ├── File Processing │ ├── 01. Работа с файлове.md │ ├── E 01 Task 05.md │ ├── E 01 Task 06.md │ ├── E 01 Task 08.md │ ├── E 01 Task 09.md │ ├── E 01 Task 12.md │ ├── Task 04.md │ ├── Task 05.md │ └── Task 06.md ├── K1_2017_SI.pdf ├── K1_2018_SI.pdf ├── K1_A_2016_SI.pdf ├── K1_B_2016_SI.pdf ├── K2_2016_SI.pdf ├── K3_2016_SI.pdf ├── OS 2018 SC StEx.pdf ├── OS Tasks Longlist '20.pdf ├── Processes │ ├── 04-a-5000.sh │ ├── 04-a-6000.sh │ ├── 04-a-6300.sh │ ├── 04-b-5000.sh │ ├── 04-b-6100.sh │ ├── 04-b-6200.sh │ ├── 04-b-7000.sh │ ├── 04-b-8000.sh │ ├── 04. Processes.pdf │ └── Processes summary.md ├── Shell │ ├── 04-b-9000 1st sol.sh │ ├── 04-b-9000 2nd sol.sh │ ├── 05-b-2000.sh │ ├── 05-b-2800 1st sol.sh │ ├── 05-b-2800 2nd sol.sh │ ├── 05-b-2800 3rd sol.sh │ ├── 05-b-3100.sh │ ├── 05-b-3200 1st sol.sh │ ├── 05-b-3200 2nd sol.sh │ ├── 05-b-3300.sh │ ├── 05-b-3400.sh │ ├── 05-b-4200 1st sol.sh │ ├── 05-b-4200 2nd sol.sh │ ├── 05-b-4200 3rd sol.sh │ ├── 05-b-4300.sh │ ├── 05-b-4301.sh │ ├── 05-b-4400.sh │ ├── 05-b-4500.sh │ ├── 05-b-4600.sh │ ├── 05-b-4700 1st sol.sh │ ├── 05-b-4700 2nd sol.sh │ ├── 05-b-4700 3rd sol.sh │ ├── 05-b-4800.sh │ ├── 05-b-5500.sh │ ├── 05-b-6600 1st sol.sh │ ├── 05-b-6600 2nd sol.sh │ ├── 05-b-6800.sh │ ├── 05-b-7000.sh │ ├── 05-b-7100.sh │ ├── 05-b-7200 1st sol.sh │ ├── 05-b-7200 2nd sol.sh │ ├── 05-b-7500.sh │ ├── 05-b-7550 1st sol.sh │ ├── 05-b-7550 2nd sol.sh │ ├── 05-b-7700 1st sol.sh │ ├── 05-b-7700 2nd sol.sh │ ├── 05-b-7800.sh │ ├── 05-b-8000.sh │ ├── 05-b-9100.sh │ ├── 05-b-9200.sh │ ├── 05-b-9501.sh │ ├── 05-b-9600.sh │ ├── 05. Shell Introduction.pdf │ ├── 05. Shell Tasks.pdf │ ├── Change files extention.sh │ ├── Draw Pyramid.sh │ ├── Find Longest Filename (solution).sh │ └── Find Longest Filename.md ├── Test 2 Preparation │ ├── 05. Shell Exam problems.pdf │ ├── 13 (solution 1).sh │ ├── 13 (solution 2).sh │ ├── 14.sh │ ├── 15.sh │ ├── 16 (solution 1).sh │ ├── 16 (solution 2).sh │ ├── 17.sh │ ├── 18.sh │ ├── 19.sh │ ├── 20.sh │ ├── 21.sh │ ├── 22.sh │ ├── 23 (multiple fields sort).sh │ ├── 23 (version sort).sh │ ├── 24.sh │ ├── 25.sh │ ├── 26.sh │ ├── 27 (input order).sh │ ├── 27 (sorted).sh │ ├── 28 (A) cycle.sh │ ├── 28 (B) extract last digit.sh │ ├── 28 (B) smart sed + bc.sh │ └── 29.sh └── Text Processing │ ├── 01 Text Processing - Exam Problems.pdf │ ├── 02. Обработка на текст.md │ ├── E 01 Task 01.md │ ├── E 01 Task 02.md │ ├── E 01 Task 04.md │ ├── E 01 Task 07.md │ ├── E 01 Task 10.md │ ├── E 01 Task 11.md │ ├── Task 01.md │ ├── Task 02.md │ └── Task 03.md ├── 2 – Theory ├── Little Book Of Semaphores.pdf ├── OS 2018-03-21 L.pdf └── OS Theory (main).pdf ├── 3 – Project └── Image editor │ ├── Image editor.pdf │ ├── crop.sh │ └── crop_all.sh ├── 4 – Linux Shell ├── Arrays in Bash │ ├── Concatenate an array with itself.sh │ ├── Count the number of elements in an Array.sh │ ├── Display an element of an array.sh │ ├── Filter an Array with Patterns (Sol. 1).sh │ ├── Filter an Array with Patterns (Sol. 2).sh │ ├── Lonely Integer - Bash! (Sol. 1).sh │ ├── Lonely Integer - Bash! (Sol. 2).sh │ ├── Read in an Array (Sol. 1).sh │ ├── Read in an Array (Sol. 2).sh │ ├── Remove the First Capital Letter from Each Element (Sol. 1).sh │ ├── Remove the First Capital Letter from Each Element (Sol. 2).sh │ ├── Remove the First Capital Letter from Each Element (Sol. 3).sh │ ├── Remove the First Capital Letter from Each Element (Sol. 4).sh │ ├── Slice an Array (Sol. 1).sh │ └── Slice an array (Sol. 2).cpp ├── Bash │ ├── A Personalized Echo.sh │ ├── Arithmetic Operations.sh │ ├── Comparing Numbers (Sol. 1).sh │ ├── Comparing Numbers (Sol. 2).sh │ ├── Compute the Average.sh │ ├── Getting started with conditionals (Sol. 1).sh │ ├── Getting started with conditionals (Sol. 2).sh │ ├── Let's Echo.sh │ ├── Looping and Skipping (Sol. 1).sh │ ├── Looping and Skipping (Sol. 2).sh │ ├── Looping and Skipping (Sol. 3).sh │ ├── Looping and Skipping (Sol. 4).sh │ ├── Looping with Numbers (Sol. 1).sh │ ├── Looping with Numbers (Sol. 2).sh │ ├── Looping with Numbers (Sol. 3).sh │ ├── Looping with Numbers (Sol. 4).sh │ ├── More on Conditionals.sh │ ├── The World of Numbers (Sol. 1).sh │ └── The World of Numbers (Sol. 2).sh └── Text Processing │ ├── 'Awk' Command #1 (Sol. 1).sh │ ├── 'Awk' Command #1 (Sol. 2).sh │ ├── 'Awk' Command #2 (Sol. 1).sh │ ├── 'Awk' Command #2 (Sol. 2).sh │ ├── 'Awk' Command #3 (Sol. 1).sh │ ├── 'Awk' Command #3 (Sol. 2).sh │ ├── 'Awk' Command #4 (Sol. 1).sh │ ├── 'Awk' Command #4 (Sol. 2).sh │ ├── 'Grep' #1 (Sol. 1).sh │ ├── 'Grep' #1 (Sol. 2).sh │ ├── 'Grep' #2.sh │ ├── 'Grep' #3.sh │ ├── 'Grep' A (Sol. 1).sh │ ├── 'Grep' A (Sol. 2).sh │ ├── 'Grep' B (Sol. 1).sh │ ├── 'Grep' B (Sol. 2).sh │ ├── 'Sed' Command #1 (Sol. 1).sh │ ├── 'Sed' Command #1 (Sol. 2).sh │ ├── 'Sed' Command #2.sh │ ├── 'Sed' Command #3 (Sol. 1).sh │ ├── 'Sed' Command #3 (Sol. 2).sh │ ├── 'Sed' Command #3 (Sol. 3).sh │ ├── 'Sed' Command #4 (Sol. 1).sh │ ├── 'Sed' Command #4 (Sol. 2).sh │ ├── 'Sed' Command #5 (Sol. 1).sh │ ├── 'Sed' Command #5 (Sol. 2).sh │ ├── 'Tr' Command #1 (Sol. 1).sh │ ├── 'Tr' Command #1 (Sol. 2).sh │ ├── 'Tr' Command #2.sh │ ├── 'Tr' Command #3 (Sol. 1).sh │ ├── 'Tr' Command #3 (Sol. 2).sh │ ├── 'Tr' Command #3 (Sol. 3).sh │ ├── 'Tr' Command #3 (Sol. 4).sh │ ├── 'Uniq' Command #1.sh │ ├── 'Uniq' Command #2 (Sol. 1).sh │ ├── 'Uniq' Command #2 (Sol. 2).sh │ ├── 'Uniq' Command #3 (Sol. 1).sh │ ├── 'Uniq' Command #3 (Sol. 2).sh │ ├── 'Uniq' Command #4.sh │ ├── Cut #1.sh │ ├── Cut #2.sh │ ├── Cut #3.sh │ ├── Cut #4 (Sol. 1).sh │ ├── Cut #4 (Sol. 2).sh │ ├── Cut #5 (Sol. 1).sh │ ├── Cut #5 (Sol. 2).sh │ ├── Cut #6.sh │ ├── Cut #7.sh │ ├── Cut #8.sh │ ├── Cut #9.sh │ ├── Head of a Text File #1.sh │ ├── Head of a Text File #2.sh │ ├── Middle of a Text File (Sol. 1).sh │ ├── Middle of a Text File (Sol. 2).sh │ ├── Middle of a Text File (Sol. 3).sh │ ├── Paste #1.sh │ ├── Paste #2.sh │ ├── Paste #3.sh │ ├── Paste #4 (Sol. 1).sh │ ├── Paste #4 (Sol. 2).sh │ ├── Sort Command #1.sh │ ├── Sort Command #2.sh │ ├── Sort Command #3.sh │ ├── Sort Command #4 (Sol. 1).sh │ ├── Sort Command #4 (Sol. 2).sh │ ├── Sort Command #5.sh │ ├── Sort Command #6.sh │ ├── Sort Command #7.sh │ ├── Tail of a Text File #1.sh │ └── Tail of a Text File #2.sh ├── 5 – Test & Exams ├── OS 2016-08-27 SE.pdf ├── OS 2017-05-13 K2.pdf ├── OS 2017-06-17 K3.pdf ├── OS 2017-08-26 K4.pdf ├── OS 2018 K1.pdf ├── OS 2018-06-19 K3.pdf ├── OS 2018-08-24 K4 CS.pdf ├── OS 2018-08-25 K4 SE.pdf ├── OS 2018-09-10 StEx.pdf ├── OS 2019-03-23 K1 KN.pdf ├── OS 2019-03-23,31 K1 KN SI.pdf ├── OS 2019-06-08 Extra Ex.pdf ├── OS 2019-08-25 K4 SI .pdf ├── OS 2019-08-28 K4 KN.pdf ├── OS 2019-09-08 K3 KN SI.pdf └── OS 2020-06-28 S1 SE.pdf ├── README.md └── assets ├── Exam ├── Examples Task 01 Exam 12-07-2020.pages └── Task 01 Exam 12-07-2020.pages ├── Project └── Image editor.pages └── Theory └── OS Theory (main).pages /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # macOS-specifics metadata 55 | .DS_Store 56 | -------------------------------------------------------------------------------- /01. GNU:Linux concepts.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/01. GNU:Linux concepts.pdf -------------------------------------------------------------------------------- /02. File management and manipulation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/02. File management and manipulation.pdf -------------------------------------------------------------------------------- /03. Text processing and command line.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/03. Text processing and command line.pdf -------------------------------------------------------------------------------- /04. Process management and job control.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/04. Process management and job control.pdf -------------------------------------------------------------------------------- /05. Shell.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/05. Shell.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Additional Task 1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv){ 6 | if(argc !=3) 7 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 8 | 9 | const char *cmd1 = argv[1], *cmd2 = argv[2]; 10 | 11 | int a[2]; 12 | if(pipe(a) == -1) 13 | err(2, "could not pipe a"); 14 | 15 | const pid_t child_cmd1 = fork(); 16 | if(child_cmd1 == -1) 17 | err(3, "could not fork"); 18 | 19 | if(child_cmd1 == 0){ // we are in child for exec cmd1 20 | if(dup2(a[0], 0) == -1) 21 | err(4, "could not dup2"); 22 | 23 | close(a[1]); 24 | 25 | if(execlp(cmd1, cmd1, (char*)NULL) == -1) 26 | err(5, "could not execlp %s", cmd1); 27 | } 28 | close(a[0]); 29 | 30 | int b[2]; 31 | if(pipe(b) == -1) 32 | err(6, "could not pipe b"); 33 | 34 | const pid_t child_cmd2 = fork(); 35 | if(child_cmd2 == -1) 36 | err(7, "could not fork"); 37 | 38 | if(child_cmd2 == 0){ // we are in child for exec cmd2 39 | if(dup2(b[0], 0) == -1) 40 | err(8, "could not execlp %s", cmd2); 41 | close(b[1]); 42 | 43 | if(execlp(cmd2, cmd2, (char*)NULL) == -1) 44 | err(9, "could not execlp %s", cmd2); 45 | } 46 | close(b[0]); 47 | 48 | char buf[1<<10]; 49 | ssize_t read_sz; 50 | int row = 1; 51 | while((read_sz = read(0, &buf, sizeof(buf))) > 0){ 52 | if((row & 1) == 0) // odd 53 | if(write(b[1], &buf, read_sz)!= read_sz) 54 | err(10, "could not write to \"write end\" of pipe b"); 55 | if((row & 1) == 1) // even 56 | if(write(a[1], &buf, read_sz)!= read_sz) 57 | err(11, "could not write to \"write end\" of pipe a"); 58 | ++row; 59 | } 60 | close(a[1]); 61 | close(b[1]); 62 | exit(0); 63 | } 64 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Additional Task 1.md: -------------------------------------------------------------------------------- 1 | **Задача 1.** (допълнителна) Напишете програма, която приема като аргументи имена на две команди, 2 | след това прочита редове от STDIN. Четните редове се пращат на STDIN на първата команда, 3 | а нечетните - на STDIN на втората (приемете, че редовете започват от 1). Програмата излиза, когато и двете команди приключат работата си (обработят всички редове). 4 | 5 | За удобство може да ползвате командите *bc* и *rev*, които очаквад текст от STDIN, или просто *echo* вместо *bc*. 6 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Additional Task 2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include // for debug 7 | 8 | void execute(char **args, int cnt){ 9 | const pid_t child = fork(); 10 | if(child == -1) 11 | err(3, "could not fork"); 12 | if(child == 0)// child process 13 | if(execvp(args[0], args) == -1) 14 | err(4, "could not execvp %s with args", args[0]); 15 | if(child > 0){ // parent procrss 16 | if(wait(NULL) == -1) 17 | err(5, "could not wait for child"); 18 | for(int i = 1; i < cnt; ++i) 19 | free(args[i]); 20 | } 21 | } 22 | 23 | int main(int argc, char **argv){ 24 | if(argc != 2) 25 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 26 | 27 | char *cmd = argv[1]; 28 | 29 | char buf[1<<7]; 30 | int read_sz; 31 | while((read_sz = read(0, &buf, sizeof(buf))) > 0){ 32 | int opts = 0; // options 33 | for(int i = 0; i < read_sz; ++i) 34 | if(*(buf + i) == ' ' || *(buf + i) == '\n') 35 | ++opts; 36 | 37 | char *args[opts + 1 + 1]; // +1 for cmd, +1 for last NULL 38 | int cnt = 0; // position of opt 39 | args[cnt++] = cmd; 40 | int indx = 0; 41 | 42 | char opt[1<<6]; 43 | for(int i = 0; i < read_sz; ++i){ 44 | if(*(buf + i) == ' ' || *(buf + i) == '\n'){ 45 | opt[indx] = '\0'; 46 | args[cnt] = malloc(indx + 1); 47 | if(args[cnt] == NULL) 48 | err(2, "not enough memory"); 49 | indx = 0; 50 | strcpy(args[cnt++], opt); 51 | if(*(buf + i) == '\n'){ 52 | args[cnt] = NULL; 53 | execute(args, cnt); 54 | } 55 | } else{ 56 | opt[indx++] = *(buf + i); 57 | } 58 | } 59 | } 60 | if(read_sz == -1) 61 | err(99, "could not read from stdin"); 62 | 63 | exit(0); 64 | } 65 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Additional Task 2.md: -------------------------------------------------------------------------------- 1 | **Задача 2.** (допълнителна) Напишете програма, която приема име на команда като параметър. След това чете редове от STDIN, като за всеки ред fork-ва ново копие 2 | на подадената команда и ѝ подава реда като аргументи (разделени по спейс). 3 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Prompt (2nd).c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include // for debug 7 | 8 | void execute(char **args, int cnt){ 9 | const pid_t child = fork(); 10 | if(child == -1) 11 | err(3, "could not fork"); 12 | if(child == 0)// child process 13 | if(execvp(args[0], args) == -1) 14 | err(4, "could not execvp %s with args", args[0]); 15 | if(child > 0){ // parent procrss 16 | if(wait(NULL) == -1) 17 | err(5, "could not wait for child"); 18 | for(int i = 0; i < cnt; ++i) 19 | free(args[i]); 20 | } 21 | } 22 | 23 | int main(void){ 24 | const char *prompt = "Andy's prompt: "; 25 | ssize_t len = (ssize_t)strlen(prompt); 26 | while(1){ 27 | if(write(1, prompt, len) != len) 28 | err(1, "could not write prompt msg to stdoutt"); 29 | char buf[1<<6]; 30 | int read_sz; 31 | while((read_sz = read(0, &buf, sizeof(buf))) > 0){ 32 | int n = 0; // cmd + options 33 | for(int i = 0; i < read_sz; ++i) 34 | if(*(buf + i) == ' ' || *(buf + i) == '\n') 35 | ++n; 36 | 37 | char *args[n + 1]; // +1 for last NULL 38 | int cnt = 0; // position of opt 39 | int indx = 0; 40 | 41 | char opt[1<<6]; 42 | for(int i = 0; i < read_sz; ++i){ 43 | if(*(buf + i) == ' ' || *(buf + i) == '\n'){ 44 | opt[indx] = '\0'; 45 | args[cnt] = malloc(indx + 1); 46 | if(args[cnt] == NULL) 47 | err(2, "not enough memory"); 48 | indx = 0; 49 | strcpy(args[cnt++], opt); 50 | if(*(buf + i) == '\n'){ 51 | if(strcmp(args[cnt - 1], "exit") == 0 && n == 1) 52 | exit(0); 53 | args[cnt] = NULL; 54 | //for(int j = 0; j < cnt; ++j) 55 | //printf("%s\n", args[j]); 56 | execute(args, cnt); 57 | } 58 | } else{ 59 | opt[indx++] = *(buf + i); 60 | } 61 | } 62 | } 63 | if(read_sz == -1) 64 | err(99, "could not read from stdin"); 65 | } 66 | exit(0); 67 | } 68 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Prompt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define max_args 8 11 | #define max_symbols 16 12 | 13 | int main(void){ 14 | OUTER: 15 | while(1){ 16 | const char *prompt = "Andy's prompt: "; 17 | ssize_t len = (ssize_t)strlen(prompt); 18 | if(write(1, prompt, len) != len) 19 | err(1, "could not write prompt msg to stdout"); 20 | 21 | char cmd_and_args[max_args + 1][max_symbols + 1]; 22 | 23 | char buf[1<<10]; 24 | int indx = 0, row = 0, n = 0; // n is number of args + cmd (here we count them) 25 | ssize_t read_sz; 26 | while((read_sz = read(0, buf + indx, 1)) == 1 && row <= max_args && *(buf + indx) != '\n'){ 27 | if(*(buf + indx) == ' ' || *(buf + indx) == '\n'){ 28 | ++n; 29 | if(n > 7){ 30 | warnx("too much arguments"); 31 | read(0, buf, sizeof(buf)); // fake /dev/null 32 | goto OUTER; 33 | } 34 | buf[indx] = '\0'; 35 | strcpy(cmd_and_args[row++], buf); 36 | indx = 0; 37 | } else { 38 | ++indx; 39 | if(indx > max_symbols){ 40 | warnx("command or argument is too long"); 41 | read(0, buf, sizeof(buf)); // fake /dev/null 42 | goto OUTER; 43 | } 44 | } 45 | } 46 | if(read_sz == -1) 47 | err(3, "could not read from stdin"); 48 | 49 | if(*(buf + indx) == '\n'){ 50 | ++n; // don't forget to count here 51 | buf[indx] = '\0'; 52 | if(strcmp(buf, "exit") == 0) 53 | exit(0); 54 | strcpy(cmd_and_args[row++], buf); 55 | } 56 | 57 | // here we adjust the arguments for the execvp command 58 | char *cmd = cmd_and_args[0]; 59 | char *args[n + 1]; 60 | 61 | for(int i = 0; i < n; ++i) 62 | args[i] = cmd_and_args[i]; 63 | 64 | args[n] = NULL; 65 | // arguments arе now in the required format 66 | 67 | const pid_t child = fork(); 68 | if(child == -1) 69 | err(4, "could not fork"); 70 | 71 | if(child == 0) // we are in child process for execution of the cmd with args 72 | if(execvp(cmd, args) == -1) 73 | err(5, "could not execvp"); 74 | 75 | if(wait(NULL) == -1) 76 | err(6, "could not wait for child process"); 77 | } 78 | exit(0); 79 | } 80 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Prompt.md: -------------------------------------------------------------------------------- 1 | **Задача 44А.** Напишете програма на C, която реализира command prompt като от [задача 44](https://github.com/andy489/Linux_Shell/blob/master/FMI%20Tasks/C%20Processes/Exam%20problems.pdf), но да се поддържат и аргументи на командите. 2 | Аргументите да не надвишават 7. Под аргументи ще разбираме всеки стринг, който е поредица от максимум 16 символа и не съдържа *blank space*. 3 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 01.c: -------------------------------------------------------------------------------- 1 | /* 2 | 1. Да се напише програма на C, която изпълнява команда date. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main(){ 10 | const char * cmd = "date"; 11 | if(execl("/bin/date", "date", "+%D", (char *)NULL) == -1) 12 | err(1,"failed to execl %s", cmd); 13 | else 14 | printf("this will never be printed\n"); 15 | } 16 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 02.c: -------------------------------------------------------------------------------- 1 | /* 2 | 2. Да се напише програма на C, която изпълнява команда ls с точно един аргумент. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv){ 9 | if(argc != 2){ 10 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 11 | } 12 | 13 | const char *cmd = "ls", *dirpath = argv[1]; 14 | 15 | if(execlp(cmd, "Pesho is listing a directory content", dirpath, 0) == -1) 16 | err(2,"could not execlp ls"); 17 | } 18 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 03.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3. Да се напише програма на C, която изпълнява команда sleep (за 60 секунди). 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | int main(void){ 9 | const char *cmd = "sleep", *arg = "60"; 10 | 11 | if(execl(cmd, "Pesho sleeps for 60 sec", arg, (char*)NULL) == -1) 12 | err(1, "could not execl %s", cmd); 13 | } 14 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 04.c: -------------------------------------------------------------------------------- 1 | /* 2 | 4. Да се напише програма на C, която създава процес дете и демонстрира принцина на конкурентност при процесите. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #define N 100000 9 | 10 | int main(void){ 11 | if(fork() > 0) 12 | for(int i=0; i < N; ++i) 13 | printf("parent\n"); 14 | else 15 | for(int i=0; i < N; ++i) 16 | printf("child\n"); 17 | exit(0); 18 | } 19 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 05.c: -------------------------------------------------------------------------------- 1 | /* 2 | 5. Да се напише програма на C, която е аналогична на предходния пример, но принуждава процеса родител да изчака 3 | детинския си процес да завърши своето изпълнение. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #define N 1000 11 | 12 | int main(void){ 13 | int status; 14 | if(fork() > 0){ 15 | wait(&status); 16 | for(int i = 0; i < N; ++i) 17 | printf("parent\n"); 18 | } else { 19 | for(int i = 0; i < N; ++i) 20 | printf("child\n"); 21 | } exit(0); 22 | } 23 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 06.c: -------------------------------------------------------------------------------- 1 | /* 2 | 6. Да се напише програма на С, която получава като параметър команда (без параметри) 3 | и при успешното ѝ изпълнение, извежда на стандартния изход името на командата. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char **argv){ 13 | if(argc != 2) 14 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 15 | 16 | const char *cmd = argv[1]; 17 | 18 | pid_t child_pid = fork(); 19 | if(child_pid == -1) 20 | err(2, "could not fork"); 21 | if(child_pid == 0) // we are in child process 22 | if(execlp(cmd, "drama lama", (char*)NULL) == -1) 23 | err(3, "could not execlp %s", cmd); 24 | 25 | int child_exit_status; 26 | if(wait(&child_exit_status) == -1) 27 | err(4, "could not wait for child"); 28 | 29 | if(!(WIFEXITED(child_exit_status))) 30 | errx(5, "child did not terminate normally"); 31 | 32 | if(WEXITSTATUS(child_exit_status)) 33 | errx(6, "child exit code not 0"); 34 | 35 | printf("command %s was successfully executed\n", cmd); 36 | 37 | exit(0); 38 | } 39 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 07.c: -------------------------------------------------------------------------------- 1 | /* 2 | 7. Да се напише програма на С, която получава като параметри три команди (без параметри), 3 | изпълнява ги последователно, като изчаква края на всяка и извежда на стандартния изход 4 | номера на завършилия процес, както и неговия код на завършване. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char **argv){ 14 | if(argc != 4) 15 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 16 | 17 | const char *cmd1 = argv[1], *cmd2 = argv[2], *cmd3 = argv[3]; 18 | 19 | pid_t cmd1_pid = fork(); 20 | if(cmd1_pid == -1) 21 | err(2, "could not fork for %s", cmd1); 22 | 23 | if(cmd1_pid == 0) // we are in child for cmd1 24 | if(execlp(cmd1, cmd1, (char*)NULL) == -1) 25 | err(3, "could not execlp %s", cmd1); 26 | 27 | int stat_cmd1; 28 | if(wait(&stat_cmd1) == -1) 29 | err(4, "could not wait for %s", cmd1); 30 | 31 | if(!WIFEXITED(stat_cmd1)) 32 | errx(5, "%s did not terminated normally", cmd1); 33 | 34 | printf("%s, pid: %d, exit code: %d\n", cmd1, cmd1_pid, WEXITSTATUS(stat_cmd1)); 35 | 36 | // ---- ---- ---- cmd1 37 | 38 | pid_t cmd2_pid = fork(); 39 | if(cmd2_pid == -1) 40 | err(6, "could not fork for %s", cmd2); 41 | 42 | if(cmd2_pid == 0) // we are in child for cmd2 43 | if(execlp(cmd2, cmd2, (char*)NULL) == -1) 44 | err(7, "could not execlp %s", cmd2); 45 | 46 | int stat_cmd2; 47 | if(wait(&stat_cmd2) == -1) 48 | err(8, "could not wait for %s", cmd2); 49 | 50 | if(!WIFEXITED(stat_cmd2)) 51 | errx(9, "%s did not terminated normally", cmd2); 52 | 53 | printf("%s, pid: %d, exit code: %d\n", cmd2, cmd2_pid, WEXITSTATUS(stat_cmd2)); 54 | 55 | // ---- ---- ---- cmd2 56 | 57 | pid_t cmd3_pid = fork(); 58 | if(cmd3_pid == -1) 59 | err(10, "could not fork for %s", cmd3); 60 | 61 | if(cmd3_pid == 0) // we are in child for cmd3 62 | if(execlp(cmd3, cmd3, (char*)NULL) == -1) 63 | err(11, "could not execlp %s", cmd3); 64 | 65 | int stat_cmd3; 66 | if(wait(&stat_cmd3) == -1) 67 | err(12, "could not wait for %s", cmd3); 68 | 69 | if(!WIFEXITED(stat_cmd3)) 70 | errx(13, "%s did not terminated normally", cmd3); 71 | 72 | printf("%s, pid: %d, exit code: %d\n", cmd3, cmd3_pid, WEXITSTATUS(stat_cmd3)); 73 | 74 | exit(0); 75 | } 76 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 08 (more precise).c: -------------------------------------------------------------------------------- 1 | /* 2 | 8. Да се напише програма на С, която получава като параметър име на файл. 3 | Създава детински процес, който записва стринга foobar във файла (ако не съществува, го създава, 4 | в противен случай го занулява), след което процеса родител прочита записаното във файла съдържание 5 | и го извежда на стандартния изход, добавяйки по един интервал между всеки два символа. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | int main(int argc, char **argv){ 18 | if(argc != 2) 19 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 20 | 21 | const char *file = argv[1]; 22 | 23 | pid_t child = fork(); 24 | if(child == -1) 25 | err(4, "could not fork"); 26 | 27 | if(child == 0){ // we are in child process 28 | ssize_t fd = open(file, O_CREAT | O_TRUNC | O_RDWR, 0644); 29 | if(fd == -1) 30 | err(5, "could not open file %s", file); 31 | 32 | const char *str = "foobar"; 33 | ssize_t len = (ssize_t)strlen(str); 34 | 35 | if(write(fd, str, len) != len){ 36 | const int olderrno = errno; 37 | close(fd); 38 | errno = olderrno; 39 | err(6, "failed to write into file %s", file); 40 | } 41 | close(fd); 42 | exit(0); 43 | } 44 | 45 | int status; 46 | if(wait(&status) == -1) 47 | err(7, "could not wait for child process"); 48 | 49 | if(!WIFEXITED(status)) 50 | errx(8, "child process did not terminate normally"); 51 | 52 | if(WEXITSTATUS(status)) 53 | errx(9, "child process did not exit with status 0"); 54 | 55 | ssize_t fd = open(file, O_RDONLY); 56 | if(fd == -1) 57 | err(10, "could not open file %s", file); 58 | 59 | uint16_t buf; 60 | ssize_t read_sz; 61 | while((read_sz = read(fd, &buf, sizeof(buf))) > 0){ 62 | while(write(1, &buf, sizeof(buf)) != sizeof(buf)){ 63 | const int olderrno = errno; 64 | close(fd); 65 | errno = olderrno; 66 | err(99, "could not write to stdout"); 67 | } 68 | write(1," ", 1); // TODO: check this write 69 | } 70 | if(read_sz == -1){ 71 | const int olderrno = errno; 72 | close(fd); 73 | errno = olderrno; 74 | err(99, "could not read from file %s", file); 75 | } 76 | write(1, "\n", 1); // TODO: check this write 77 | 78 | exit(0); 79 | } 80 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 09.c: -------------------------------------------------------------------------------- 1 | /* 2 | 9. Да се напише програма на C, която която създава файл в текущата директория и генерира два процесa, 3 | които записват низовете foo и bar в създадения файл. 4 | Програмата не гарантира последователното записване на низове. 5 | Променете програмата така, че да записва низовете последователно, като първия е foo. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | void err_handler(int exit_code, const char *msg, int errnum, ssize_t fd){ 17 | if(fd != -1) close(fd); 18 | errno = errnum; 19 | err(exit_code, "error while %s", msg); 20 | } 21 | 22 | int main(void){ 23 | ssize_t fd = open("foobar.txt", O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP/* equiv. to 0644 */); 24 | if(fd == -1) 25 | err(1, "error while opening file foobar.txt"); 26 | close(fd); 27 | 28 | pid_t child_pid1 = fork(); 29 | if(child_pid1 == -1) 30 | err_handler(2, "fork in first child", errno, -1); 31 | 32 | if(child_pid1 == 0){ // we are in first child process 33 | ssize_t fd1 = open("foobar.txt", O_WRONLY | O_APPEND); 34 | if(fd1 == -1) 35 | err_handler(3, "opening foobar.txt in first child", errno, -1); 36 | if(write(fd, "foo", 3) != 3) 37 | err_handler(4, "writing into foobar.txt in first child", errno, fd1); 38 | close(fd1); 39 | exit(0); 40 | } 41 | 42 | if(wait(NULL) == -1) err_handler(5, "waiting first child", errno, -1); // comment to unorder child processes 43 | 44 | const pid_t child_pid2 = fork(); 45 | if(child_pid2 == -1) 46 | err_handler(5, "fork second child", errno, -1); 47 | 48 | if(child_pid2 == 0){ // we are in second child process 49 | ssize_t fd2 = open("foobar.txt", O_WRONLY | O_APPEND); 50 | if(fd2 == -1) 51 | err_handler(6, "opening foobar.txt in second child", errno, fd2); 52 | if(write(fd2, "bar\n", 4) != 4) 53 | err_handler(7, "writing into foobar.txt in second child", errno, fd2); 54 | close(fd2); 55 | exit(0); 56 | } 57 | 58 | if(wait(NULL) == -1) 59 | err(8,"could not wait all children processes"); 60 | 61 | exit(0); 62 | } 63 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 10.c: -------------------------------------------------------------------------------- 1 | /* 2 | 10. Да се напише програма на C, която получава като параметри от команден ред две команди (без параметри). 3 | Изпълнява първата. Ако тя е завършила успешно изпълнява втората. Ако не, завършва с код -1. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char **argv){ 11 | if(argc != 3) 12 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 13 | 14 | const char *cmd1 = argv[1], *cmd2 = argv[2]; 15 | 16 | const pid_t cmd1_pid = fork(); 17 | if(cmd1_pid == -1) 18 | err(2, "could not fork for %s", cmd1); 19 | 20 | if(cmd1_pid == 0) // we are in child for cmd1 21 | if(execlp(cmd1, cmd1, (char*)NULL) == -1) 22 | err(3, "could not execlp %s", cmd1); 23 | 24 | int cmd1_stat; 25 | if(wait(&cmd1_stat) == -1) 26 | err(4, "could not wait child process for command %s", cmd1); 27 | 28 | if(!WIFEXITED(cmd1_stat)) 29 | errx(-1, "%s did not terminated normally", cmd1); 30 | 31 | if(WEXITSTATUS(cmd1_stat)) 32 | errx(-1, "%s exit status not 0", cmd1); 33 | 34 | const pid_t cmd2_pid = fork(); 35 | if(cmd2_pid == -1) 36 | err(5, "could not fork for %s", cmd2); 37 | 38 | if(cmd2_pid == 0) // we are in child for cmd2 39 | if(execlp(cmd2, cmd2, (char*)NULL) == -1) 40 | err(6, "could not execlp %s", cmd2); 41 | 42 | wait(NULL); 43 | exit(0); 44 | } 45 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 11.c: -------------------------------------------------------------------------------- 1 | /* 2 | 11. Да се напише програма на C, която изпълнява последователно подадените ѝ като параметри команди, 3 | като реализира следната функционалност постъпково: 4 | - main cmd1 ... cmdN Изпълнява всяка от командите в отделен дъщерен процес. 5 | - ... при което се запазва броя на изпълнените команди, които са дали грешка и броя на завършилите успешно. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char **argv){ 14 | size_t successful = 0, failed = 0; 15 | 16 | for(int i = 1; i< argc; ++i){ 17 | const char *cmd = argv[i]; 18 | const pid_t child_pid = fork(); 19 | if(child_pid == -1) 20 | err(1, "failed to fork %s", cmd); 21 | 22 | if(child_pid == 0) 23 | if(execlp(cmd, cmd, (char*)NULL) == -1) 24 | err(2,"error while execlp command %s", cmd); 25 | 26 | int status; 27 | if(wait(&status) == -1) 28 | err(2,"could not wait for current child"); 29 | 30 | if(WIFEXITED(status)){ 31 | if(WEXITSTATUS(status)) ++failed; 32 | else ++successful; 33 | } else ++failed; 34 | } 35 | 36 | printf("successful: %zu, failed: %zu\n", successful, failed); 37 | exit(0); 38 | } 39 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 13 (2nd solution).c: -------------------------------------------------------------------------------- 1 | /* 2 | 13. Да се напише програма на C, която получава като командни параметри две команди (без параметри). 3 | Изпълнява ги едновременно и извежда на стандартния изход номера на процеса на първата завършила успешно. 4 | Ако нито една не завърши успешно извежда -1. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char **argv){ 14 | if(argc != 3) 15 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 16 | 17 | const char *cmd1 = argv[1], *cmd2 = argv[2]; 18 | 19 | 20 | const pid_t child1 = fork(); 21 | if(child1 == -1) 22 | err(2, "could not fork for child 1"); 23 | 24 | if(child1 == 0) // we are in child 1 25 | if(execlp(cmd1, cmd1, (char*)NULL) == -1) 26 | err(3, "could not execlp %s", cmd1); 27 | 28 | const pid_t child2 = fork(); 29 | if(child2 == -1) 30 | err(4, "could not fork for child 2"); 31 | 32 | if(child2 == 0) 33 | if(execlp(cmd2, cmd2, (char*)NULL) == -1) 34 | err(5, "could not execlp %s", cmd2); 35 | 36 | 37 | int status1, status2; 38 | 39 | printf("%s: %d\n", cmd1, child1); 40 | printf("%s: %d\n", cmd2, child2); 41 | 42 | const pid_t first = wait(&status1); 43 | if(first == -1) 44 | err(6, "could not wait for any process"); 45 | 46 | if(WIFEXITED(status1) && !WEXITSTATUS(status1)){ 47 | printf("%d\n", first); 48 | } else { // the first one has finished but not successsfully 49 | const pid_t second = wait(&status2); 50 | if(second == -1) 51 | err(7, "could not wait for second process"); 52 | 53 | if(WIFEXITED(status2) && !WEXITSTATUS(status2)){ 54 | printf("%d\n", second); 55 | } else printf("%d\n", -1); 56 | } 57 | exit(0); 58 | } 59 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 13.c: -------------------------------------------------------------------------------- 1 | /* 2 | 13. Да се напише програма на C, която получава като командни параметри две команди (без параметри). 3 | Изпълнява ги едновременно и извежда на стандартния изход номера на процеса на първата завършила успешно. 4 | Ако нито една не завърши успешно извежда -1. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char **argv){ 14 | if(argc != 3) 15 | errx(1, "Invalid number of arguments. Usage %s ", argv[0]); 16 | 17 | const char *cmd1 = argv[1], *cmd2 = argv[2]; 18 | 19 | const pid_t child_pid1 = fork(); 20 | if(child_pid1 == -1) 21 | err(2, "could not fork (1st child)"); 22 | 23 | if(child_pid1 == 0) // we are in first child process 24 | if(execlp(cmd1, cmd1, (char *)NULL) == -1) 25 | err(3, "error while execlp %s", cmd1); 26 | 27 | pid_t child_pid2 = fork(); 28 | if(child_pid2 == -1) 29 | err(4, "could not fork (2nd child)"); 30 | 31 | if(child_pid2 == 0) // we are in second child process 32 | if(execlp(cmd2, cmd2, (char *)NULL) == -1) 33 | err(5, "error while execlp %s", cmd2); 34 | 35 | int status, flag = 0; 36 | const pid_t first_finished_pid = wait(&status); 37 | if(first_finished_pid == -1) 38 | err(6, "could not wait any child"); 39 | 40 | if(WIFEXITED(status)){ 41 | if(WEXITSTATUS(status) == 0){ 42 | printf("PID of first finished process: %d\n", first_finished_pid); 43 | flag = 1; 44 | } 45 | } 46 | 47 | if(!flag){ 48 | const pid_t try_second_pid = wait(&status); 49 | 50 | if(WIFEXITED(status)){ 51 | if(WEXITSTATUS(status) == 0){ 52 | printf("PID of first finished process: %d\n", try_second_pid); 53 | flag = 1; 54 | } 55 | } 56 | } 57 | 58 | // guarantee that the children will terminate before the parent (which is not necessary) 59 | if(wait(NULL) == -1) 60 | err(7, "could not wait children"); 61 | 62 | if(!flag) 63 | printf("-1\n"); 64 | 65 | exit(0); 66 | } 67 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 43.c: -------------------------------------------------------------------------------- 1 | /* 2 | cat file.txt | sort 3 | a 4 | 5 | we can transform the pipeline into: 6 | 7 | sort file.txt 8 | 9 | then we will only need to execlp("sort", "sorting file", argv[1], (char *)NULL); 10 | But the task wants us to do it with pipeline, so: 11 | 12 | Pseudo code for the algorithm: 13 | 14 | init1 15 | fork 16 | child "cat" 17 | init2 18 | sort 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | int main(int argc, char **argv){ 27 | if(argc != 2) 28 | err(1, "Invalid number of arguments. Usage: %s ", argv[0]); 29 | 30 | const char *file = argv[1]; 31 | 32 | const ssize_t fd_check = open(file, O_RDONLY); 33 | if(fd_check == -1) 34 | err(2, "colud not open %s in read mode", file); 35 | 36 | close(fd_check); 37 | 38 | int a[2]; 39 | if(pipe(a) == -1) 40 | err(3, "could not pipe a"); 41 | 42 | const pid_t child_cat = fork(); 43 | if(child_cat == -1) 44 | err(4, "could not fork"); 45 | 46 | if(child_cat == 0){ // we are in child for cat 47 | close(a[0]); 48 | if(dup2(a[1], 1) == -1) 49 | err(5, "could not dup2"); 50 | 51 | if(execl("/bin/cat", "cat", file, (char *)NULL) == -1) 52 | err(6, "could not execl cat"); 53 | } 54 | close(a[1]); 55 | 56 | if(dup2(a[0], 0) == -1) 57 | err(7, "could not dup2"); 58 | 59 | if(execlp("sort", "pesho_sort", (char *)NULL) == -1) 60 | err(8, "could not exec"); 61 | } 62 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 44 (1st sol).c: -------------------------------------------------------------------------------- 1 | // 1st solution 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(void){ 10 | while(1){ 11 | if(write(1, "Pesho's simple prompt: ", 23) != 23) 12 | err(1, "could not write the prompt name to stdout"); 13 | 14 | char cmd[1<<5]; 15 | ssize_t read_sz = read(0, &cmd, sizeof(cmd)); 16 | if(read_sz == -1) 17 | err(2, "could not read from stdin"); 18 | 19 | //changing newline to terminating zero '\n' -> '\0': 20 | cmd[read_sz - 1] = '\0'; 21 | 22 | if(strcmp(cmd, "exit") == 0) 23 | break; 24 | 25 | const char *bin = "/bin/"; 26 | char buf[1<<6]; 27 | strcpy(buf,bin); // copy /bin/ 28 | strcat(buf,cmd); // append cmd 29 | 30 | const pid_t child = fork(); 31 | if(child == -1){ 32 | warn("could not fork for %s", buf); 33 | continue; 34 | } 35 | 36 | if(child == 0) // we are in child for exec cmd in /bin 37 | if(execl(buf, "Pesho's process", (char*)NULL) == -1) 38 | err(3, "could not execl %s", buf); 39 | 40 | if(wait(NULL) == -1) 41 | err(4, "could not wait %s", buf); 42 | } 43 | exit(0); 44 | } 45 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 44 (2nd sol).c: -------------------------------------------------------------------------------- 1 | // 2nd solution 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(void){ 10 | char buf[1<<6]; 11 | ssize_t read_sz; 12 | 13 | const char *prompt = "Stamat's simple prompt: "; 14 | const ssize_t len = (ssize_t)strlen(prompt); 15 | 16 | if(write(1, prompt, len) != len) 17 | err(1, "could not write prompt to stdout"); 18 | 19 | while((read_sz = read(0, buf, sizeof(buf))) > 0){ 20 | char cmd[1<<6]; 21 | ssize_t i = 0; 22 | for(; i < read_sz; ++i){ 23 | if(buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\t') 24 | break; 25 | cmd[i] = buf[i]; 26 | } 27 | cmd[i]='\0'; 28 | 29 | if(strlen(cmd) == 0 || strcmp(cmd, "exit") == 0) 30 | break; 31 | 32 | const pid_t child = fork(); 33 | if(child == -1) 34 | err(2, "could not fork"); 35 | 36 | if(child == 0) // we are in child process for exec cmd 37 | if(execlp(cmd, cmd, (char*)NULL) == -1) 38 | err(3, "could not execlp: %s", cmd); 39 | 40 | if(wait(NULL) == -1) 41 | err(4, "could not wait"); 42 | 43 | if(write(1, prompt, len) != len) 44 | err(5, "could not write ptompt to stdout"); 45 | } 46 | exit(0); 47 | } 48 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 45.c: -------------------------------------------------------------------------------- 1 | /* 2 | cut -d: -f7 /etc/passwd | sort | uniq -c | sort 3 | a b c 4 | 5 | Pseudo code for the algorithm: 6 | 7 | init1 8 | fork 9 | child "cut [..]" 10 | init2 11 | fork 12 | child "sort" 13 | init3 14 | fork 15 | child "uniq [..]" 16 | init4 17 | sort 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | int main(void){ 24 | // init1 25 | int a[2]; 26 | if(pipe(a) == -1) 27 | err(1, "could not pipe a"); 28 | 29 | const pid_t child_cat = fork(); 30 | if(child_cat == -1) 31 | err(2, "could not fork for cut"); 32 | 33 | if(child_cat == 0){ // child process for cut 34 | close(a[0]); 35 | if(dup2(a[1], 1) == -1) 36 | err(3, "could not dup2"); 37 | if(execlp("cut", "Pesho is cutting", "-d:", "-f7", "/etc/passwd", (char *)NULL) == -1) 38 | err(4, "could not execlp cut with args"); 39 | } 40 | close(a[1]); 41 | //init2 42 | int b[2]; 43 | if(pipe(b) == -1) 44 | err(5, "could not pipe"); 45 | 46 | const pid_t child_sort = fork(); 47 | if(child_sort == -1) 48 | err(6, "could not fork for sort"); 49 | 50 | if(child_sort == 0){ // child process for sort 51 | if(dup2(a[0],0) == -1) 52 | err(7, "could not dup2"); 53 | close(b[0]); 54 | if(dup2(b[1], 1) == -1) 55 | err(1, "could not dup2"); 56 | if(execlp("sort", "Pesho is sorting", (char *)NULL) == -1){ 57 | err(8, "could not execlp sort"); 58 | } 59 | } 60 | close(b[1]); 61 | //init3 62 | int c[2]; 63 | if(pipe(c) == -1) 64 | err(9, "could not pipe c"); 65 | 66 | const pid_t child_uniq = fork(); 67 | if(child_uniq == -1) 68 | err(10,"could not fork for uniq"); 69 | 70 | if(child_uniq == 0){ // child process for uniq 71 | if(dup2(b[0], 0) == -1) 72 | err(11, "could not dup2"); 73 | close(c[0]); 74 | if(dup2(c[1], 1) == -1) 75 | err(12, "could not dup2"); 76 | if(execlp("uniq", "Pesho filters out repeated lines and counts them", "-c", (char *)NULL) == -1){ 77 | err(13, "could not execlp uniq with args"); 78 | } 79 | } 80 | close(c[1]); 81 | //init 4 and executing final command in parent process 82 | if(dup2(c[0],0) == -1) 83 | err(14, "could not dup"); 84 | if(execlp("sort", "Pesho is sorting again", (char *)NULL) == -1) 85 | err(15, "could not exec"); 86 | } 87 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 46.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define arg_size 4 8 | #define max_args 2 9 | 10 | void print_arr(char * arr){ 11 | for(int i = 0; arr[i] != '\0'; ++i) 12 | write(1, arr + i, 1); 13 | 14 | write(1, " ", 1); 15 | } 16 | 17 | void print_cmd_args(char args[][arg_size+1]){ 18 | for(int i = 0; args[i][0] != '\0'; ++i) 19 | print_arr(args[i]); 20 | 21 | write(1, "\n", 1); 22 | } 23 | 24 | void print_exec_args(char *args[max_args + 1]){ 25 | for(int i = 0; args[i] != NULL; ++i) 26 | print_arr(args[i]); 27 | write(1, "\n", 1); 28 | } 29 | 30 | void exec_cmd(char args[][arg_size + 1], char *cmd){ 31 | pid_t pid = fork(); 32 | if(pid == 0){ 33 | char *execv_args[max_args + 2]; 34 | execv_args[0] = cmd; 35 | 36 | int i = 1, j = 0; 37 | while(args[j][0] != '\0') 38 | execv_args[i++] = args[j++]; 39 | 40 | execv_args[i] = NULL; 41 | if(execvp(cmd, execv_args) == -1) 42 | err(11, "could not exec"); 43 | return; 44 | } 45 | wait(NULL); 46 | } 47 | 48 | int main(int argc, char **argv){ 49 | char cmd[arg_size + 1]; 50 | if(argc == 1) 51 | strcpy(cmd, "echo"); 52 | else if(argc == 2 && strlen(cmd) < 5) 53 | strcpy(cmd, argv[1]); 54 | else 55 | errx(1, "Invalid number of arguments. Usage: %s [cmd]", argv[0]); 56 | char arg[arg_size + 1]; 57 | int indx = 0, row = 0; 58 | char cmd_args[max_args + 1][arg_size + 1]; 59 | ssize_t read_size = -1; 60 | while(((read_size = read(0, arg + indx, 1)) > 0) && indx <= arg_size){ 61 | if(row == max_args){ 62 | cmd_args[max_args][0] = '\0'; 63 | exec_cmd(cmd_args, cmd); 64 | row = 0; 65 | } 66 | if(arg[indx] == '\n' || arg[indx] == ' '){ 67 | arg[indx] = '\0'; 68 | strcpy(cmd_args[row++], arg); 69 | indx = 0; 70 | } else { 71 | ++indx; 72 | } 73 | } 74 | 75 | if(read_size == -1) 76 | err(2, "could not read from stdin"); 77 | 78 | if(indx > arg_size) 79 | errx(3, "argument out of bounds"); 80 | 81 | if(row != 0){ 82 | cmd_args[row][0] = '\0'; 83 | exec_cmd(cmd_args, cmd); 84 | } 85 | exit(0); 86 | } 87 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 48 (1st sol).c: -------------------------------------------------------------------------------- 1 | // 1st solution 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int log_line(const char *path, time_t start, time_t end, int exit_code){ 17 | char buf[3 * sizeof(intmax_t) + 4]; 18 | sprintf(buf, "%jd %jd %d\n", (intmax_t)start, (intmax_t)end, exit_code); 19 | ssize_t fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0644); 20 | if(fd == -1){ 21 | return -1; 22 | } 23 | int len = strlen(buf); 24 | if(write(fd, buf, len) != len){ 25 | errno = EIO; 26 | return -1; 27 | } 28 | if(close(fd) == -1) return -1; 29 | return 0; 30 | } 31 | 32 | int main(int argc, char **argv){ 33 | if(argc < 3){ 34 | errx(1, "INvalid number of arguments. Usage: %s [args]", argv[0]); 35 | } 36 | 37 | char *duration = argv[1]; 38 | if( *duration < '0' || *duration > '9' || duration[1]){ 39 | errx(2, "Invalid first argument"); 40 | } 41 | 42 | int cond_old, cond_new = 0; 43 | do{ 44 | time_t start = time(NULL); 45 | const pid_t p = fork(); 46 | if(p == 0){ 47 | if(execvp(argv[2], argv + 2) == -1){ 48 | err(2, "could not exec"); 49 | } 50 | } 51 | 52 | if(p == -1){ 53 | err(3, "could not fork"); 54 | } 55 | 56 | int status; 57 | if(wait(&status) == -1){ 58 | err(4, "could not wait"); 59 | } 60 | 61 | time_t end = time(NULL); 62 | const int exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : 129; 63 | 64 | if(log_line("run.log", start, end, exitcode) < 0){ 65 | err(5, "error"); 66 | } 67 | 68 | cond_old = cond_new; 69 | cond_new = WEXITSTATUS(status) && end - start < *duration - '0'; 70 | 71 | } while(!cond_old || !cond_new); 72 | 73 | exit(0); 74 | } 75 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 48 (2nd sol).c: -------------------------------------------------------------------------------- 1 | // 2nd solution 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int execChild(char *args[]){ 15 | int pid = fork(); 16 | if(pid == -1){ 17 | err(1, "could not fork"); 18 | } 19 | if(pid == 0){ 20 | if(execvp(args[0], args) == -1){ 21 | err(2, "could not exec"); 22 | } 23 | } 24 | int status; 25 | wait(&status); 26 | if(WIFEXITED(status)) 27 | return WEXITSTATUS(status); 28 | return 1; 29 | } 30 | 31 | void flog(time_t start, time_t end, int status){ 32 | int fd = open("log.txt", O_RDWR | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP); 33 | if(fd == -1){ 34 | err(4, "could not open file log.txt"); 35 | } 36 | char logline[30]; 37 | 38 | ssize_t len = 0; 39 | 40 | sprintf(logline, "%ld %ld %d\n", start, end, status); 41 | len = strlen(logline); 42 | if(write(fd, logline, len) != len){ 43 | err(5, "could not write in log.txt"); 44 | } 45 | 46 | close(fd); 47 | } 48 | 49 | bool execute(int lim, char *args[]){ 50 | time_t start = time(NULL); 51 | int status = execChild(args); 52 | time_t end = time(NULL); 53 | 54 | flog(start, end, status); 55 | 56 | return (((end - start) < lim) && status !=0); 57 | } 58 | 59 | 60 | int main(int argc, char **argv){ 61 | if(argc < 3){ 62 | errx(3, "Invalid number of arguments. Usage: %s [args]", argv[0]); 63 | } 64 | 65 | char c = argv[1][0]; 66 | 67 | if(c > '9' || c < '0' || argv[1][1] != '\0') 68 | errx(99, "Invalid digit argument"); 69 | 70 | int sec = (argv[1][0] - '0'); 71 | 72 | 73 | 74 | char *args[12]; 75 | 76 | int i = 2, cnt = 0; 77 | for(; i < argc; ++i){ 78 | args[cnt++] = argv[i]; 79 | } 80 | args[cnt] = NULL; 81 | 82 | int condcnt = 0; 83 | while(condcnt < 2) { 84 | if(execute(sec, args) != 0) 85 | condcnt++; 86 | else 87 | condcnt = 0; 88 | } 89 | exit(0); 90 | } 91 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task 48 test script for 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FILE="tmp.txt" 4 | 5 | if [ -f "${FILE}" ]; then 6 | RUN_INDX="$(cat "${FILE}")" 7 | else 8 | RUN_INDX=0 9 | fi 10 | 11 | RUN_INDX="$(expr $RUN_INDX + 1)" 12 | echo "${RUN_INDX}" > "${FILE}" 13 | 14 | case "${RUN_INDX}" in 15 | 1) sleep 3; exit 2 ;; 16 | 2) sleep 3; exit 3 ;; 17 | 3) sleep 0.5; exit 0 ;; 18 | 4) sleep 1; exit 1 ;; 19 | 5) sleep 1; exit 0 ;; 20 | 6) sleep 1; exit 1 ;; 21 | 7) sleep 1; exit 1 ;; 22 | *) echo "this should never be written" >&2; sleep 1; exit 1 ;; 23 | esac 24 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task P01 (2nd solution).c: -------------------------------------------------------------------------------- 1 | /* 2 | T1 - Да се напише програма на C, която приема аргумент - име на файл. Програмата да: 3 | - записва във файла 'fo' 4 | - създава child процес, който записва 'bar\n' 5 | - parent-а, след като изчака child процеса, записва 'o\n' 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main(int argc, char **argv){ 15 | if(argc != 2) 16 | errx(1, "Invalid number of arguments. Uage: %s ", argv[0]); 17 | 18 | const char *file = argv[1]; 19 | 20 | ssize_t fd = open(file, O_CREAT | O_TRUNC | O_RDWR, 0644); 21 | if(fd == -1) 22 | err(2, "could not open file %s", file); 23 | 24 | if(write(fd, "fo", 2) != 2){ 25 | const int olderrno = errno; 26 | close(fd); 27 | errno = olderrno; 28 | err(3, "could not write to file %s", file); 29 | } 30 | close(fd); 31 | 32 | const pid_t child = fork(); 33 | if(child == -1) 34 | err(4, "could not fork process for child"); 35 | 36 | if(child == 0){ // we are in child process 37 | fd = open(file, O_APPEND | O_WRONLY); 38 | if(fd == -1) 39 | err(5, "could not open file %s", file); 40 | 41 | if(write(fd, "bar\n", 4) != 4){ 42 | const int olderrno = errno; 43 | close(fd); 44 | errno = olderrno; 45 | err(6, "could not write to file %s", file); 46 | } 47 | close(fd); 48 | exit(0); 49 | } 50 | 51 | 52 | if(wait(NULL) == -1) 53 | err(7, "could not wait for child process"); 54 | 55 | fd = open(file, O_APPEND | O_WRONLY); 56 | if(fd == -1) 57 | err(8, "could not open file %s", file); 58 | 59 | if(write(fd, "o\n", 2) != 2){ 60 | const int olderrno = errno; 61 | close(fd); 62 | errno = olderrno; 63 | err(9, "could not write to file %s", file); 64 | } 65 | 66 | close(fd); 67 | exit(0); 68 | } 69 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task P01.c: -------------------------------------------------------------------------------- 1 | /* 2 | T1 - Да се напише програма на C, която приема аргумент - име на файл. Програмата да: 3 | - записва във файла 'fo' 4 | - създава child процес, който записва 'bar\n' 5 | - parent-а, след като изчака child процеса, записва 'o\n' 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main(int argc, char **argv){ 15 | if(argc!=2) 16 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 17 | 18 | const char *file = argv[1]; 19 | 20 | ssize_t fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0644); 21 | if(fd == -1) 22 | err(2, "error while opening file %s", file); 23 | 24 | const char *str1 = "foo\n", *str2 = "bar\n"; 25 | 26 | if(write(fd, str1, 2) != 2){ 27 | const int olderrno = errno; 28 | close(fd); 29 | errno = olderrno; 30 | err(3, "error while writing into file %s", file); 31 | } 32 | close(fd); 33 | 34 | const pid_t child_pid = fork(); 35 | if(child_pid == -1) 36 | err(4, "could not fork"); 37 | 38 | if(child_pid == 0){ 39 | fd = open(filename, O_WRONLY | O_APPEND); 40 | if(write(fd, str2, 4) != 4){ 41 | const int olderrno = errno; 42 | close(fd); 43 | errno = olderrno; 44 | err(5, "failed to write into file %s in child process", file); 45 | } 46 | exit(0); 47 | } 48 | 49 | int child_status; 50 | const pid_t wait_code = wait(&child_status); 51 | 52 | if(wait_code == -1){ 53 | const int olderrno = errno; 54 | close(fd); 55 | errno = olderrno; 56 | err(6, "could not wait for child"); 57 | } 58 | 59 | if(!WIFEXITED(child_status)){ 60 | const int olderrno = errno; 61 | close(fd); 62 | errno = olderrno; 63 | err(7, "child did not terminate normally"); 64 | } 65 | 66 | if(WEXITSTATUS(child_status) != 0){ 67 | err(8, "child exit code not 0, file should be already closed"); 68 | } 69 | 70 | fd = open(filename, O_WRONLY | O_APPEND); 71 | if(write(fd, str1 + 2, 2) != 2){ 72 | const int olderrno = errno; 73 | close(fd); 74 | errno = olderrno; 75 | err(9, "failed to write into file %s in parent process", file); 76 | } 77 | 78 | close(fd); 79 | exit(0); 80 | } 81 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task P02.c: -------------------------------------------------------------------------------- 1 | /* 2 | T2 - Напишете програма на C, която демонстрира комуникация през pipe между parent и child процеси. 3 | Parent-ът трябва да изпраща стринга, получен като първи аргумент на командния ред към child-а, който 4 | да го отпечатва на стандартния изход. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char **argv){ 13 | if(argc != 2) 14 | errx(1, "Invalid number of arguments. Usage %s ", argv[0]); 15 | 16 | const char *str = argv[1]; 17 | ssize_t len = (ssize_t)strlen(str); 18 | 19 | int p[2]; 20 | if(pipe(p) == -1) 21 | err(2, "could not create pipe"); 22 | 23 | const pid_t child_pid = fork(); 24 | if(child_pid == -1) 25 | err(3, "could not fork child process"); 26 | 27 | if(child_pid == 0){ // we are in child process 28 | close(p[1]); 29 | 30 | if(read(p[0], &str, len) == len){ 31 | if(write(1, &str, len) != len) 32 | err(4, "could not write to stdout"); 33 | } else 34 | err(5,"error while reading in child process"); 35 | 36 | close(p[0]); 37 | exit(0); 38 | } 39 | 40 | close(p[0]); 41 | if(write(p[1], str, len) != len) 42 | err(6, "error while writing in parent"); 43 | 44 | close(p[1]); 45 | wait(NULL); 46 | exit(0); 47 | } 48 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Task P03.c: -------------------------------------------------------------------------------- 1 | /* 2 | T3 - Напишете програма на C, която демонстрира употребата на dup/dup2 между parent и child процеси. 3 | Parent-ът трябва да изпраща стринга, получен като първи аргумент на командния ред към child-а, 4 | където той да може да се чете от stdin. Child процесът да изпълнява wc -c. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main(const int argc, const char * const argv[]){ 15 | if(argc !=2 ) 16 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 17 | const char *str = argv[1]; 18 | int p[2]; 19 | 20 | if(pipe(p) == -1) 21 | err(2, "could not create pipe"); 22 | 23 | const pid_t child_pid = fork(); 24 | if(child_pid == -1) 25 | err(3, "could not fork"); 26 | 27 | if(child_pid == 0){ // we are in child process 28 | close(p[1]); 29 | close(0); 30 | dup(p[0]); 31 | // dup2(pf[0], 0); 32 | if(execlp("wc", "wc", "-c", (char *)NULL) == -1) 33 | err(4, "could not exec"); 34 | } 35 | 36 | close(p[0]); 37 | ssize_t len = (ssize_t)strlen(str); 38 | if(write(p[1], str, len) != len) 39 | err(5, "error while writing in parent process into pipe"); 40 | 41 | close(p[1]); 42 | wait(NULL); 43 | 44 | exit(0); 45 | } 46 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/bar.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char **argv){ 8 | if(argc !=2) 9 | errx(1, "Invalid number of arguments. Usage %s ", argv[0]); 10 | 11 | const char *cmd = argv[1]; 12 | 13 | int fdp = open("mypipe", O_RDONLY); 14 | if(fdp == -1) 15 | err(2, "could not open named pipe"); 16 | 17 | const pid_t child = fork(); 18 | if(child == -1) 19 | err(3, "could not fork"); 20 | 21 | if(child == 0){ // child process 22 | if(dup2(fdp, 0) == -1) 23 | err(3, "could not dup2"); 24 | 25 | if(execlp(cmd, cmd, (char *)NULL) == -1) 26 | err(4, "could not execlp"); 27 | } 28 | 29 | if(child > 0){ // parent process 30 | if(wait(NULL) == -1) 31 | err(5, "could not wait for child"); 32 | 33 | if(unlink("mypipe") == -1) 34 | err(6, "could not remove named pipe"); 35 | exit(0); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/cat a.txt | sort | uniq (long).c: -------------------------------------------------------------------------------- 1 | /* 2 | cat a.txt | sort | uniq 3 | a b 4 | 5 | init1 6 | fork 7 | child "cat" 8 | init2 9 | fork 10 | child "sort" 11 | init3 12 | uniq 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | int main(void){ 20 | int a[2]; 21 | if(pipe(a) == -1) 22 | err(1, "could not pipe a"); 23 | 24 | pid_t child_pid = fork(); 25 | if(child_pid == -1) 26 | err(2, "could not fork"); 27 | 28 | if(child_pid == 0){ // we are in child "cat" 29 | close(a[0]); 30 | dup2(a[1], 1); // TODO: check dup2 31 | if(execlp("cat", "cat", "a.txt", (char *)NULL) == -1) 32 | err(3, "could not exec"); 33 | } 34 | close(a[1]); 35 | 36 | int b[2]; 37 | if(pipe(b) == -1) 38 | err(4, "could not pipe b"); 39 | 40 | child_pid = fork(); 41 | if(child_pid == -1) 42 | err(5, "could not fork"); 43 | 44 | if(child_pid == 0){ // we are in child "sort" 45 | dup2(a[0], 0); // TODO: check dup2 46 | close(b[0]); 47 | dup2(b[1],1); // TODO: check dup2 48 | if(execlp("sort", "sort", (char *)NULL) == -1) 49 | err(6, "could not exec"); 50 | } 51 | 52 | close(b[1]); 53 | dup2(b[0],0); // TODO: check dup2 54 | 55 | if(execlp("uniq", "uniq", (char *)NULL) == -1) 56 | err(7, "could not exec"); 57 | } 58 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/cat a.txt | sort | uniq (short).c: -------------------------------------------------------------------------------- 1 | /* 2 | cat a.txt | sort | uniq 3 | a b 4 | 5 | since sort works with files, we can rearrange the pipeline like this: 6 | 7 | sort a.txt | uniq 8 | a 9 | 10 | init1 11 | fork 12 | child "sort" 13 | init2 14 | uniq 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | int main(void){ 22 | int a[2]; 23 | if(pipe(a) == -1) 24 | err(1, "could not pipe a"); 25 | 26 | pid_t child_pid = fork(); 27 | if(child_pid == -1) 28 | err(2, "could not fork"); 29 | 30 | if(child_pid == 0){ // we are in child "sort" 31 | close(a[0]); 32 | close(1); // to be more precise 33 | dup(a[1]); // TODO: check dup 34 | 35 | if(execlp("sort", "sort", "a.txt", (char *)NULL) == -1) 36 | err(3, "could not exec"); 37 | } 38 | close(a[1]); 39 | close(0); // to be more precise 40 | dup(a[0]); // TODO: check dup 41 | 42 | if(execlp("uniq", "uniq", (char *)NULL) == -1) 43 | err(4, "could not exec"); 44 | } 45 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/cat passwd.txt | cut -d ':' -f 7 | sort | uniq.c: -------------------------------------------------------------------------------- 1 | /* 2 | cat ./passwd.txt | cut -d ':' -f 7 | sort | uniq 3 | a b c 4 | since cut can accept file as argument, we can transform the pipeline into: 5 | 6 | cut -d: -f7 ./passwd.txt | sort | uniq 7 | a b 8 | 9 | now we have 2 pipes instead of 3 10 | 11 | init1 12 | fork 13 | child "cut" 14 | init2 15 | fork 16 | child "sort" 17 | init3 18 | uniq 19 | 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | int main(void){ 26 | int a[2]; 27 | if(pipe(a) == -1) 28 | err(1, "could not pipe a"); 29 | 30 | const pid_t child_cut = fork(); 31 | if(child_cut == -1) 32 | err(2, "could not fork for cut"); 33 | 34 | if(child_cut == 0){ // we are in child for cut 35 | close(a[0]); 36 | if(dup2(a[1],1) == -1) 37 | err(3, "could not dup2"); 38 | 39 | if(execlp("cut", "Pesho is cutting", "-d:", "-f7", "/etc/passwd", (char *)NULL) == -1) 40 | err(4, "could not execlp cut with args"); 41 | } 42 | close(a[1]); 43 | 44 | int b[2]; 45 | if(pipe(b) == -1) 46 | err(5, "could not pipe b"); 47 | 48 | const pid_t child_sort = fork(); 49 | if(child_sort == -1) 50 | err(6, "could not fork"); 51 | 52 | if(child_sort == 0){ // we are in child for sort 53 | if(dup2(a[0], 0) == -1) 54 | err(7, "could not dup2"); 55 | 56 | close(b[0]); 57 | if(dup2(b[1],1) == -1) 58 | err(8, "could not dup2"); 59 | 60 | if(execlp("sort", "Pesho is sorting", (char *)NULL) == -1) 61 | err(9, "could not execlp sort"); 62 | } 63 | close(b[1]); 64 | // we are in parent process for the final command 65 | if(dup2(b[0], 0) == -1) 66 | err(10, "could not dup2"); 67 | 68 | if(execlp("uniq", "Pesho filters out the repeated lines", (char *)NULL) == -1) 69 | err(11, "could not execlp uniq"); 70 | } 71 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/classic deadlock example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv){ 7 | if(argc!=2){ 8 | errx(1, "Invalid number of arguments. Usage %s ", argv[0]); 9 | } 10 | 11 | const char *str = argv[1]; 12 | 13 | int pf[2]; 14 | if(pipe(pf) == -1){ 15 | errx(2, "could not create pipe"); 16 | } 17 | 18 | const pid_t child_pid = fork(); 19 | if(child_pid == -1){ 20 | err(3, "could not fork child process"); 21 | } 22 | 23 | if(child_pid == 0){ 24 | // we are in child process 25 | close(pf[1]); 26 | char buf; 27 | ssize_t read_size = read(pf[0], &buf, 1); 28 | while(read_size == 1){ 29 | write(1, &buf, 1); 30 | read_size = read(pf[0], &buf, 1); 31 | } 32 | if(read_size == -1){ 33 | err(4,"error while reading in child process"); 34 | } 35 | close(pf[0]); 36 | exit(0); 37 | } 38 | 39 | close(pf[0]); 40 | ssize_t len = (ssize_t)strlen(str); 41 | if(write(pf[1], str, len) != len){ 42 | err(4, "error while writing in parent"); 43 | } 44 | //close(pf[1]); // uncomment here to remove deadlock 45 | wait(NULL); 46 | exit(0); 47 | } 48 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/foo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv){ 7 | if(argc != 2) 8 | err(1, "Invalid number of arguments. Usage: %s ", argv[0]); 9 | 10 | const char *file = argv[1]; 11 | 12 | if(mkfifo("mypipe", 0600) == -1) 13 | err(2, "could not create named pipe"); 14 | 15 | int fdp = open("mypipe", O_WRONLY); 16 | if(fdp == -1) 17 | err(3, "could not open named pipe"); 18 | 19 | if(dup2(fdp, 1) == -1) 20 | err(4, "could not dup2"); 21 | 22 | if(execlp("cat", "cat", file, (char *)NULL) == -1) 23 | err(5, "could not execlp cat"); 24 | } 25 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/fork-loop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | char *indent(int tabs){ 8 | char *indentation=(char *)malloc(tabs+1); 9 | for(int i=0;i0){ 25 | printf("%s%d: parent with PID %d\n", indentation, i, getpid()); 26 | //wait(NULL); // 1 - uncomment to order the tree 27 | free(indentation); 28 | } else if(pid == 0) { 29 | printf("%s%d: child with PID %d\n", indentation, i, getpid()); 30 | free(indentation); 31 | //exit(0); // 2 - uncomment to create a vine 32 | } 33 | } 34 | exit(0); 35 | } 36 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C Processes/Задaча 2.md: -------------------------------------------------------------------------------- 1 | **Зад. 2** Напишете две програми на C (*foo* и *bar*), които си комуникират през наименована тръба.
2 | Програмата *foo* приема параметър – имена файл,
3 | програмата *bar* приема параметър – команда като абсолютен път до изпълним файл.
4 | 5 | *Примерни извиквания и ред на изпълнение (в отделни терминали):* 6 | 7 | *./foo a.txt*
8 | *./bar /usr/bin/sort* 9 |

10 | Програмата *foo* трябва да изпълнява външна команда cat с аргумент името на подадения файл, така че съдържанието му да се прехвърли през 11 | тръбата към параметър програмата *bar*, която от своя страна трябва да изпълни подадената ѝ като аргумент команда без параметри (*/usr/bin/sort* в примера), 12 | която да обработи получените през тръбата данни, четейки от стандартния вход. Еквивалент на горния пример би било следното изпълнение: 13 |

14 | *cat a.txt | /usr/bin/sort* 15 | 16 | *Алтернативен вариант за тестване на програмите foo и bar с един терминал:
* 17 | *./foo a &*
18 | *./bar /usr/bin/sort*

19 | (& ще изпълни програмата в background режим) 20 | 21 | *Решение:*
22 | [foo.c](https://github.com/andy489/Linux_Shell/blob/master/FMI%20Tasks/C%20Processes/foo.c)
23 | [bar.c](https://github.com/andy489/Linux_Shell/blob/master/FMI%20Tasks/C%20Processes/bar.c) 24 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/06. C problems.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/C/06. C problems.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Examples Task 01 Exam 12-07-2020.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/C/Examples Task 01 Exam 12-07-2020.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Makefile: -------------------------------------------------------------------------------- 1 | ifndef CC 2 | CC=gcc 3 | endif 4 | CFLAGS=-std=c99 -Werror -Wall -Wpedantic -Wextra 5 | SRCS=main.c 6 | OBJS=$(subst .c,.o,$(SRCS)) 7 | RM=rm -f 8 | 9 | all: main 10 | 11 | foo: main.o 12 | $(CC) $(CFLAGS) -o main main.c 13 | 14 | clean: 15 | $(RM) $(OBJS) main 16 | 17 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/README.md: -------------------------------------------------------------------------------- 1 | **2 System calls (functions provided by the kernel)
3 Library calls (functions within program libraries)** 2 | 3 | attribute|Shell Scriopts|C 4 | :---|:---:|:---: 5 | abstraction level|high level|low level 6 | man pages|1|2,3| 7 | type system|no|yes (char, uint8_t, struct) 8 | '#' of arguments|$#|argc 9 | arguments|$1, $2|argv[1], argv[2], ... 10 | compiled?|no|yes (make) 11 | memory management|no|pointers 12 | performance|slow|fast 13 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 00 (struct padding).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv){ 15 | printf("argv[0]: %s\n", argv[0]); 16 | if(argc != 2){ 17 | errx(1, "exactly one argument needed"); 18 | } 19 | printf("argv[1]: %s\n", argv[1]); 20 | 21 | struct foo { 22 | uint16_t a; 23 | uint8_t b; 24 | uint16_t c; 25 | uint32_t d; 26 | }A; 27 | 28 | //struct foo A; 29 | 30 | A.a = 3; A.b = 4; A.c = 5; A.d = 0x12345678; 31 | 32 | printf("\nstruct A:\na: %d, b: %d, c: %d, d: %d\n", A.a, A.b, A.c, A.d); 33 | printf("a size: %ld, b size: %ld, c size: %ld, d size: %ld, all size: %ld\n", 34 | sizeof(A.a), sizeof(A.b), sizeof(A.c), sizeof(A.d), sizeof(A)); 35 | printf("1+2=3 byte unnamed padding [2 1 2 4 -> 4(2+1) 4(2) 4(4)]\n"); 36 | 37 | struct bar { 38 | uint16_t a; 39 | uint8_t b; 40 | uint16_t c; 41 | uint32_t d; 42 | }__attribute__((packed))B; 43 | 44 | B.a = 3; B.b = 4; B.c = 5, B.d = 0x12345678; 45 | 46 | printf("\nstruct B:\na: %d, b: %d, c: %d, d: %d\n", B.a, B.b, B.c, B.d); 47 | printf("a size: %ld, b size: %ld, c size: %ld, d size: %ld, all size: %ld\n", 48 | sizeof(B.a), sizeof(B.b), sizeof(B.c), sizeof(B.d), sizeof(B)); 49 | printf("No padding\n\n"); 50 | 51 | int fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 52 | if (fd <=0 ){ 53 | err(2,"error open"); 54 | } 55 | //printf("file descriptor: %d\n", fd); 56 | 57 | int wa = write(fd, &A, sizeof(A)); 58 | if(wa != sizeof(A) ){ 59 | err(3,"err1 write"); 60 | } 61 | 62 | int wb = write(fd, &B, sizeof(B)); 63 | if(wb != sizeof(B) ){ 64 | err(4,"err2 write"); 65 | 66 | } 67 | 68 | close(fd); 69 | exit(0); 70 | } 71 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 01 (append - O_APPEND).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char** argv){ 13 | if(argc != 3) errx(1,"usage: %s file1.txt file2.txt", argv[0]); 14 | 15 | int fd1 = -1, fd2 = -1; 16 | 17 | const char *f1 = argv[1], *f2 = argv[2]; 18 | 19 | if((fd1 = open(f1, O_RDONLY)) == -1){ 20 | err(2,"error while opening %s", f1); 21 | } 22 | 23 | if((fd2 = open(f2, O_APPEND | O_WRONLY | O_EXCL)) == -1){ 24 | int _errno=errno; 25 | close(fd1); 26 | errno=_errno; 27 | err(3,"error while opening %s", f2); 28 | } 29 | 30 | char c[2<<11]; 31 | int read_sz = -1; 32 | 33 | while((read_sz=read(fd1, &c, sizeof(c))) > 0){ 34 | if(read_sz == -1){ 35 | int _errno=errno; 36 | close(fd1); 37 | close(fd2); 38 | errno=_errno; 39 | err(4,"error while reading %s", f1); 40 | } 41 | int wr = write(fd2, &c, read_sz); 42 | if(wr == -1){ 43 | int _errno=errno; 44 | close(fd1); 45 | close(fd2); 46 | errno=_errno; 47 | err(5,"error while writing %s", f2); 48 | } 49 | } 50 | close(fd1); 51 | close(fd2); 52 | exit(0); 53 | } 54 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 01 (append - lseek).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char** argv){ 13 | if(argc != 3) errx(1,"usage: %s file1.txt file2.txt", argv[0]); 14 | 15 | int fd1 = -1, fd2 = -1; 16 | 17 | const char *f1 = argv[1], *f2 = argv[2]; 18 | 19 | if((fd1 = open(f1, O_RDONLY)) == -1){ 20 | err(2,"error while opening %s", f1); 21 | } 22 | 23 | if((fd2 = open(f2, O_WRONLY | O_EXCL)) == -1){ 24 | int _errno=errno; 25 | close(fd1); 26 | errno=_errno; 27 | err(3,"error while opening %s", f2); 28 | } 29 | 30 | lseek(fd2, 0, SEEK_END); 31 | 32 | char c[2<<11]; 33 | int read_sz = -1; 34 | 35 | while((read_sz=read(fd1, &c, sizeof(c))) > 0){ 36 | if(read_sz == -1){ 37 | int _errno=errno; 38 | close(fd1); 39 | close(fd2); 40 | errno=_errno; 41 | err(4,"error while reading %s", f1); 42 | } 43 | int wr = write(fd2, &c, read_sz); 44 | if(wr == -1){ 45 | int _errno=errno; 46 | close(fd1); 47 | close(fd2); 48 | errno=_errno; 49 | err(5,"error while writing %s", f2); 50 | } 51 | } 52 | close(fd1); 53 | close(fd2); 54 | exit(0); 55 | } 56 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 01 Exam 12-07-2020.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/C/Task 01 Exam 12-07-2020.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 02 (swap 2 files - read & write).c: -------------------------------------------------------------------------------- 1 | // Swap contents of two files 2 | // github.com/andy489 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void closeFree(int fd1, int fd2, void* buf){ 14 | if(fd1 != -1) close(fd1); 15 | if(fd2 != -1) close(fd2); 16 | free(buf); 17 | } 18 | 19 | void errorHandler(int code, int errnum, void* buf, int fd1, int fd2){ 20 | closeFree(fd1,fd2,buf); 21 | errno = errnum; 22 | err(code, "error occurred"); 23 | } 24 | 25 | int main(int argc, char* argv[]){ 26 | if (argc != 3) errx(1, "Invalid number of arguments"); 27 | 28 | int fd1 = -1, fd2 = -1; 29 | 30 | fd1 = open(argv[1], O_RDONLY); 31 | if (fd1 == -1) errorHandler(2, errno, NULL, fd1, fd2); 32 | 33 | fd2 = open(argv[2], O_RDONLY); 34 | if (fd2 == -1) errorHandler(3, errno, NULL, fd1, fd2); 35 | 36 | struct stat st; 37 | 38 | if (stat(argv[1], &st) == -1) 39 | errorHandler(4, errno, NULL, fd1, fd2); 40 | 41 | void* buf = malloc(st.st_size); 42 | 43 | if (buf == NULL){ 44 | closeFree(fd1,fd2,buf); 45 | errx(5,"Not enough memory"); 46 | } 47 | 48 | if (read(fd1, buf, st.st_size) != st.st_size){ 49 | closeFree(fd1,fd2,buf); 50 | errx(6,"error"); 51 | } 52 | 53 | fd1 = open(argv[1], O_TRUNC | O_WRONLY); 54 | if (fd1 == -1) errorHandler(7,errno,buf,fd1,fd2); 55 | 56 | char c[4096]; 57 | ssize_t read_size; 58 | 59 | while ((read_size = read(fd2, &c, sizeof(c))) > 0){ 60 | if (write(fd1, &c, read_size) != read_size){ 61 | closeFree(fd1,fd2,buf); 62 | errx(8,"error while writing"); 63 | } 64 | } 65 | 66 | fd2 = open(argv[2], O_TRUNC | O_WRONLY); 67 | if (fd2 == -1) errorHandler(9, errno, buf, fd1, fd2); 68 | 69 | if (write(fd2, buf, st.st_size) != st.st_size){ 70 | closeFree(fd1,fd2,buf); 71 | errx(10,"error while writing"); 72 | } 73 | closeFree(fd1,fd2,buf); 74 | exit(0); 75 | } 76 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 02 (swap 2 files - renameat2).c: -------------------------------------------------------------------------------- 1 | // Swap contents of two files 2 | // github.com/andy489 3 | 4 | #define _GNU_SOURCE 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char *argv[]){ 12 | if(argc != 3) { 13 | errx(1,"Wrong number of arguments"); 14 | } 15 | int ex; 16 | if((ex = renameat2(AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_EXCHANGE)) == -1) { 17 | err(2,"Fail"); 18 | } 19 | exit(0); 20 | } 21 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 02 Exam 12.07.2020.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/C/Task 02 Exam 12.07.2020.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 03 (head without options).c: -------------------------------------------------------------------------------- 1 | // Implement a head function withoud options 2 | // github.com/andy489 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char* argv[]){ 11 | int fd, lines = 0; 12 | char c; 13 | 14 | if (argc != 2) { 15 | errx(1, "Invalid number of arguments"); 16 | } 17 | 18 | const char *file = argv[1]; 19 | 20 | if ((fd = open(file, O_RDONLY)) == -1) { 21 | err(2, "failed to open %s", file); 22 | } 23 | 24 | int rd; 25 | while ((rd = read(fd, &c, 1)) > 0) { 26 | if(rd == -1){ 27 | int _errno=errno; 28 | close(fd); 29 | errno=_errno; 30 | err(3, "failed to read %s", file); 31 | } 32 | if (c == '\n') ++lines; 33 | write(1, &c, 1); 34 | if (lines == 10) break; 35 | } 36 | close(fd); 37 | exit(0); 38 | } 39 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 04 (wc).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main (int argc, char* argv[]){ 11 | 12 | if (argc != 2) { 13 | errx(1, "Invalid number of arguments"); 14 | } 15 | 16 | const char * file = argv[1]; 17 | 18 | int fd; 19 | if ( (fd = open(file, O_RDONLY)) == -1 ) { 20 | err(2, "error opening file %s", file); 21 | } 22 | 23 | int lines = 0, words = 0, chars = 0; 24 | char c[2<<10]; 25 | 26 | int inWord = 0, rd = -1; 27 | 28 | while((rd = read(fd, &c, sizeof(c))) > 0) { 29 | for(int i=0; i 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int cmp(const void* a, const void* b){ 12 | return *((unsigned char*)a) - *((unsigned char*)b); 13 | } 14 | 15 | int main(int argc, char** argv){ 16 | if(argc != 3){ 17 | errx(1,"expect two argument"); 18 | } 19 | 20 | int fd = open(argv[1], O_RDONLY); 21 | 22 | if(fd < 0){ 23 | err(2, "error opening file %s", argv[1]); 24 | } 25 | 26 | struct stat st; 27 | 28 | if(stat(argv[1], &st) == -1){ 29 | err(3,"error stat file %s", argv[1]); 30 | } 31 | 32 | int fd_res = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 33 | 34 | if(fd_res < 0){ 35 | err(4, "error opening file %s", argv[2]); 36 | } 37 | 38 | if(!st.st_size){ 39 | close(fd); 40 | close(fd_res); 41 | exit(0); 42 | } 43 | 44 | void *buf = malloc(st.st_size); 45 | 46 | if(!buf){ 47 | int olderrno = errno; 48 | close(fd); 49 | close(fd_res); 50 | errno = olderrno; 51 | err(5, "no memory"); 52 | } 53 | 54 | if(read(fd, buf, st.st_size) != st.st_size){ 55 | int olderrno = errno; 56 | free(buf); 57 | close(fd); 58 | close(fd_res); 59 | errno = olderrno; 60 | err(6, "error while reading file %s", argv[1]); 61 | } 62 | 63 | qsort(buf, st.st_size, 1, cmp); 64 | 65 | if(write(fd_res, buf, st.st_size) != st.st_size){ 66 | int olderrno = errno; 67 | free(buf); 68 | close(fd); 69 | close(fd_res); 70 | errno = olderrno; 71 | err(7, "error while writing file %s", argv[2]); 72 | } 73 | 74 | free(buf); 75 | close(fd); 76 | close(fd_res); 77 | exit(0); 78 | } 79 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 06 (cp with 2 args).c: -------------------------------------------------------------------------------- 1 | //github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char** argv){ 12 | 13 | if(argc !=3 ){ 14 | errx(1,"Invalid number of arguments"); 15 | } 16 | 17 | int fd1 = -1, fd2 = -1; 18 | 19 | fd1 = open(argv[1], O_RDONLY); 20 | 21 | if(fd1 == -1){ 22 | err(2,"error while opening %s", argv[1]); 23 | } 24 | 25 | fd2 = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); 26 | 27 | if(fd2 == -1){ 28 | int oldErrno = errno; 29 | close(fd1); 30 | errno = oldErrno; 31 | err(3,"error while opening %s", argv[2]); 32 | } 33 | 34 | char c[4096]; 35 | ssize_t read_size; 36 | 37 | while((read_size=read(fd1, &c, sizeof(c))) > 0){ 38 | if(write(fd2, &c, read_size) != read_size){ 39 | close(fd1); 40 | close(fd2); 41 | errx(4,"error while writing"); 42 | } 43 | } 44 | 45 | close(fd1); 46 | close(fd2); 47 | 48 | exit(0); 49 | } 50 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 07 (cat with multiple args).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char** argv){ 12 | if(argc == 1) errx(1, "expect arguments"); 13 | 14 | int i; 15 | for(i = 1; i < argc; ++i){ 16 | int fd = open(argv[i], O_RDONLY); 17 | if(fd == -1){ 18 | printf("permissions denied: %s\n", argv[i]); 19 | continue; 20 | } 21 | 22 | char c[4096]; 23 | ssize_t read_size; 24 | 25 | while((read_size = read(fd, &c, sizeof(c))) > 0) 26 | write(1, &c, read_size); 27 | 28 | close(fd); 29 | } 30 | exit(0); 31 | } 32 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 08 1st sol (cp with multiple args).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char** argv){ 14 | 15 | if(argc < 3){ 16 | errx(1,"invalid number of args"); 17 | } 18 | 19 | char *dirpath = argv[argc-1]; 20 | 21 | int fd_dir = open(dirpath, O_DIRECTORY); 22 | if(fd_dir == -1){ 23 | err(2,"error %s", dirpath); 24 | } 25 | 26 | int wr = access(dirpath, W_OK); 27 | if(wr == -1){ 28 | err(3,"dir %s - not writable", dirpath); 29 | } 30 | 31 | int s1 = (int)strlen(dirpath); 32 | if(dirpath[s1-1] != '/'){ 33 | strcat(dirpath,"/"); 34 | s1+=1; 35 | } 36 | //printf("name: %s, len: %lu\n",dirpath, strlen(dirpath)); 37 | 38 | int i=1; 39 | for(; i < argc - 1; ++i){ 40 | int fd = open(argv[i], O_RDONLY); 41 | if(fd == -1){ 42 | printf("error. file %s not readable\n", argv[i]); 43 | continue; 44 | } 45 | 46 | int s2 = (int)strlen(argv[i]); 47 | char *target = malloc(s1+s2+1); 48 | if(target == NULL){ 49 | int _errno=errno; 50 | close(fd); 51 | errno=_errno; 52 | err(4,"not enough memory"); 53 | } 54 | int j=0; 55 | for(; j < s1; ++j){ 56 | target[j] = argv[argc-1][j]; 57 | } 58 | for(;j < s1 + s2; ++j){ 59 | target[j] = argv[i][j-s1]; 60 | } 61 | target[j] = '\0'; 62 | 63 | //printf("target: %s\n", target); 64 | 65 | int towr = open(target, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 66 | if(towr == -1){ 67 | close(fd); 68 | free(target); 69 | printf("error file %s \n", target); 70 | } 71 | 72 | char c[4096]; 73 | ssize_t read_size; 74 | 75 | while((read_size = read(fd, &c, sizeof(c))) > 0){ 76 | if(write(towr, &c, read_size) != read_size){ 77 | printf("error while writing to file: %s\n", target); 78 | } 79 | } 80 | free(target); 81 | close(fd); 82 | close(towr); 83 | } 84 | exit(0); 85 | } 86 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 09 (passwd with '?' separator).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(){ 12 | char* etc = "/etc/passwd"; 13 | char* new = "./passwd.txt"; 14 | 15 | int fd1 = open(etc, O_RDONLY); 16 | if(fd1 == -1){ 17 | err(1,"error while opening %s", etc); 18 | } 19 | 20 | int fd2 = open(new, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 21 | if(fd2 == -1){ 22 | int _errno=errno; 23 | close(fd1); 24 | errno=_errno; 25 | err(2,"error while opening %s", new); 26 | } 27 | 28 | char c; 29 | 30 | while(read(fd1, &c, 1)){ 31 | if(c == ':'){ 32 | c = '?'; 33 | } 34 | if(write(fd2, &c, 1) != 1){ 35 | int _errno=errno; 36 | close(fd1); 37 | close(fd2); 38 | errno=_errno; 39 | err(3,"error while writing %s", new); 40 | } 41 | } 42 | close(fd1); 43 | close(fd2); 44 | exit(0); 45 | } 46 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 09.md: -------------------------------------------------------------------------------- 1 | **Задача 09.** Koпирайте файл */etc/passwd* в текущата ви работна директория и променете разделителят на копирания файл от ":", на "?". 2 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 10.md: -------------------------------------------------------------------------------- 1 | **Задача 10.** Напишете програма, която приема точно 2 аргумента. Първият може да бъде само *--min*, *--max* или *--print* (вижте man 3 strcmp). 2 | Вторият аргумент е двоичен файл, в който има записани цели неотрицателни двубайтови числа. Ако първият аргумент е: 3 | 4 | *--min* - програмата отпечатва кое е най-малкото число в двоичния файл.
5 | *--max* - програмата отпечатва кое е най-голямото число в двоичния файл.
6 | *--print* - програмата отпечатва на нов ред всяко число.
7 | 8 | Използвайте двоичния файл binary/dump или генерирайте сами такъв (правилно подравнен). 9 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 11 (counting sort inplace).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | // counting sort binary file - inplace 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char **argv){ 14 | if (argc != 2) 15 | errx(1, "Usage: %s ", argv[0]); 16 | 17 | char * bin = argv[1]; 18 | 19 | if (access(bin, F_OK) == -1) 20 | err(2, "file %s doesnot exist", bin); 21 | 22 | if (access(bin, R_OK | W_OK) == -1) 23 | err(3, "file %s does not have the needed permissions for inplace sorting", bin); 24 | 25 | ssize_t fd = open(bin, O_RDWR); 26 | if (fd == -1) 27 | err(4, "error while opening file %s", bin); 28 | 29 | uint32_t counting[256] = { 0 }; 30 | 31 | uint8_t b; 32 | ssize_t read_sz; 33 | 34 | while ((read_sz = read(fd, &b, sizeof(b))) == sizeof(b)) 35 | ++counting[b]; 36 | if (read_sz == -1){ 37 | int _errno = errno; 38 | close(fd); 39 | errno = _errno; 40 | err(5, "error while reading file %s", bin); 41 | } 42 | 43 | ssize_t ls = lseek(fd, 0, SEEK_SET); 44 | if(ls == -1){ 45 | int _errno = errno; 46 | close(fd); 47 | errno = _errno; 48 | err(6,"error while lseek file %s", bin); 49 | } 50 | 51 | uint16_t i; 52 | for (i = 0; i < 256; ++i){ 53 | b = i; 54 | while (counting[i]){ 55 | if( write(fd, &b, sizeof(b)) != sizeof(b) ){ 56 | int _errno = errno; 57 | close(fd); 58 | errno = _errno; 59 | err(7, "error while writing to file %s", bin); 60 | } 61 | --counting[i]; 62 | } 63 | } 64 | close(fd); 65 | exit(0); 66 | } 67 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 11 (counting sort).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SIZE 256 14 | 15 | int main(int argc, char** argv){ 16 | if(argc != 3){ 17 | errx(1,"Usage: %s ", argv[0]); 18 | } 19 | char * file = argv[1], * sorted = argv[2]; 20 | 21 | int fd1, fd2; 22 | fd1 = open(file, O_RDWR); 23 | if(fd1 == -1){ 24 | err(2, "error while opening file %s", file); 25 | } 26 | 27 | fd2 = open(sorted, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 28 | if(fd2 == -1){ 29 | int _errno=errno; 30 | close(fd1); 31 | errno=_errno; 32 | err(3, "error while opening file %s", sorted); 33 | } 34 | 35 | const uint32_t BUF_SIZE = 2<<10; 36 | uint8_t histo[SIZE] = { 0 }; 37 | uint8_t buf[BUF_SIZE]; 38 | ssize_t read_sz; 39 | uint32_t total_sz = 0; 40 | 41 | while((read_sz = read(fd1, &buf, sizeof(buf))) > 0){ 42 | for(int i = 0; i< read_sz; ++i){ 43 | ++histo[buf[i]]; 44 | ++total_sz; 45 | } 46 | } 47 | 48 | if(read_sz == -1){ 49 | int _errno=errno; 50 | close(fd1); close(fd2); 51 | errno=_errno; 52 | err(3, "error while reading from file %s", file); 53 | } 54 | // reset marker to the beginning of the file for inplace sorting 55 | // lseek(fd1, 0, SEEK_SET); 56 | uint16_t byte = 0; 57 | // while the counts are not fully traversed 58 | while (byte < SIZE){ 59 | // fill the buffer for writing 60 | size_t pos = 0; 61 | while(pos < BUF_SIZE && byte < SIZE){ 62 | if(histo[byte] == 0){ 63 | ++byte; // move to next byte 64 | } 65 | else { 66 | buf[pos] = byte; // write the byte inside the buffer 67 | --histo[byte]; // decrement counter for this byte 68 | ++pos; // move one step forward in the buffer 69 | } 70 | } 71 | ssize_t write_sz = pos; 72 | if(write(fd2, buf, write_sz) != write_sz){ // for inplace sorting write to fd1 73 | int _errno=errno; 74 | close(fd1); close(fd2); 75 | errno=_errno; 76 | err(4, "error while writing to file %s", sorted); 77 | } 78 | } 79 | close(fd1); close(fd2); 80 | exit(0); 81 | } 82 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 31 (sort file.bin inplace).c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char **argv){ 11 | if(argc != 2){ 12 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 13 | } 14 | 15 | char *file = argv[1]; 16 | 17 | struct stat st; 18 | 19 | if(stat(file, &st) == -1){ 20 | err(2, "could not stat file %s", file); 21 | } 22 | 23 | if(!(st.st_mode & S_IRUSR) || !(st.st_mode & S_IWUSR)){ 24 | errx(3, "file %s not readable or not writable", file); 25 | } 26 | 27 | /* 28 | if(st.st_size > UINT64_MAX){ 29 | warnx("small chance of overfloating"); 30 | } 31 | */ 32 | 33 | uint64_t counting[256] = { 0 }; 34 | uint16_t level[256]; 35 | for (uint16_t j = 0; j< 256; ++j){ 36 | level[j] = 1; 37 | } 38 | 39 | ssize_t fd = open(file, O_RDWR); 40 | if(fd == -1){ 41 | err(4, "error while opening file %s", file); 42 | } 43 | 44 | ssize_t read_sz; 45 | uint8_t b; 46 | 47 | while((read_sz = read(fd, &b, sizeof(b))) == sizeof(b)){ 48 | ++counting[b]; 49 | if(counting[b] == UINT64_MAX){ 50 | counting[b] = 0; 51 | ++level[b]; 52 | } 53 | } 54 | if(read_sz == -1){ 55 | const int olderrno = errno; 56 | close(fd); 57 | errno = olderrno; 58 | err(5, "error while reading file %s", file); 59 | } 60 | 61 | if(lseek(fd, 0, SEEK_SET) == -1){ 62 | const int olderrno = errno; 63 | close(fd); 64 | errno = olderrno; 65 | err(6, "error while lseek file %s", file); 66 | } 67 | 68 | uint16_t i = 0; 69 | 70 | for(; i < 256; ++i){ 71 | while(level[i]--){ 72 | b = i; 73 | while(counting[i]--){ 74 | if(write(fd, &b, sizeof(b)) != sizeof(b)){ 75 | const int olderrno = errno; 76 | close(fd); 77 | errno = olderrno; 78 | err(7, "error while writing into file %s", file); 79 | } 80 | } 81 | counting[i] = UINT64_MAX; 82 | } 83 | } 84 | 85 | close(fd); 86 | exit(0); 87 | } 88 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 36 (more precise).c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void READ(int fd, const char *from, uint8_t numerate, uint16_t *cnt){ 12 | char c; 13 | ssize_t read_sz; 14 | 15 | int newline = 1; 16 | 17 | while((read_sz = read(fd, &c, 1)) == 1){ 18 | if(numerate){ 19 | if(newline){ 20 | setbuf(stdout, NULL); 21 | fprintf(stdout, "%d ", *cnt); 22 | write(1, &c, 1); 23 | newline = 0; 24 | ++(*cnt); 25 | } else write(1, &c, 1); 26 | if(c == '\n') newline = 1; 27 | } else write (1,&c, 1); 28 | } 29 | if(read_sz == -1){ 30 | const int olderrno = errno; 31 | close(fd); 32 | errno = olderrno; 33 | err(99, "error while reding from %s", from); 34 | } 35 | } 36 | 37 | int main(int argc, char **argv){ 38 | uint16_t i = 1, cnt = 1; 39 | uint8_t numerate = 0; 40 | 41 | if(argc == 1){ 42 | READ(0, "STDIN", numerate, &cnt); 43 | exit(0); 44 | } else if (argc == 2 && strcmp(argv[1], "-n") == 0){ 45 | numerate = 1; 46 | READ(0, "STDIN", numerate, &cnt); 47 | exit(0); 48 | } 49 | 50 | if(strcmp(argv[i], "-n") == 0){ 51 | numerate = 1; 52 | ++i; 53 | } 54 | 55 | for(; i< argc; ++i){ 56 | if(strcmp("-", argv[i]) == 0){ 57 | READ(0, "STDIN", numerate, &cnt); 58 | continue; 59 | } 60 | 61 | const char *filepath = argv[i]; 62 | 63 | struct stat st; 64 | if(stat(filepath, &st) == -1) 65 | err(1, "could not stat file %s", filepath); 66 | 67 | if(!(st.st_mode & S_IRUSR)){ 68 | warnx("file %s is not readable", filepath); 69 | continue; 70 | } 71 | 72 | ssize_t fd = open(filepath, O_RDONLY); 73 | if(fd == -1) 74 | err(3, "failed to open file %s", filepath); 75 | 76 | READ(fd, filepath, numerate, &cnt); 77 | } 78 | exit(0); 79 | } 80 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 36.c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int numerate = 0; 15 | int cnt = 1; 16 | 17 | void READ(int fd, const char * from){ 18 | char c; 19 | ssize_t read_sz; 20 | 21 | int newline = 1; 22 | 23 | while((read_sz = read(fd, &c, 1)) > 0){ 24 | if(numerate) { 25 | if(newline) { 26 | setbuf(stdout, NULL); 27 | fprintf(stdout, "%02d ", cnt); 28 | write(1, &c, sizeof(c)); 29 | ++cnt; 30 | newline = 0; 31 | } 32 | else { 33 | write(1, &c, sizeof(c)); 34 | } 35 | if(c == '\n') newline = 1; 36 | } 37 | else write(1, &c, 1); 38 | } 39 | if(read_sz == -1){ 40 | int _errno=errno; 41 | close(fd); 42 | errno=_errno; 43 | err(4,"error while reading %s", from); 44 | } 45 | 46 | /* 47 | read ----> write 48 | 1) 49 | printf(cnt) 50 | setbuf(3) 51 | write(c) 52 | 53 | 2) 54 | char foo[10]; 55 | snprintf(foo... 56 | write(FD, foo, n) 57 | */ 58 | } 59 | 60 | int main(int argc, char ** argv){ 61 | if(argc == 1){ 62 | READ(0, "STDIN"); 63 | exit(0); 64 | } 65 | 66 | int i = 1; 67 | 68 | if(strcmp(argv[i],"-n") == 0){ 69 | numerate = 1; 70 | ++i; 71 | } 72 | 73 | for(;i < argc; ++i){ 74 | if(strcmp("-", argv[i]) == 0){ 75 | READ(0, "STDIN"); 76 | continue; 77 | } 78 | const char * filepath = argv[i]; 79 | 80 | struct stat st; 81 | if(stat(filepath, &st) == -1){ 82 | err(1, "error while stat %s", filepath); 83 | } 84 | 85 | if(!S_ISREG(st.st_mode)){ 86 | errx(2, "%s is nor regular file", filepath); 87 | } 88 | 89 | int fd = open(filepath, O_RDONLY); 90 | if(fd == -1){ 91 | err(3,"error opening %s", filepath); 92 | } 93 | // exist, regular, readable 94 | READ(fd, "filepath"); 95 | } 96 | exit(0); 97 | } 98 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 38 (strchr, strrchr).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main(int argc, char **argv){ 15 | if(argc != 3) 16 | errx(1, "Invalid number of arguments. Usage: %s [OPTION] SET1 [SET2]", argv[0]); 17 | 18 | int d, s; 19 | const char *set1 = NULL, *set2 = NULL; 20 | 21 | d = (strcmp(argv[1],"-d") == 0)? 1:0; 22 | s = (strcmp(argv[1],"-s") == 0)? 1:0; 23 | 24 | if (!d && !s){ 25 | set1 = argv[1]; 26 | set2 = argv[2]; 27 | } else set1 = argv[2]; 28 | 29 | ssize_t rd = -1; 30 | char c; 31 | 32 | if(d){ 33 | while( (rd = read(0, &c, 1)) == 1){ 34 | if(strchr(set1, c) != NULL) continue; 35 | printf("%c", c); 36 | } 37 | if(rd == -1) err(2,"error while reading from STDIN"); 38 | } 39 | else if(s){ 40 | char prev = '\0'; 41 | uint8_t first = 1; 42 | while( (rd = read(0, &c, 1)) == 1){ 43 | if(c != prev) first = 1; 44 | if(strchr(set1, c)){ 45 | if(!first) continue; 46 | printf("%c", c); 47 | first = 0; 48 | } 49 | else 50 | printf("%c", c); 51 | prev = c; 52 | } 53 | if(rd == -1) err(3, "error while reading from STDIN"); 54 | } 55 | else{ 56 | if(strlen(set1) != strlen(set2)) 57 | errx(4,"sizes of sets are not consistent"); 58 | 59 | while( (rd = read(0, &c, 1)) == 1){ 60 | char *at = strrchr(set1, c); 61 | if(at) 62 | printf("%c", set2[(int)(at-set1)]); 63 | else 64 | printf("%c", c); 65 | } 66 | if(rd == -1) err(5, "error while reading from STDIN"); 67 | } 68 | exit(0); 69 | } 70 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 40.c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void usage(const char *executable){ 12 | errx(1, "Usage: %s [-c n | -c n-m | -d t -f n | -d t -f n-m]", executable); 13 | } 14 | 15 | bool isdig(const char c){ 16 | if(c>='0' && c<='9') 17 | return true; 18 | return false; 19 | } 20 | 21 | ssize_t parse_digit(char symbol){ 22 | if(!isdig(symbol)) 23 | usage("this executable"); 24 | return symbol - '0'; 25 | } 26 | 27 | ssize_t parse_number(char **str){ 28 | ssize_t n = 0; 29 | for(; isdig((*str)[0]); ++(*str)) 30 | n = n * 10 + parse_digit((*str)[0]); 31 | return n; 32 | } 33 | 34 | void parse_range(char *arg, ssize_t *from, ssize_t *to){ 35 | // arg is either 'n' or 'n-m' 36 | if(!isdig(arg[0]) && arg[0] != '-') 37 | usage("this executable"); 38 | 39 | *from = parse_number(&arg); 40 | if(arg[0] == '\0') 41 | *to = *from; 42 | else if(arg[0] == '-'){ 43 | ++arg; 44 | if(arg[0] == '\0') 45 | *to = 1<<15; 46 | else 47 | *to = parse_number(&arg); 48 | 49 | if(arg[0] != '\0') 50 | usage("this executable"); 51 | } else 52 | usage("this executable"); 53 | } 54 | 55 | void cut(ssize_t start, ssize_t end, bool use_delim, char delim){ 56 | char ch; 57 | ssize_t cnt = 0, read_sz; 58 | 59 | while((read_sz = read(0, &ch, sizeof(ch))) == 1){ 60 | if((!use_delim) || (ch == delim) || (cnt == 0)) 61 | ++cnt; 62 | if(ch == '\n'){ 63 | write(1, "\n", 1); 64 | cnt = 0; 65 | } else if(cnt >= start && cnt <= end) 66 | if(!((cnt == start) && (ch == delim) && use_delim)) 67 | write(1, &ch, 1); 68 | } 69 | if(read_sz == -1) 70 | err(2, "could not read from stdin"); 71 | } 72 | 73 | int main(int argc, char **argv){ 74 | ssize_t start = -1, end = -1; 75 | char delim = '\0'; 76 | if((argc == 3) && (strcmp(argv[1], "-c") == 0)){ 77 | parse_range(argv[2], &start, &end); 78 | cut(start, end, false, delim); 79 | } else if((argc == 5) && (strcmp(argv[1], "-d") == 0)){ 80 | parse_range(argv[4], &start, &end); 81 | delim = argv[2][0]; 82 | cut(start, end, true, delim); 83 | } else 84 | usage(argv[0]); 85 | exit(0); 86 | } 87 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/Task 41 (uint16_t heapsort).c: -------------------------------------------------------------------------------- 1 | // github.com/andy489 2 | 3 | /* 4 | PROBLEM: 5 | 65535 * sizeof(uint16_t) = 65535 * 2 = 131070 bytes (MAX) 6 | 256 KB = 256 * 1024 = 262144 bytes RAM 7 | 8 | NO DRAMA, we can do it with only 1 qsort, heapsort or with counting sort. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int cmp(const void *a, const void *b){ 20 | if(*((uint16_t*)a) > *((uint16_t*)b)) 21 | return 1; 22 | else if(*((uint16_t*)a) < *((uint16_t*)b)) 23 | return -1; 24 | return 0; 25 | } 26 | 27 | int main(int argc, char **argv){ 28 | if(argc != 3) 29 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 30 | 31 | char *input = argv[1], *output = argv[2]; 32 | 33 | struct stat st; 34 | 35 | if(stat(input, &st) == -1) 36 | err(2, "could not stat file %s", input); 37 | 38 | if(st.st_size % sizeof(uint16_t) != 0) 39 | errx(3, "file %s is corrupted", input); 40 | 41 | if(!(st.st_mode & S_IRUSR)) 42 | errx(4, "file %s is not readable", input); 43 | 44 | ssize_t fd_i = open(input, O_RDONLY); 45 | if(fd_i == -1) 46 | err(5, "could not open file %s", input); 47 | 48 | uint8_t buf[(1<<16) * sizeof(uint16_t)]; 49 | ssize_t read_sz = read(fd_i, &buf, sizeof(buf)); 50 | if(read_sz == -1){ 51 | const int olderrno = errno; 52 | close(fd_i); 53 | errno = olderrno; 54 | err(6, "could not read from file %s into buffer", input); 55 | } 56 | 57 | if(heapsort(buf, read_sz/sizeof(uint16_t), sizeof(uint16_t), cmp) == -1){ 58 | const int olderrno = errno; 59 | close(fd_i); 60 | errno = olderrno; 61 | err(8, "could not heapsort uint16_t elements in buffer"); 62 | } 63 | 64 | ssize_t fd_o = open(output, O_CREAT | O_TRUNC | O_RDWR, 0644); 65 | if(fd_o == -1){ 66 | const int olderrno = errno; 67 | close(fd_i); 68 | errno = olderrno; 69 | err(9, "could not open file %s", output); 70 | } 71 | 72 | if(write(fd_o, &buf, read_sz) != read_sz){ 73 | const int olderrno = errno; 74 | close(fd_i); 75 | close(fd_o); 76 | errno = olderrno; 77 | err(10, "could not write to file %s", output); 78 | } 79 | 80 | close(fd_i); 81 | close(fd_o); 82 | exit(0); 83 | } 84 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/overflow testing with counting sort.c: -------------------------------------------------------------------------------- 1 | // Sample use: cat /dev/urandom | head -68899 > file.bin 2 | // ./main file.bin 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main(int argc, char **argv){ 15 | if(argc != 2) 16 | errx(1, "Invalid number of arguments. Usage: %s ", argv[0]); 17 | 18 | char *file = argv[1]; 19 | 20 | struct stat st; 21 | 22 | if(stat(file, &st) == -1) 23 | err(2, "could not stat file %s", file); 24 | 25 | if(!(st.st_mode & S_IRUSR) || !(st.st_mode & S_IWUSR)) 26 | errx(3, "file %s not readable or not writable", file); 27 | 28 | uint16_t counting[256] = { 0 }; // uint32_t for less overflows 29 | int16_t level[256] = { 0 }; 30 | 31 | ssize_t fd = open(file, O_RDWR); 32 | if(fd == -1) 33 | err(4, "error while opening file %s", file); 34 | 35 | ssize_t read_sz; 36 | uint8_t b; 37 | 38 | while((read_sz = read(fd, &b, sizeof(b))) == sizeof(b)){ 39 | ++counting[b]; 40 | if(counting[b] == UINT16_MAX){ 41 | counting[b] = 0; 42 | ++level[b]; 43 | } 44 | } 45 | if(read_sz == -1){ 46 | const int olderrno = errno; 47 | close(fd); 48 | errno = olderrno; 49 | err(5, "error while reading file %s", file); 50 | } 51 | 52 | if(lseek(fd, 0, SEEK_SET) == -1){ 53 | const int olderrno = errno; 54 | close(fd); 55 | errno = olderrno; 56 | err(6, "error while lseek file %s", file); 57 | } 58 | 59 | uint16_t i = 0; 60 | 61 | uint32_t overflows = 0; 62 | for (int j = 0; j< 256; ++j) 63 | overflows+=level[j]; 64 | 65 | for(; i < 256; ++i){ 66 | while(level[i] >= 0){ 67 | --level[i]; 68 | b = i; 69 | while(counting[i]--){ 70 | if(write(fd, &b, sizeof(b)) != sizeof(b)){ 71 | const int olderrno = errno; 72 | close(fd); 73 | errno = olderrno; 74 | err(7, "error while writing into file %s", file); 75 | } 76 | } 77 | counting[i] = UINT16_MAX; // UINT32_MAX 78 | } 79 | } 80 | printf("File %s is sorted inplace.\nTotal overflows: %u\n", file, overflows); 81 | close(fd); 82 | exit(0); 83 | } 84 | -------------------------------------------------------------------------------- /1 – FMI Tasks/C/paste with 2 files.md: -------------------------------------------------------------------------------- 1 | **Задача.** Реализирайте командата *paste* със следната функционалност: 2 | 3 | * програмата може да приема като аргументи точно 2 файла 4 | * ако не е подаден аргумент *-d* на командата, то по подразбиране разделителя се приема за табулация 5 | * ако е подаден аргумент *-d* на командата, следващия аргумент да е разделителя и след това двата файла (виж *man paste*) 6 | 7 | 8 | cat a.txt
9 | a1 a2 a3
10 | 11 | cat b.txt
12 | b1
13 | b2
14 | 15 | Примерени извиквания и резултатите от тях:
16 | *./main a.txt b.txt*
17 | a1 a2 a3 b1
18 |    b2
19 | 20 | *./main -d : a.txt b.txt*
21 | a1 a2 a3:b1
22 | :b2 23 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Cheat sheets/Bash Redirections Cheat Sheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/Cheat sheets/Bash Redirections Cheat Sheet.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/Cheat sheets/Vi Reference Card.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/Cheat sheets/Vi Reference Card.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/File Processing/E 01 Task 05.md: -------------------------------------------------------------------------------- 1 | **Задача 5.** Напишете серия от команди, извеждащи на екрана само броя на свички обекти във файловата система, чиито собственик е текущия потребител. 2 | 3 | *Забележка: Във файловата система със сигурност съществуват директории, до които нямате достъп.* 4 | 5 | **Решение:** 6 | 7 | ```sh 8 | find / -user "$(whoami)" 2>/dev/null | wc -l 9 | ``` 10 | -------------------------------------------------------------------------------- /1 – FMI Tasks/File Processing/E 01 Task 06.md: -------------------------------------------------------------------------------- 1 | **Задача 6.** Напишете серия от команди, които изтриват:
2 | а) всички файлове в текущата директория и нейните поддиректории, които са с нулева дължина;
3 | б) 5-те най-големи файла в home директорията на текущия потребител и нейните поддиректории. 4 | 5 | **Решение:** 6 | 7 | a) 8 | 9 | Първи начин: 10 | 11 | ```sh 12 | find . -maxdepth 2 2>/dev/null | xargs -I {} stat -l {} |\ 13 | awk '$5==0 {for i=10;i/dev/null -printf"%s %p\n" |\ 21 | awk '$1==0{for(i=2;i/dev/null -size 0 -exec rm -i {}\; 29 | ``` 30 | 31 | б) 32 | 33 | ```sh 34 | gfind ~ -maxdepth 2 2>/dev/null -printf"%s %p\n" |\ 35 | sort -rn -t' ' k1 | head -5 | cut -d' ' -f2- | xargs -I {} rm -i {} 36 | ``` 37 | -------------------------------------------------------------------------------- /1 – FMI Tasks/File Processing/E 01 Task 08.md: -------------------------------------------------------------------------------- 1 | **Задача 8.** Намерете имената на топ 5 файловете в текущата директория с най-много hardlinks. 2 | 3 | *Решение:* 4 | 5 | Първи начин: 6 | 7 | ```sh 8 | stat -f "%l %N" * | sort -rn -t' ' -k1 | head -5 | cut -d' ' -f2- 9 | ``` 10 | 11 | Втори начин: 12 | 13 | ```sh 14 | gstat -c "%h %N" * | sort -rn -t' ' -k1 | head -5 | cut -d' ' -f2- 15 | ``` 16 | -------------------------------------------------------------------------------- /1 – FMI Tasks/File Processing/E 01 Task 09.md: -------------------------------------------------------------------------------- 1 | **Задача 9.** Напишете серия от команди, извеждащи на екрана само inode-a на най-скоро променения (по съдържание) файл, намиращ се в home директорията на потребител pesho (или нейните поддиректории), който има повече от едно име. 2 | 3 | **Решение:** 4 | 5 | ```sh 6 | find ~pesho -type f 2>/dev/null -printf "%i %T@ %n\n" |\ 7 | awk '$3>1 {print$2,$3}' |\ 8 | sort -rn -t' ' -k2 | head -1 | awk '{print $1}' 9 | ``` 10 | -------------------------------------------------------------------------------- /1 – FMI Tasks/File Processing/E 01 Task 12.md: -------------------------------------------------------------------------------- 1 | **Задача 12.** От всичкии файлове в home директорията на потребителя velin, извадете дълбочината на файл, който: 2 | - има същия inode като този на най-скоро променения файл сред тях 3 | - има минимална дълбочина 4 | 5 | *Пояснение:* Под "дълбочина" да се разбира дълбочина в дървото на файловата система: например файлът /foo/bar/baz има дълбочина 3. 6 | 7 | **Решение:** 8 | 9 | ```sh 10 | gfind . -inum (gfind ~velin -type f 2 > /dev/null -printf "%T@ %i %p\n" |\ 11 | sort -n | tail -1 | awk '{print $2}') | egrep -o '.' | fgrep '/' | wc -l 12 | ``` 13 | -------------------------------------------------------------------------------- /1 – FMI Tasks/File Processing/Task 04.md: -------------------------------------------------------------------------------- 1 | **Задача 4.** Да се намери обикновения файл в текущата директория (рекурсивно), който се е модифицирал най-отдавна без да се използват сортировки (sort). 2 | 3 | 4 | **Решение:** 5 | 6 | ```sh 7 | gfind . -type f 2>/dev/null -printf "%T@ %p\n" |\ 8 | awk 'BEGIN{t=99999999999} $1/dev/null -printf "%s %f\n" | awk '$2 ~ "^[^.]" {c+=1;s+=$1}END{print s/c}' 7 | ``` 8 | -------------------------------------------------------------------------------- /1 – FMI Tasks/File Processing/Task 06.md: -------------------------------------------------------------------------------- 1 | **Задача 6.** Да се изведат всички редове, които съдържат цифров палиндром с дължина 4 или 5 от шелскрипта с най-много редове, намиращ се в текущата директория. 2 | 3 | **Решение:** 4 | 5 | ```sh 6 | file ./* | awk -F':' '$2~/shell script/ {print $0}' | cut -d':' -f1 | xargs -I {} wc -l {} |\ 7 | awk '{$1=$1}1' | sort -n -t' ' -k1 | tail -1 | cut -d' ' -f2- |\ 8 | xargs -I {} cat {} | grep -E --color '(\d)(\d).?\2\1' 9 | ``` 10 | -------------------------------------------------------------------------------- /1 – FMI Tasks/K1_2017_SI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/K1_2017_SI.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/K1_2018_SI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/K1_2018_SI.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/K1_A_2016_SI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/K1_A_2016_SI.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/K1_B_2016_SI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/K1_B_2016_SI.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/K2_2016_SI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/K2_2016_SI.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/K3_2016_SI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/K3_2016_SI.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/OS 2018 SC StEx.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/OS 2018 SC StEx.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/OS Tasks Longlist '20.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/OS Tasks Longlist '20.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04-a-5000.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 04-a-5000 3 | # Намерете командите на 10-те най-стари процеси в системата. 4 | 5 | ps -eo cmd= --sort=start_time | head 6 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04-a-6000.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 04-a-6000 3 | # Намерете PID и командата на процеса, който заема най-много виртуална памет в системата. 4 | 5 | ps -eo pid,cmd --sort=vsz | tail -1 6 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04-a-6300.sh: -------------------------------------------------------------------------------- 1 | # 04-a-6300 2 | # Изведете командата на най-стария процес 3 | 4 | ps -eo cmd= --sort=start_time | head -1 5 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04-b-5000.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 04-b-5000 3 | # Намерете колко физическа памет заемат всички процеси на потребителската група students. 4 | 5 | ps -e -g students -o drs | awk '{m+=$1}END{print m}' 6 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04-b-6100.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 04-b-6100 3 | # Изведете имената на потребителите, които имат поне 2 процеса, чиято команда е vim 4 | 5 | ps -eo user,comm | awk '$2~/vim$/' | cut -d' ' -f1 | uniq -d 6 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04-b-6200.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 04-b-6200 4 | # Изведете имената на потребителите, които не са логнати в момента, но имат живи процеси 5 | 6 | grep -vFxf <(who | cut -d' ' -f1 | sort | uniq) <(ps -eo user= | sort | uniq) 7 | 8 | comm -23 <(ps -eo user= | sort | uniq) <(who | cut -d' ' -f1 | sort | uniq) 9 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04-b-7000.sh: -------------------------------------------------------------------------------- 1 | # 04-b-7000 2 | # Намерете колко физическа памет заемат осреднено всички процеси на потребителската група students. Внимавайте, когато групата няма нито един процес. 3 | 4 | ps -e -g students -o rss= | awk '{m+=$1}END{OFMT="%.3f"; if(NR==0){print 0} else {print m/NR}}' 5 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04-b-8000.sh: -------------------------------------------------------------------------------- 1 | # 04-b-8000 2 | # Намерете всички PID и техните команди (без аргументите), които нямат tty, което ги управлява. Изведете списък само с командите без повторения. 3 | 4 | ps -eo tty,comm,pid | grep -v "^?" | cut -d' ' -f2- | sort | uniq 5 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/04. Processes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/Processes/04. Processes.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/Processes/Processes summary.md: -------------------------------------------------------------------------------- 1 | -- 04-a-5000 2 | Намерете командите на 10-те най-стари процеси в системата. 3 | 4 | ps -eo cmd= --sort=start_time | head 5 | 6 | -- 04-a-6000 7 | Намерете PID и командата на процеса, който заема най-много виртуална памет в системата. 8 | 9 | ps -eo pid,cmd --sort=vsz | tail -1 10 | 11 | -- 04-a-6300 12 | Изведете командата на най-стария процес 13 | 14 | ps -eo cmd= --sort=start_time | head -1 15 | 16 | -- 04-b-5000 17 | Намерете колко физическа памет заемат всички процеси на потребителската група students. 18 | 19 | ps -e -g students -o drs | awk '{m+=$1}END{print m}' 20 | 21 | -- 04-b-6100 22 | Изведете имената на потребителите, които имат поне 2 процеса, чиято команда е vim 23 | 24 | ps -eo user,comm | awk '$2~/vim$/' | cut -d' ' -f1 | uniq -d 25 | 26 | -- 04-b-6200 27 | Изведете имената на потребителите, които не са логнати в момента, но имат живи процеси 28 | 29 | grep -vFxf <(who | cut -d' ' -f1 | sort | uniq) <(ps -eo user= | sort | uniq) 30 | 31 | comm -23 <(ps -eo user= | sort | uniq) <(who | cut -d' ' -f1 | sort | uniq) 32 | 33 | -- 04-b-7000 34 | Намерете колко физическа памет заемат осреднено всички процеси на потребителската група students. Внимавайте, когато групата няма нито един процес. 35 | 36 | ps -e -g students -o drs= | awk 'BEGIN{lines=0}{++lines; m+=$1}END{OFMT="%.3f"; if(lines==0){print 0} else {print m/lines}}' 37 | 38 | -- 04-b-8000 39 | Намерете всички PID и техните команди (без аргументите), които нямат tty, което ги управлява. Изведете списък само с командите без повторения. 40 | 41 | ps -eo tty,comm,pid | grep -v "^?" | cut -d' ' -f2- | sort | uniq 42 | 43 | -- 04-b-9000 44 | Да се отпечатат PID на всички процеси, които имат повече деца от родителския си процес. 45 | 46 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/04-b-9000 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 04-b-9000 1st solution 3 | # github.com/andy489 4 | 5 | function count_children() { 6 | ps --ppid="${1}" | head +2 | wc -l 7 | } 8 | 9 | ps -eo pid=,ppid= | while read PID PPID; do 10 | [ $(count_children "${PID}") -ge $(count_children "${PPID}") ] && echo "${PID}" 11 | done 2>/dev/null 12 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/04-b-9000 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 04-b-9000 2nd solution 3 | # github.com/andy489 4 | 5 | PROCESS_FILE="$(mktemp)" 6 | 7 | ps -e -o pid=,ppid= > "${PROCESS_FILE}" 8 | 9 | function get_children() { 10 | cat "${PROCESS_FILE}" | awk -v pid="${1}" '$2 == pid { print $1 }' 11 | } 12 | 13 | function count_children() { 14 | get_children "${1}" | wc -l 15 | } 16 | 17 | while read PID PPID; do 18 | [ $(count_children "${PID}") -ge $(count_children "${PPID}") ] && echo "${PID}" 19 | done < "${PROCESS_FILE}" 20 | 21 | rm -- "${PROCESS_FILE}" 22 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-2000.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-2000 3 | 4 | read -p "Please, enter your name: " NAME 5 | echo "Hello, ${NAME}" 6 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-2800 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-2800 1st solution 3 | 4 | if [ $# -ne 1 ]; then 5 | echo "Invalid number of arguments!" 6 | exit 1 7 | elif [[ "${1}" =~ ^[[:alnum:]]+$ ]]; then 8 | echo "True" 9 | exit 0 10 | else 11 | echo "False" 12 | exit 1 13 | fi 14 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-2800 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-2800 2nd solution 3 | 4 | if [ $# -ne 1 ]; then 5 | echo "Invalid number of arguments!" 6 | exit 1 7 | elif echo "${1}" | grep -qE '^[[:alnum:]]+$'; then 8 | echo "True" 9 | exit 0 10 | else 11 | echo "False" 12 | exit 1 13 | fi 14 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-2800 3rd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-2800 3rd solution 3 | 4 | if [ $# -ne 1 ]; then 5 | echo "Invalid number of arguments!" 6 | exit 1 7 | elif grep -qE '^[[:alnum:]]+$' <(echo "${1}"); then 8 | echo "True" 9 | exit 0 10 | else 11 | echo "False" 12 | exit 1 13 | fi 14 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-3100.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-3100 3 | 4 | read -p "Enter username: " NAME 5 | who | awk '{print $1}' | grep -wF "${NAME}" | wc -l 6 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-3200 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-3200 1st solution 3 | 4 | read -p "Enter full directory path: " DIR_PATH 5 | 6 | BASE_NAME=$(basename ${DIR_PATH}) 7 | 8 | echo "Count of directories in '${BASE_NAME}' is: \ 9 | $(find "${DIR_PATH}" -mindepth 1 -maxdepth 1 -type d 2>/dev/null |\ 10 | wc -l)" 11 | 12 | echo "Count of files in '${BASE_NAME}' is: \ 13 | $(find "${DIR_PATH}" -mindepth 1 -maxdepth 1 -type f 2>/dev/null |\ 14 | wc -l)" 15 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-3200 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-3200 2nd solution 3 | 4 | read -p "Enter full directory path: " DIR_PATH 5 | 6 | BASE_NAME=$(basename ${DIR_PATH}) 7 | FILES_CNT=0 8 | DIRS_CNT=0 9 | 10 | for i in "${DIR_PATH}"/*; do 11 | if [ -f "${i}" ]; then 12 | FILES_CNT=$((FILES_CNT+=1)) 13 | elif [ -d "${i}" ]; then 14 | DIRS_CNT=$((DIRS_CNT+=1)) 15 | fi 16 | # echo ${i} 17 | done 18 | 19 | echo "Count of directories in '${BASE_NAME}' is: ${DIRS_CNT}" 20 | echo "Count of files in '${BASE_NAME}' is: ${FILES_CNT}" 21 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-3300.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-3300 3 | 4 | if [ ! $# -eq 3 ]; then 5 | echo "Invalid number of argumrnts!" 6 | exit 1 7 | fi 8 | 9 | FILE_1="${1}" 10 | FILE_2="${2}" 11 | 12 | if [ ! -r "${FILE_1}" ] || [ ! -r ${FILE_2} ]; then 13 | echo "First two files are not both readable." 14 | exit 2 15 | fi 16 | 17 | paste "${FILE_1}" "${FILE_2}" | sort > "${3}" 18 | # paste -d "\n" "${FILE_1}" "${FILE_2}" | sort > "${3}" 19 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-3400.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-3400 3 | 4 | read -p "Enter full path name of file: " FILE_NAME 5 | read -p "Enter string to match: " EXP 6 | 7 | grep -qsF "${EXP}" "${FILE_NAME}" 8 | echo $? 9 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4200 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4200 1st solution 3 | 4 | if [ $# -ne 1 ]; then 5 | echo "Invalid number of arguments!" 6 | exit 1 7 | fi 8 | 9 | if [ ! -r $1 ]; then 10 | echo "Error, file not readable" 11 | exit 2 12 | fi 13 | 14 | MAX_CNT=0 15 | CUR_CNT=0 16 | 17 | DATA_FIRST_WAY=$(cat "$1" | grep -o "." | egrep "({|})") 18 | DATA_SECOND_WAY=$(cat "$1" | sed 's/[^{}]//g' | gsed "s/./&\n/g" | sed '/^ *$/d') 19 | 20 | DATA=${DATA_SECOND_WAY} 21 | 22 | for i in $DATA; do 23 | if [ $i = "{" ]; then 24 | CUR_CNT=$((CUR_CNT+1)) 25 | if [ $CUR_CNT -gt $MAX_CNT ]; then 26 | MAX_CNT=$CUR_CNT 27 | fi 28 | else 29 | CUR_CNT=$((CUR_CNT-1)) 30 | fi 31 | done 32 | 33 | echo "The deepest nesting is ${MAX_CNT} levels" 34 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4200 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4200 2nd solution 3 | 4 | [ $# -eq 1 ] || exit 1 5 | [ ! -r $1 ] || exit 2 6 | 7 | F=${1} 8 | 9 | DATA=$(cat $F | sed -e 's/[^{}]//g' | tr -d '\n' | tr -d ' ') 10 | while grep -qsF '{}{' <(echo ${DATA}); do 11 | DATA=$(echo "${DATA}" | sed -e 's/{}{/{/') 12 | done 13 | 14 | ALLCHARS=$(echo ${DATA} | tr -d '}' | wc -c) 15 | echo "The deepest nesting is $((--ALLCHARS)) levels" 16 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4200 3rd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # we assume that there is only one curly bracket per row 3 | 4 | awk 'BEGIN{level=0;maxLevel=0;}\ 5 | /{/{level++}\ 6 | /}/{level--}\ 7 | (level>maxLevel){maxLevel = level}\ 8 | END{print "The deepest nesting is " maxLevel ".";}' $1 9 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4300.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4300 3 | 4 | if [ $# -ne 2 ]; then 5 | echo "Invalid number of arguments!" 6 | exit 1 7 | fi 8 | 9 | ADDRESS_BOOK="${1}" 10 | NICKNAME="${2}" 11 | 12 | if [ ! -f "${ADDRESS_BOOK}" ]; then 13 | echo "Invalid file argument!" 14 | exit 2 15 | elif [ ! -r "${ADDRESS_BOOK}" ]; then 16 | echo "File is not readable!" 17 | exit 3 18 | fi 19 | 20 | if ! fgrep -wq "${NICKNAME}" "${ADDRESS_BOOK}"; then 21 | echo "Nickname ${NICKNAME} is not in the address book!" 22 | exit 4 23 | fi 24 | 25 | USERNAME=$(fgrep -w "${NICKNAME}" "${ADDRESS_BOOK}" | head -1 | awk '{print $2}') 26 | 27 | if ! id -u "${USERNAME}" &>/dev/null; then 28 | echo "Invalid username!" 29 | exit 5 30 | elif ! who | awk '{print $1}' | fgrep -qE "^${USERNAME}$"; then 31 | echo "User ${USERNAME} is not logged in!" 32 | exit 6 33 | fi 34 | 35 | read -p "Enter message: " MSG 36 | 37 | echo "${MSG}" | write "${USERNAME}" 38 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4301.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4301 3 | 4 | if [ $# -ne 3 ]; then 5 | echo "Invalid number of arguments!" 6 | exit 1 7 | fi 8 | 9 | ADDRESS_FILE="${1}" 10 | 11 | if [ ! -f "${ADDRESS_FILE}" ]; then 12 | echo "First argument is not a file!" 13 | exit 2 14 | elif [ ! -r "${ADDRESS_FILE}" ]; then 15 | echo "Address book file is not readable!" 16 | exit 3 17 | elif [ ! -w "${ADDRESS_FILE}" ]; then 18 | echo "Address book file is not writable!" 19 | exit 4 20 | fi 21 | 22 | NAME="${2}" 23 | NICK="${3}" 24 | 25 | USERNAME=$(cat ~velin/passwd.txt | awk -v name="${NAME}" -F ':' '($5 == name){print $1}') 26 | 27 | #if [ $(wc -l "${USERNAME}") -ne 1 ]; then 28 | # echo "Do the bonus thing" 29 | #fi 30 | 31 | echo "${NICK} ${USERNAME}" >> "${ADDRESS_FILE}" 32 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4400.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4400.sh 3 | 4 | if [ $# -eq 0 ]; then 5 | echo "Invalid number of arguments!" 6 | exit 1 7 | fi 8 | 9 | FIRST_DIR_PATH="${1}" 10 | 11 | if [ ! -d "${FIRST_DIR_PATH}" ]; then 12 | echo "First argument is not a directory!" 13 | exit 2 14 | fi 15 | 16 | SECOND_DIR_PATH="" 17 | 18 | if [ $# -eq 2 ]; then 19 | SECOND_DIR_PATH="${2}" 20 | else 21 | if [ $# -eq 1 ]; then 22 | SECOND_DIR_PATH="target-$(date +'%Y-%m-%d-%H-%M')" 23 | mkdir "${SECOND_DIR_PATH}" 24 | else 25 | echo "Too many arguments!" 26 | exit 3 27 | fi 28 | fi 29 | 30 | if [ ! -d "${SECOND_DIR_PATH}" ]; then 31 | echo "Second file is not a directory!" 32 | exit 3 33 | fi 34 | 35 | echo "Source directory: ${FIRST_DIR_PATH}" 36 | echo "Destination directory: ${SECOND_DIR_PATH}" 37 | echo -e "\nChanged files in the last 45 mins in Source directory:\n" 38 | 39 | find "${FIRST_DIR_PATH}" -type f -mmin -45 -exec echo {} \; 40 | 41 | find "${FIRST_DIR_PATH}" -type f -mmin -45 -exec cp {} "${SECOND_DIR_PATH}" \; 42 | 43 | #find "${FIRST_DIR_PATH}" -type f -mmin -45 | while read FILE; do 44 | # cp "${FILE}" "${SECOND_DIR_PATH}" 45 | #done 46 | 47 | echo -e "\n~Copying files was successfull\n" 48 | 49 | tar -zcvf "${SECOND_DIR_PATH}".tar.gz "${SECOND_DIR_PATH}" 50 | 51 | [ $? -eq 0 ] && echo -e "\n~Archivating was successful\n" 52 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4500.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4500.sh 3 | # github.com/andy489 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | USERNAME="${1}" 11 | 12 | if ! cut -d ':' -f1 /etc/passwd | fgrep -qE "^${USERNAME}$"; then 13 | echo "Invalid username!" 14 | exit 2 15 | fi 16 | 17 | until who -u | awk -F : '{print $1} | fgrep -qE "^${USERNAME}$"; do 18 | sleep 1 19 | done 20 | 21 | echo "User ${USERNAME} has just logged in" 22 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4600.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4600 3 | 4 | if [ $# -ne 3 ]; then 5 | #echo "Invalid number of arguments!" 6 | exit 4 7 | fi 8 | 9 | grep -vqE '^[+-]?[0-9]+$' <(echo "${1}"; echo "${2}"; echo "${3}") 10 | 11 | if [ $? -eq 0 ]; then 12 | #echo "At least one of the arguments is not an integer!" 13 | exit 3 14 | fi 15 | 16 | if [ $2 -gt $3 ]; then 17 | #echo "Reversed intervals" 18 | exit 2 19 | fi 20 | 21 | if [ $1 -lt $2 ] || [ $1 -gt $3 ]; then 22 | #echo "Not in interval" 23 | exit 1 24 | fi 25 | 26 | if [ $1 -ge $2 ] && [ $1 -le $3 ]; then 27 | #echo "In interval" 28 | exit 0 29 | fi 30 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4700 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4700 1st solution 3 | # girhub.com/andy489 4 | 5 | if [ $# -eq 1 ]; then 6 | DELIMITER=" " 7 | elif [ $# -eq 2 ]; then 8 | DELIMITER="${2}" 9 | else 10 | echo "Invalid number of parameters" 11 | exit 1 12 | fi 13 | 14 | grep -qE '^[-+]?[0-9]+$' <(echo "${1}") 15 | 16 | if [ ! $? -eq 0 ]; then 17 | echo "Invalid integer number!" 18 | exit 2 19 | fi 20 | 21 | NUM=$(echo "${1}") 22 | SIGN=$(echo "${1}" | cut -c1) 23 | 24 | FLAG=0 25 | grep -q [-+] <(echo "${SIGN}") 26 | 27 | if [ $? -eq 0 ]; then 28 | NUM=$(echo "${NUM}" | cut -c2-) 29 | FLAG=1 30 | fi 31 | 32 | REV_NUM=$(echo "${NUM}" | gsed 's/./&\n/g' | tac) 33 | 34 | CNT=1 35 | 36 | for i in ${REV_NUM}; do 37 | NEW_NUM+="${i}" 38 | if [ $(($CNT%3)) -eq 0 ]; then 39 | NEW_NUM+="${DELIMITER}" 40 | fi 41 | CNT=$((CNT+1)) 42 | done 43 | 44 | DEL_FIRST_DELI=0 45 | 46 | if [ $(( (${CNT}-1)%3 )) -eq 0 ]; then 47 | DEL_FIRST_DELI=1 48 | fi 49 | 50 | [ "${FLAG}" -eq 1 ] && echo -n "${SIGN}" 51 | REST_NUM=$(echo -e "${NEW_NUM}" | grep -o . | tac | tr -d "\n" ; echo) 52 | if [ ${DEL_FIRST_DELI} -eq 1 ]; then 53 | REST_NUM=$(echo "${REST_NUM}" | cut -c2-) 54 | fi 55 | 56 | echo "${REST_NUM}" 57 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4700 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4700 2nd solution 3 | # girhub.com/andy489 4 | 5 | if [ $# -eq 1 ]; then 6 | DELIMITER=" " 7 | elif [ $# -eq 2 ]; then 8 | DELIMITER="${2}" 9 | else 10 | echo "Invalid number of parameters" 11 | exit 1 12 | fi 13 | 14 | grep -qE '^[-+]?[0-9]+$' <(echo "${1}") 15 | 16 | if [ ! $? -eq 0 ]; then 17 | echo "Invalid integer number!" 18 | exit 2 19 | fi 20 | 21 | NUM=$(echo "${1}" | grep -o .) 22 | SIGN=$(echo "${NUM}" | head -1) 23 | 24 | FLAG=0 25 | grep -q [-+] <(echo "${SIGN}") 26 | 27 | if [ $? -eq 0 ]; then 28 | NUM=$(echo "${NUM}" | tail -n +2) 29 | FLAG=1 30 | fi 31 | 32 | [ "${FLAG}" -eq 1 ] && echo -n "${SIGN}" 33 | 34 | echo "${NUM}" | tac | xargs -n3 | tr -d " " | tr "\n" "${DELIMITER}" |\ 35 | grep -o . | tac | tail -n +2 | tr -d "\n" ; echo 36 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4700 3rd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4700 3rd solution 3 | # github.com/andy489 4 | 5 | case $# in 6 | 1) N="${1}"; D=" " 7 | ;; 8 | 2) N="${1}"; D="${2}" 9 | ;; 10 | *) echo "Invalid number of arguments!"; exit 1 11 | ;; 12 | esac 13 | 14 | if ! grep -qE '^[-+]?[0-9]+$' <(echo "${N}"); then 15 | echo "Invalid number!" 16 | exit 2 17 | fi 18 | 19 | echo "${N}" | rev | sed -E "s/(.{3})/\1$D/g" | rev \ 20 | | sed -e "s/^$D//" \ 21 | | sed -E "s/^([-+])$D/\1/" 22 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-4800.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-4800.sh 3 | # github.com/andy489 4 | 5 | if [ $# -ne 2 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | SEARCHED_FILE="${1}" 11 | DIR_PATH="${2}" 12 | 13 | if [ ! -f "${SEARCHED_FILE}" ]; then 14 | echo "First argument is not a file!" 15 | exit 2 16 | elif [ ! -r "${SEARCHED_FILE}" ]; then 17 | echo "File is not readable!" 18 | exit 3 19 | fi 20 | 21 | if [ ! -d "${DIR_PATH}" ]; then 22 | echo "Second argument is not a directory!" 23 | exit 4 24 | elif [ ! -r "${DIR_PATH}" ]; then 25 | echo "Directory is not readable!" 26 | exit 5 27 | fi 28 | 29 | SEARCHED_HASH=$(md5sum "${SEARCHED_FILE}" | awk '{print $1}') 30 | 31 | CNT=0 32 | 33 | while read CUR_HASH FILE_PATH; do 34 | if [ "${CUR_HASH}" = "${SEARCHED_HASH}" ]; then 35 | echo "$(basename ${FILE_PATH})" 36 | CNT=$(( ++CNT )) 37 | fi 38 | done < <(find "${DIR_PATH}" -type f 2>/dev/null -print0 \ 39 | | xargs -0 -I {} md5sum {}) 40 | 41 | if [ $CNT -eq 0 ]; then 42 | echo "~No copies found." 43 | else 44 | echo "~Found total $CNT duplicates." 45 | fi 46 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-5500.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-5500 3 | # github.com/andy489 4 | 5 | cat ~andreystoev/passwd.txt |\ 6 | awk -F : 'BEGIN { printf("\n \n \n \n \n \n \n", 7 | "Username", "Group", "Login Shell", "GECKO") } 8 | { printf(" \n \n \n \n \n \n",$1, $4, $5, $7) } 9 | END { printf("
%s%s%s%s
%s%s%s%s
\n") }' 10 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-6600 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-6600 1st solution 3 | # github.com/andy489 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | DIR_PATH="${1}" 11 | 12 | if [ ! -d "${DIR_PATH}" ]; then 13 | echo "Argument is not directory!" 14 | exit 2 15 | fi 16 | 17 | if [ ! -r "${DIR_PATH}" ]; then 18 | echo "Directory has no read permissions!" 19 | exit 3 20 | fi 21 | 22 | HASHES=$(mktemp) 23 | 24 | find "${DIR_PATH}" -type f -maxdepth 1 -exec md5sum {} 2>/dev/null \; |\ 25 | sort > "${HASHES}" 26 | 27 | cat "${HASHES}" | cut -d' ' -f1 | uniq -d | while read DUPLICATED_HASH; do 28 | grep "${DUPLICATED_HASH}" "${HASHES}" \ 29 | | awk '{print $2}' \ 30 | | tail -n +2 \ 31 | | xargs rm -- 32 | done 33 | 34 | rm "${HASHES}" 35 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-6600 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-6600 2nd solution 3 | # github.com/andy489 4 | 5 | [ $# -eq 1 ] || exit 1 6 | 7 | [ -d "${1}" ] || exit 2 8 | 9 | [ -r "${1}" ] || exit 3 10 | 11 | while read -d $'\n' LINE ; do 12 | find "${1}" -maxdepth 1 -type f -exec md5sum {} \; \ 13 | | awk -v FIRST="${LINE}" '$1 == FIRST {print $2}' \ 14 | | sort | tail -n +2 | xargs -I{} rm {} 15 | done < <( find "${1}" -maxdepth 1 -type f -exec md5sum {} \; \ 16 | | awk '{ print $1}' | sort | uniq -d ) 17 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-6800.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-6800 3 | # github.com/andy489 4 | 5 | [ $# -eq 0 ] && exit 0 6 | 7 | FIRST_ARG="${1}" 8 | FLAG_INCLUDE_HIDDEN="not set" 9 | 10 | if [ "${FIRST_ARG}" = -a ]; then 11 | FLAG_INCLUDE_HIDDEN="-a" 12 | shift 1 13 | fi 14 | 15 | [ $# -eq 0 ] && exit 0 16 | 17 | DIR_PATH="${1}" 18 | 19 | if [ ! -d "${DIR_PATH}" ]; then 20 | echo "Invalid directory name!" 21 | exit 1 22 | elif [ ! -r "${DIR_PATH}" ]; then 23 | echo "Directory is not readable!" 24 | exit 2 25 | fi 26 | 27 | if [ "${FLAG_INCLUDE_HIDDEN}" = -a ]; then 28 | echo "Including hidden files:" 29 | while read -d $'\n' i; do 30 | BASE_NAME=$(basename ${i}) 31 | if [ -f "${i}" ]; then 32 | eval $(stat -s "${i}") 33 | echo "${BASE_NAME} (${st_size} bytes)" 34 | elif [ -d "${i}" ]; then 35 | ENTRIES=$(find "${i}" | wc -l | awk '{$1=$1}1') 36 | echo "${BASE_NAME} (${ENTRIES} entries)" 37 | fi 38 | done < <(find . -maxdepth 1 -mindepth 1) 39 | else 40 | echo "Not incuding hidden files:" 41 | for i in "${DIR_PATH}"/*; do 42 | BASE_NAME=$(basename "${i}") 43 | if [ -f "${i}" ]; then 44 | eval $(stat -s "${i}") 45 | echo "${BASE_NAME} (${st_size} bytes)" 46 | elif [ -d "${i}" ]; then 47 | ENTRIES=$(find "${i}" ! -name '.*' | wc -l | awk '{$1=$1}1') 48 | echo "${BASE_NAME} (${ENTRIES} entries)" 49 | fi 50 | done 51 | fi 52 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7000.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7000 3 | # github.com/andy489 4 | 5 | if [ $# -eq 0 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | read -p "Insert searched string: " STRING 11 | 12 | while [ $# -ne 0 ]; do 13 | FILE_NAME="${1}" 14 | if [ ! -f "${FILE_NAME}" ]; then 15 | echo "Invalid file name given as argument!" 16 | elif [ ! -r "${FILE_NAME}" ]; then 17 | echo "File is not readable!" 18 | else 19 | CUR_MATCHES=$(grep -oc "${STRING}" "${FILE_NAME}") 20 | echo "In file \"${FILE_NAME}\", ${CUR_MATCHES} rows contains string \"${STRING}\"" 21 | fi 22 | shift 1 23 | done 24 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7100.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7100 3 | # github.com/andy489 4 | 5 | if [ $# -ne 2 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | DIR_PATH="${1}" 11 | NUM="${2}" 12 | 13 | if [ ! -d "${DIR_PATH}" ]; then 14 | echo "First argument is not a directory" 15 | exit 2 16 | elif [ ! -r "${DIR_PATH}" ]; then 17 | echo "Directory is not readable!" 18 | exit 3 19 | fi 20 | 21 | function validate_num { 22 | grep -qE '^[+-]?[0-9]+$' <(echo "${1}") 23 | } 24 | 25 | if validate_num "${NUM}" ; then 26 | #find . -type f 2>/dev/null -size +"${NUM}"c -printf "%f\n" 27 | while read -r -d% SIZE FILE_PATH; do 28 | if validate_num "${SIZE}"; then 29 | if [ "${SIZE}" -gt "${NUM}" ]; then 30 | echo "${FILE_PATH}" 31 | fi 32 | fi 33 | done < <(find "${DIR_PATH}" -type f 2>/dev/null -printf "%s %p%%") 34 | else 35 | echo "Second argument is not an integer!" 36 | exit 4 37 | fi 38 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7200 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7200 1st solution 3 | # github.com/andy489 4 | 5 | for i; do 6 | if [ -f "${i}" ]; then 7 | if [ -r "${i}" ]; then 8 | echo "$(basename "${i}") is readable file" 9 | else 10 | echo "$(basename "${i}") is not readabl file" 11 | fi 12 | elif [ -d "${i}" ]; then 13 | COUNT_FILES=$(find "${i}" -type f 2>/dev/null | wc -l | awk '{$1=$1}1') 14 | echo "$(find "${i}" -type f -size -"${COUNT_FILES}"c 2>/dev/null |\ 15 | xargs basename -a)" 16 | else 17 | echo "$(basename "${i}") is not a file/directory name!" 18 | fi 19 | done 20 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7200 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7200 2nd solution 3 | # github.com/andy489 4 | 5 | for i; do 6 | if [ -f "${i}" ]; then 7 | if [ -r "${i}" ]; then 8 | echo "$(basename "${i}") is readable file" 9 | else 10 | echo "$(basename "${i}") is not readabl file" 11 | fi 12 | elif [ -d "${i}" ]; then 13 | COUNT_FILES=$(find "${i}" -type f 2>/dev/null | wc -l | awk '{$1=$1}1') 14 | gfind "${i}" -type f 2>/dev/null -printf "%s %f\n" \ 15 | | awk -v sz="${COUNT_FILES}" '$1 < sz {print $2}' 16 | else 17 | echo "$(basename "${i}") is not a file/directory name!" 18 | fi 19 | done 20 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7500.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7500 3 | # github.com/andy489 4 | 5 | NUM=$(( (RANDOM%200)-100 )) 6 | 7 | GUESSES_CNT=0 8 | 9 | read -p 'Guess? ' GUESS 10 | 11 | function validate_guess { 12 | grep -qE '^[+-]?[0-9]+$' <(echo "${1}") 13 | } 14 | 15 | while true; do 16 | GUESS_CNT=$((GUESS_CNT+1)) 17 | if validate_guess "${GUESS}"; then 18 | if [ "${GUESS}" -gt "${NUM}" ]; then 19 | echo '...smaller!' 20 | elif [ "${GUESS}" -lt "${NUM}" ]; then 21 | echo '...bigger!' 22 | else 23 | echo "RIGHT! Guessed ${NUM} in ${GUESS_CNT} tries!" 24 | exit 0 25 | fi 26 | else 27 | echo 'Not a valid guess!' 28 | fi 29 | read -p 'Guess? ' GUESS 30 | done 31 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7550 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7550 1st solution 3 | # github.com/andy489 4 | 5 | : ' 6 | Do not use kill -9 7 | It does not give the process a chance to cleanly: 8 | 1) shut down socket connections 9 | 2) clean up temp files 10 | 3) inform its children that it is going away 11 | 4) reset its terminal characteristics 12 | and so on and so on. 13 | Generally, send 15, and wait a second or two, and if that does not work, send 2, 14 | and if that does not work send 1. If that does not work, REMOVE THE BINARY because 15 | the program is badly behaved! 16 | ' 17 | if [ $# -ne 1 ]; then 18 | echo "Invalid number of arguments!" 19 | exit 1 20 | fi 21 | 22 | USER="${1}" 23 | 24 | if [ $(id -u "${USER}") -eq 1 ]; then 25 | echo "Invalid username!" 26 | exit 2 27 | fi 28 | 29 | PS_CNT=0 30 | 31 | while read PID; do # read -d $'\n' PID 32 | kill -15 "${PID}" 33 | sleep 1 34 | kill -9 "${PID}" 35 | PS_CNT=(($PS_CNT+1)) 36 | done < <(ps -u "${USER}" -o pid=) 37 | 38 | echo "Total: ${PS_CNT} killed processes" 39 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7550 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7550 2nd solution 3 | # github.com/andy489 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | USER="${1}" 11 | 12 | if [ $(id -u "${USER}") -eq 1 ]; then 13 | echo "Invalid username!" 14 | exit 2 15 | fi 16 | 17 | PS_CNT=$(ps -u "${USER}" | wc -l) 18 | killall -15 -u "${USER}" 19 | killall -9 -u "${USER}" 20 | echo "Total: ${PS_CNT} killed processes" 21 | 22 | # run with sudo ./05-b-7550.sh user 23 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7700 1st sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7700 1st solution 3 | # github.com/andy489 4 | 5 | if [ $# -ne 2 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | DIR_PATH="${1}" 11 | NUM="${2}" 12 | 13 | if [ ! -d "${DIR_PATH}" ]; then 14 | echo "Invalid directory name!" 15 | exit 2 16 | elif [ ! -r "${DIR_PATH}" ]; then 17 | echo "Directory is not readable!" 18 | exit 3 19 | fi 20 | 21 | function validate_num { 22 | grep -qE '^[-+]?[0-9]+$' <(echo ${NUM}) 23 | } 24 | 25 | if validate_num "${NUM}"; then 26 | find "${DIR_PATH}" -maxdepth 1 -type f 2>/dev/null -printf "%s\n" \ 27 | | awk -v sz="${NUM}" '$1 > sz {SUM+=$1} END {print SUM}' 28 | else 29 | echo "Second argument is an invalid integer number!" 30 | exit 4 31 | fi 32 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7700 2nd sol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7700 2nd solution 3 | # github.com/andy489 4 | 5 | if [ $# -ne 2 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | DIR_PATH="${1}" 11 | NUM="${2}" 12 | 13 | if [ ! -d "${DIR_PATH}" ]; then 14 | echo "Invalid directory name!" 15 | exit 2 16 | elif [ ! -r "${DIR_PATH}" ]; then 17 | echo "Directory is not readable!" 18 | exit 3 19 | fi 20 | 21 | function validate_num { 22 | grep -qE '^[-+]?[0-9]+$' <(echo ${NUM}) 23 | } 24 | 25 | if validate_num "${NUM}"; then 26 | ALL_SIZES=$(find "${DIR_PATH}" -maxdepth 1 -type f 2>/dev/null -size -"${NUM}"c -printf "%s\n") 27 | # echo "${ALL_SIZES}" 28 | TOTAL_SIZE=0 29 | for i in ${ALL_SIZES}; do 30 | (( TOTAL_SIZE+="${i}" )) 31 | done 32 | echo "${TOTAL_SIZE}" 33 | else 34 | echo "Second argument is an invalid integer number!" 35 | exit 4 36 | fi 37 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-7800.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-7800 3 | # github.com/andy489 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "Invalid number of arguments" 7 | exit 1 8 | fi 9 | 10 | DIR_PATH="${1}" 11 | 12 | if [ ! -d "${DIR_PATH}" ]; then 13 | echo "Invalid directory name!" 14 | exit 2 15 | elif [ ! -r "${DIR_PATH}" ]; then 16 | echo "Directory is not readable!" 17 | exit 3 18 | fi 19 | 20 | CNT_X=0 21 | 22 | while read -d $'\n' LINE; do 23 | if [ -x "${LINE}" ]; then 24 | (( CNT_X+=1 )) 25 | fi 26 | done < <(gfind "${DIR_PATH}" 2>/dev/null) 27 | 28 | echo "Number of executable files is ${CNT_X}" 29 | 30 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-8000.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-8000 3 | # github.com/andy489 4 | 5 | : ' 6 | This script calculates the proportion of 7 | Resident Set Size (memory allocated to a process in RAM) 8 | and Virtual Memory Size (memory that a process can access) 9 | for every specific user process 10 | ' 11 | 12 | [ $# -eq 1 ] || { 13 | echo "Invalid number of arguments. Usage $0 ." 14 | exit 1 15 | } 16 | 17 | _USER="${1}" 18 | 19 | if ! id "${_USER}" &>/dev/null ; then 20 | echo "Invalid username!" 21 | exit 2 22 | fi 23 | 24 | ps -u "${_USER}" -o pid,rss,vsz | tail -n +2 | while read PID RSS VSZ; do 25 | if [ $VSZ -eq 0 ]; then 26 | PROPORTION="inf" 27 | else 28 | PROPORTION=$(echo "scale=4; $RSS / $VSZ" | bc) 29 | fi 30 | echo "${VSZ} ${PID} consume ${PROPORTION} of RSS/VSZ memory" 31 | done | sort -rn -t' ' -k1 | cut -d' ' -f2- 32 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-9100.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-9100.sh 3 | # github.com/andy489 4 | 5 | if [ $# -ne 2 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | S="${1}" # S=SOURCE 11 | D="${2}" # D=DESTINATION 12 | 13 | if [ ! -d "${S}" ]; then 14 | echo "Invalid source directory!" 15 | exit 2 16 | elif [ ! -r "${S}" ]; then 17 | echo "Source directory is not readable!" 18 | exit 3 19 | fi 20 | 21 | if [ ! -d "${D}" ]; then 22 | echo "Invalid destination directory!" 23 | exit 4 24 | elif [ ! -r "${S}" ]; then 25 | exho "Destination directory is not readable!" 26 | exit 5 27 | fi 28 | 29 | while read EXT; do 30 | mkdir -p "${D}/${EXT}" 31 | gfind "${S}" -type f -name "*.${EXT}" 2>/dev/null -print0 | xargs -0 -I {} mv {} "${D}/${EXT}" 32 | done < <(gfind "${S}" -type f -name "*.*" -printf "%f\n" \ 33 | | rev | cut -d '.' -f1 | rev | sort | uniq ) 34 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-9200.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-9200 3 | # github.com/andy489 4 | 5 | echo -e "Usage:\n-r [ args ] deletes recursively files in given args\n" 6 | 7 | [ $# -eq 0 ] && exit 0 8 | 9 | FIRST_ARG="${1}" 10 | FLAG_RECUR=0 11 | 12 | if [ "${FIRST_ARG}" = -r ]; then 13 | FLAG_RECUR=1 14 | shift 1 15 | fi 16 | 17 | export LOGFILE=$(mktemp) 18 | 19 | for i; do 20 | if [ -d "${i}" ]; then 21 | DIR_CONTENTS=$(find "${i}" -mindepth 1 | wc -l | awk '{$1=$1}1') 22 | if [ "${DIR_CONTENTS}" -eq 0 ]; then 23 | 24 | echo "[$(date +"Y-%m-%d %H:%M:%S")] Removed directory ${i}/" >> "${LOGFILE}" 25 | rm -di "${i}" # rmdir "${i}" 26 | 27 | elif [ "${FLAG_RECUR}" -eq 1 ]; then 28 | 29 | echo "[$(date +"Y-%m-%d %H:%M:%S")] Removed directory recursively ${i}/" >> "${LOGFILE}" 30 | rm -Rdi "${i}" 31 | 32 | fi 33 | elif [ -f "${i}" ]; then 34 | echo "[$(date +"%Y-%m-%d %H:%M:%S")] Removed file ${i}" >> "${LOGFILE}" 35 | rm -di ${i} 36 | fi 37 | done 38 | 39 | echo "Log file info:" 40 | cat ${LOGFILE} 41 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-9501.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-9501 3 | # github.com/andy489 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "Invalid number of arguments!" 7 | exit 1 8 | fi 9 | 10 | SC="${1}" #S = starting color 11 | 12 | if ! grep -qE '^-[rgbx]$' <(echo "${SC}"); then 13 | echo "Invalid color argument!" 14 | exit 2 15 | fi 16 | 17 | case "${SC}" in 18 | -r) COUNT=0 19 | ;; 20 | -g) COUNT=1 21 | ;; 22 | -b) COUNT=2 23 | ;; 24 | -x) COUNT=3 25 | ;; 26 | esac 27 | 28 | if [ ${COUNT} -eq 3 ]; then 29 | 30 | while read LINE; do 31 | echo "${LINE}" 32 | done 33 | 34 | exit 0 35 | 36 | fi 37 | 38 | function change_color { 39 | N=${1} 40 | STR=${2} 41 | REM=$((${N} % 3)) 42 | 43 | case "${REM}" in 44 | 0) 45 | echo -e "\033[0;31m${STR}" 46 | ;; 47 | 1) 48 | echo -e "\033[0;32m${STR}" 49 | ;; 50 | 2) 51 | echo -e "\033[0;34m${STR}" 52 | ;; 53 | esac 54 | } 55 | 56 | while read LINE; do 57 | change_color ${COUNT} ${LINE} 58 | COUNT=$(( COUNT + 1 )) 59 | done 60 | 61 | # Usage: cat file.txt | ./05-b-9501 -r 62 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05-b-9600.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 05-b-9600 3 | # github.com/andy489 4 | 5 | [ $# -eq 0 ] && exit 1 6 | 7 | FIRST_ARG="${1}" 8 | FLAG=0 9 | 10 | if [ "${FIRST_ARG}" = -r ];then 11 | FLAG=1 12 | shift 1 13 | fi 14 | 15 | function timestamp { 16 | date +"%Y-%m-%d-%H-%M-%S" 17 | } 18 | 19 | function archive_and_save { 20 | SRC=$1 21 | POSTFIX=$2 22 | TIMESTAMP=$(timestamp) 23 | tar -czf "${BACKUP_DIR}/${TIMESTAMP}_${POSTFIX}.tgz" "${SRC}" 24 | } 25 | 26 | function compress_and_save { 27 | SRC=$1 28 | TIMESTAMP=$(timestamp) 29 | gzip -c "${SRC}" > "${BACKUP_DIR}/${SRC}_${TIMESTAMP}.gz" 30 | } 31 | 32 | for i; do 33 | if [ -d "${i}" ]; then 34 | DIR_CONTENT=$(find "${i}" -mindepth 1 -maxdepth 1 2>/dev/null | wc -l) 35 | if [ "${DIR_CONTENT}" -eq 0 ]; then 36 | archive_and_save "${i}" "empty_dir" 37 | rm -i -d "${i}" 38 | elif [ "${FLAG}" -eq 1 ];then 39 | archive_and_save "${i}" "full_dir" 40 | rm -i -d -R "${i}" 41 | fi 42 | elif [ -f "${i}" ]; then 43 | compress_and_save "${i}" 44 | rm -i -- "${i}" 45 | fi 46 | done 47 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05. Shell Introduction.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/Shell/05. Shell Introduction.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/05. Shell Tasks.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/Shell/05. Shell Tasks.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/Change files extention.sh: -------------------------------------------------------------------------------- 1 | /* 2 | Да се напише shell скрипт, който приема точно три аргумента - име на директория, старо файлово разширение и ново файлово 3 | разширение. Във всички директории с подаденото име, скрипта да поставя на всички файлове с подаденото 4 | старо разширение - новото разширение. 5 | 6 | Примерно извикване: 7 | (change file extension) 8 | ./chfext "dir" "avi" "mp3" 9 | 10 | Резултат: 11 | renamed '/home/students/s61000/dir/film.avi' -> '/home/students/s61000/dir/film.mp3' 12 | renamed '/home/students/s61000/dir/mov1.avi' -> '/home/students/s61000/dir/mov1.mp3' 13 | renamed '/home/students/s61000/dir/mov2.avi' -> '/home/students/s61000/dir/mov2.mp3' 14 | renamed '/home/students/s61000/folder/dir/deeper.avi' -> '/home/students/s61000/folder/dir/deeper.mp3' 15 | */ 16 | 17 | #!/bin/bash 18 | 19 | [ $# -eq 3 ] || { 20 | echo "Invalid number of arguments. Usage: ${0} ." 21 | exit 1 22 | } 23 | 24 | DIRNAME="${1}" 25 | OLD="${2}" 26 | NEW="${3}" 27 | 28 | while read DIRPATH; do 29 | for FILE in ${DIRPATH}/*.${OLD}; do 30 | mv -v -- "${FILE}" "${FILE%${OLD}}${NEW}" 2> /dev/null 31 | done 32 | done < <(find / -type d -name "${DIRNAME}" 2> /dev/null) 33 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/Draw Pyramid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | n=$1 4 | 5 | for((r=1; r<=n; ++r)) 6 | do 7 | for((j=0; j"; exit 1;} 4 | 5 | DIR_PATH="${1}" 6 | 7 | [ -d "${DIR_PATH}" ] || { echo "Invalid directory name"; exit 2; } 8 | [ -r "${DIR_PATH}" ] || { echo "Directory is not readable"; exit 3; } 9 | [ -x "${DIR_PATH}" ] || { echo "Directory is not searchable"; exit 4; } 10 | 11 | LENGTH_FILENAME=$(mktemp) 12 | 13 | gfind "${DIR_PATH}" -type f -printf "%f\n" 2>/dev/null |\ 14 | awk '{printf "%s %s\n", length($0),$0}' |\ 15 | sort -n -t' ' -k1 > "${LENGTH_FILENAME}" 16 | 17 | MAXLENGHT="$(cat "${LENGTH_FILENAME}" | tail -1 | cut -d' ' -f1)" 18 | #echo "MAX LENGHT: ${MAXLENGHT}" 19 | 20 | grep '^30 ' "${LENGTH_FILENAME}" | cut -d' ' -f2- 21 | 22 | rm -- "${LENGTH_FILENAME}" 23 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Shell/Find Longest Filename.md: -------------------------------------------------------------------------------- 1 | **Задача.** *(Longest Filename Search)* Да се напише shell script, който получава 1 задължителен параметър – пълен път към директория. Script-a да връща най-дългитото име на файл, което съществува във 2 | файловете в тази директория както и във всяка една от поддиректориите ѝ. Ако има няколко файла с еднаква дължина, която е най-дългата съществуваща такава, script-а 3 | да извежда всички тези файлове. 4 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/05. Shell Exam problems.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/Test 2 Preparation/05. Shell Exam problems.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/13 (solution 1).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 13.sh 1st solution 3 | 4 | [ $# -eq 1 ] || { 5 | echo "Invalid number of arguments. Usage: ${0} " >&2 6 | exit 1 7 | } 8 | 9 | D="${1}" 10 | 11 | [ -d "${D}" -a -r "${D}" ] || { 12 | echo "Not directory or not readable." >&2 13 | exit 2 14 | } 15 | 16 | find "${D}" -type l -printf "%Y %p\n" 2>/dev/null | grep -e "^[NL]" | cut -c3- 17 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/13 (solution 2).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 13.sh 2nd solution 3 | 4 | [ $# -eq 1 ] || { echo "Invalid number of arguments. Usage: $0 "; exit 1; } 5 | 6 | DIRNAME="${1}" 7 | 8 | [ -d "${DIRNAME}" -a -r "${DIRNAME}" ] || { echo "Not directory or not readable"; exit 2; } 9 | 10 | find "${DIRNAME}" -type l -print0 2>/dev/null \ 11 | | xargs -0 -I {} file {} \ 12 | | fgrep "broken" | cut -d':' -f1 13 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/14.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 14.sh 3 | 4 | [ $# -eq 1 ] || { echo "Invalid number of arguments. Usage: $0 "; exit 1; } 5 | 6 | [ $(id -u) -eq 0 ] || exit 0 7 | 8 | N="${1}" 9 | 10 | if ! grep -qE '^[-+]?[0-9]+$' <(echo "${N}"); then 11 | echo "Invalid argument" 12 | exit 3 13 | fi 14 | 15 | USERS=$(mktemp) 16 | ps -e -o user= | sort | uniq > "${USERS}" 17 | 18 | while read _USER; do 19 | USER_TOTAL_RSS=0 20 | while read PID RSS; do 21 | USER_TOTAL_RSS=$(expr $USER_TOTAL_RSS + $RSS) 22 | LAST_PID="${PID}" 23 | done < <(ps -u "${_USER}" -o pid=,rss= | sort -n -k2) 24 | 25 | echo "Total ${USER_TOTAL_RSS} resident set size for user ${_USER}" 26 | 27 | if [ ${USER_TOTAL_RSS} -gt ${N} ]; then 28 | kill -s TERM "${LAST_PID}" 29 | sleep 1 30 | kill -s KILL "${LAST_PID}" 31 | fi 32 | done < "${USERS}" 33 | rm -- "${USERS}" 34 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/15.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 15 3 | 4 | [ $(id -u) -eq 0 ] || exit 0 5 | 6 | while read _USER _HOME; do 7 | if [ ! -d "${_HOME}" ] || sudo -u "${_USER}" [ ! -w "${_HOME}" ]; then 8 | echo "${_USER}" 9 | fi 10 | done < <(cat /etc/passwd | awk -F : '{print $1,$6}') 11 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/16 (solution 1).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 16.sh 3 | 4 | [ $# -eq 3 ] || { echo "Invalid number of arguments"; exit 1; } 5 | 6 | FILE="${1}"; KEY_1="${2}"; KEY_2="${3}" 7 | 8 | [ -f "${FILE}" -a -r "${FILE}" ] || { echo "Not file or not readable"; exit 2; } 9 | 10 | [ -n "${KEY_1}" -a -n "${KEY_2}" ] || { echo "There is a key with length 0"; exit 3; } 11 | 12 | VALUE_1=$( grep "${KEY_1}" "${FILE}" | cut -d'=' -f2 | awk '{$1=$1}1' | tr ' ' '\n' | sort | uniq) 13 | 14 | VALUE_2=$( grep -vxF -f <(echo "${VALUE_1}") <(grep "${KEY_2}" "${FILE}" \ 15 | | cut -d'=' -f2 | awk '{$1=$1}1' | tr ' ' '\n' | sort | uniq) ) 16 | 17 | NEW_VALUE_1=$(echo "${VALUE_1}" | tr '\n' ' ') 18 | NEW_VALUE_2=$(echo "${VALUE_2}" | tr '\n' ' ') 19 | 20 | sed -i -e "s/^${KEY_1}=.*/${KEY_1}=${NEW_VALUE_1}/; s/^${KEY_2}=.*/${KEY_2}=${NEW_VALUE_2}/" "${FILE}" 21 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/16 (solution 2).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 16.sh 3 | 4 | [ $# -eq 3 ] || { 5 | echo "Invalid number of arguments. Usage: $0 " 6 | exit 1 7 | } 8 | 9 | FILE_PATH="${1}" 10 | 11 | [ -f "${FILE_PATH}" ] || { echo "File ${FILE_PATH}" does not exist; exit 2; } 12 | 13 | [ -r "${FILE_PATH}" ] || { echo "File ${FILE_PATH}" is not readable; exit 3; } 14 | 15 | [ -w "${FILE_PATH}" ] || { echo "File ${FILE_PATH}" is not writable; exit 4; } 16 | 17 | KEY_1="${2}" 18 | KEY_2="${3}" 19 | 20 | [ -n "${KEY_1}" -a -n "${KEY_2}" ] || { echo "There is a key with zero length"; exit 5; } 21 | 22 | VAL_1=$(fgrep "${KEY_1}=" "${FILE_PATH}" | sed "s/${KEY_1}=//") 23 | VAL_2=$(fgrep "${KEY_2}=" "${FILE_PATH}" | sed "s/${KEY_2}=//") 24 | 25 | # alternative with awk: 26 | # VAL_1="$(fgrep "${KEY_1}=" "${FILE_PATH}" | awk -F'=' '{print $2}')" 27 | # VAL_2="$(fgrep "${KEY_2}=" "${FILE_PATH}" | awk -F'=' '{print $2}')" 28 | 29 | # echo "${VAL_1}" 30 | # echo "${VAL_2}" 31 | 32 | [ -n "${VAL_2}" ] || exit 0 33 | 34 | NEW_VAL="" 35 | 36 | for WORD in ${VAL_2}; do 37 | if fgrep -qv "${WORD}" <(echo "${VAL_1}"); then 38 | NEW_VAL+="${WORD} " 39 | fi 40 | done 41 | 42 | NEV_VAL="$(echo "${NEW_VAL%?}" )" # removing the last space symbol 43 | 44 | sed -i -E "s/${KEY_2}=${VAL_2}/${KEY_2}=${NEW_VAL}/" "${FILE_PATH}" 45 | 46 | exit $? 47 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/17.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 17.sh 3 | 4 | [ $# -eq 1 ] || { echo "Invalid number of arguments. Usage: $0 "; exit 1; } 5 | 6 | FOO="${1}" 7 | 8 | $(id -u "${FOO}" &>/dev/null) || { echo "Invalid username!"; exit 2; } 9 | [ $(id -u) -eq 0 ] || exit 0 10 | 11 | # If we are here, we are sure that script is executed as root. 12 | 13 | PS=$(mktemp) 14 | UNIQUE_USERS=$(mktemp) 15 | 16 | ps -e -o user=,pid=,etimes= | grep -v '^_' | sort -t' ' -k1 > "${PS}" 17 | 18 | FOO_PS_CNT=$( awk -v "foo=${FOO}" '{ if ($1 == foo) ++cnt } END {print cnt}' "${PS}" ) 19 | cat "${PS}" | cut -d ' ' -f 1 | uniq > "${UNIQUE_USERS}" 20 | 21 | 22 | echo "a)" 23 | while read _USER; do 24 | CUR_CNT=$(grep -c "${_USER}" "${PS}") 25 | 26 | if [ -z "${FOO_PS_CNT}" ]; then 27 | FOO_PS_CNT=0 28 | fi 29 | 30 | if [ "${CUR_CNT}" -gt "${FOO_PS_CNT}" ]; then 31 | echo "${_USER}" 32 | fi 33 | 34 | done < "${UNIQUE_USERS}" 35 | echo 36 | 37 | echo "b)" 38 | AVG=$(awk '{total += $3}END{print int(total/NR)}' "${PS}") 39 | echo 40 | 41 | while read PID ETIMES; do 42 | if [ "${ETIMES}" -gt $( echo "${AVG} * 2" | bc ) ]; then 43 | kill -15 PID 44 | sleep 2 45 | kill -9 PID 46 | fi 47 | done < <( fgrep "^${FOO}" "${PS}") 48 | 49 | rm -- "${PS}" 50 | rm -- "${UNIQUE_USERS}" 51 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/18.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 18.sh 3 | 4 | user_home=$(mktemp) 5 | 6 | cat /etc/passwd | cut -d ':' -f 1,6 | tr ':' ' ' > "${user_home}" 7 | 8 | function find_most_recently_modified_regular_file { 9 | find "${1}" -type f ! -name ".*" -printf "%T@ %f\n" 2>/dev/null | sort -n -t' ' -k1 | tail -1 10 | } 11 | 12 | most_recent_for_all_users=$(mktemp) 13 | 14 | while read user home; do 15 | 16 | [ -d "${home}" ] || continue 17 | [ -r "${home}" ] || continue 18 | 19 | cur_file="$(find_most_recently_modified_regular_file "${home}")" 20 | 21 | [ -n "${cur_file}" ] || continue 22 | 23 | echo "${user} ${cur_file}" >> "${most_recent_for_all_users}" 24 | 25 | done < "${user_home}" 26 | 27 | cat "${most_recent_for_all_users}" | sort -n -t' ' -k2 | tail -1 | cut -d' ' -f1,3- 28 | 29 | rm -- "${most_recent_for_all_users}" 30 | rm -- "${user_home}" 31 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/19.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 19.sh 3 | 4 | num="" 5 | 6 | if [ $# -eq 2 ]; then 7 | num="${2}" 8 | elif [ $# -gt 2 ]; then 9 | echo "Invalid number of arguments!" 10 | exit 1 11 | elif [ $# -eq 0 ]; then 12 | echo "Invalid number of arguments!" 13 | exit 2 14 | fi 15 | 16 | dir="${1}" 17 | 18 | if [ ! -d "${dir}" ]; then 19 | echo "Not a valid directory name!" 20 | exit 3 21 | elif [ ! -r "${dir}" ]; then 22 | echo "Directory is not readable!" 23 | exit 4 24 | fi 25 | 26 | function validate_num { 27 | egrep -q '^[0-9]+$' <(echo "${1}") 28 | } 29 | 30 | function count_hardlinks { 31 | find "${1}" -samefile "${2}" 2>/dev/null | wc -l 32 | } 33 | 34 | function is_broken_symlink { 35 | file "${1}" | grep -q 'broken' 36 | } 37 | 38 | if [ -n "${num}" ]; then 39 | if validate_num "${num}" ; then 40 | 41 | while read f; do 42 | if [ $(count_hardlinks "${dir}" "${f}") -ge "${num}" ]; then 43 | echo "${f}" 44 | fi 45 | done < <(find "${dir}" -type f ! -name '.*' 2>/dev/null) 46 | else 47 | echo "Invalid number argument!" 48 | exit 5 49 | fi 50 | else 51 | while read l; do 52 | if is_broken_symlink "${l}"; then 53 | echo "${l}" 54 | fi 55 | done < <(find "${dir}" -type l 2>/dev/null) 56 | fi 57 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/20.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 20.sh 3 | 4 | [ $# -eq 3 ] || { echo "Usage: $0 "; exit 1; } 5 | 6 | src="${1}" 7 | dst="${2}" 8 | str="${3}" 9 | 10 | [ -d "${src}" ] || { echo "Source is not a directory!"; exit 2; } 11 | [ -d "${dst}" ] || { echo "Destination is not a directory!"; exit 3; } 12 | [ -r "${src}" -a -w "${src}" ] || { echo "Source does not have \"r\" or \"w\" perm!"; exit 4; } 13 | [ -r "${dst}" -a -w "${dst}" ] || { echo "Destination does not have \"r\" or \"w\" perm!"; exit 5; } 14 | 15 | #[ $(id -u) -eq 0 ] || { echo "Script not run as root (do nothing)!"; exit 0; } 16 | 17 | dst_content=$( find "${dst}" -type f ! -name ".*" 2>/dev/null | wc -l) 18 | [ "${dst_content}" -eq 0 ] || { echo "Destinarion dir must not have other files!"; exit 6; } 19 | 20 | dir_name="$(dirname "${0}")" 21 | while read file; do 22 | real_dir_base_name="$(echo "${file}" | sed -E "s/${src}\///")" 23 | 24 | mkdir -p "${dst}/$(dirname "${real_dir_base_name}")" 25 | # we use cp instead of mv for better testing 26 | cp -v -- "${file}" "${dst}/${real_dir_base_name}" 27 | done < <(find "${src}" -type f -name "*${str}*" 2>/dev/null) 28 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/21.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 21.sh 3 | 4 | [ $(id -u) -eq 0 ] || { echo "Script $0 not executed as root, nothing done!"; exit 1; } 5 | 6 | for U in $(ps -e -o user= | grep -v "^_" | sort | uniq); do 7 | TOTAL_RSS=0 8 | PS_CNT=0 9 | 10 | while read CPID CRSS; do 11 | PS_CNT=$(expr ${PS_CNT} + 1 ) 12 | TOTAL_RSS=$(expr ${TOTAL_RSS} + ${CRSS}) 13 | MAX_RSS=${CRSS} 14 | MAX_RSS_PID=${CPID} 15 | done < <(ps -u "${U}" -o pid=,rss= | sort -n -k 2) 16 | 17 | if [ ${PS_CNT} -eq 0 ]; then 18 | continue 19 | fi 20 | 21 | AVG_RSS=$(expr ${TOTAL_RSS} '/' ${PS_CNT}) 22 | echo "${U} ${PS_CNT} ${TOTAL_RSS}" 23 | 24 | if [ ${MAX_RSS} -gt $(expr ${AVG_RSS} '*' 2) ]; then 25 | echo "killing process ${MAX_RSS_PID}" 26 | kill -s SIGTERM ${MAX_RSS_PID} 27 | sleep 2 28 | kill -s SIGKILL ${MAX_RSS_PID} 29 | fi 30 | done 31 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/22.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 22.sh 3 | 4 | if [ $# -eq 0 ] || [ $# -gt 2 ]; then 5 | echo "Invalid number of arguments!" 6 | echo "Usage: [ ]" 7 | exit 1 8 | fi 9 | 10 | dir="${1}" 11 | file="" 12 | 13 | if [ $# -eq 2 ]; then 14 | file="${2}" 15 | if [ ! -f "${file}" ]; then 16 | echo "Invalid file!" 17 | exit 2 18 | elif [ ! -w "${file}" ]; then 19 | echo "File is not writable!" 20 | exit 3 21 | fi 22 | fi 23 | 24 | if [ ! -d "${dir}" ]; then 25 | echo "Invalid directory!" 26 | exit 4; 27 | elif [ ! -r "${dir}" ]; then 28 | echo "Directory is not readable!" 29 | exit 5; 30 | fi 31 | 32 | cnt=0 33 | 34 | while read symlink; do 35 | if fgrep -q "broken sym" <(echo "${symlink}"); then 36 | cnt=$(expr $cnt '+' 1) 37 | else 38 | if [ -n "${file}" ]; then 39 | # macOS 40 | # stat -f "%N%SY" "$(echo "${symlink}" | cut -d':' -f1)" >> "${file}" 41 | stat -c "%N" "$(echo "${symlink}" | cut -d':' -f1)" | tr -d "\'" >> "${file}" 42 | else 43 | # macOS 44 | # stat -f "%N%SY" "$(echo "${symlink}" | cut -d':' -f1)" 45 | stat -c "%N" "$(echo "${symlink}" | cut -d':' -f1)" | tr -d "\'" 46 | fi 47 | fi 48 | done < <(find "${dir}" -type l 2>/dev/null -exec file {} \;) 49 | 50 | if [ -n "${file}" ]; then 51 | cat "${file}" 52 | fi 53 | 54 | echo "Broken symlinks: ${cnt}" 55 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/23 (multiple fields sort).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 23.sh 2nd sol 3 | 4 | [ $# -eq 2 ] || { echo "Usage: ${0} "; exit 1; } 5 | 6 | dir="$1" 7 | str="$2" 8 | 9 | if [ ! -d "${dir}" ]; then 10 | echo "Invalid directory!" 11 | exit 2 12 | elif [ ! -r "${dir}" ]; then 13 | echo "Directory is not readable!" 14 | exit 3 15 | fi 16 | 17 | [ -n "${str}" ] || { echo "empty string"; exit 4; } 18 | 19 | temp=$(mktemp) 20 | gfind "${dir}" -maxdepth 1 -type f -printf "%f\n" 2>/dev/null \ 21 | | egrep "^vmlinuz-[0-9]+\.[0-9]+\.[0-9]+-${str}$" > "${temp}" 22 | 23 | searched="$(cat "${temp}" | cut -d'-' -f2 | sort -t'.' -n -k 1,1 -k 2,2 -k 3,3 | tail -1)" 24 | 25 | fgrep "${searched}" "${temp}" 26 | 27 | rm -- "${temp}" 28 | 29 | exit 0 30 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/23 (version sort).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 23.sh 1st sol 3 | 4 | [ $# -eq 2 ] || { echo "Invalid number of arguments!"; exit 1; } 5 | 6 | dir="${1}" 7 | str="${2}" 8 | 9 | if [ ! -d "${dir}" ]; then 10 | echo "Invalid directory!" 11 | exit 2 12 | elif [ ! -r "${dir}" ]; then 13 | echo "Directory is not readable!" 14 | exit 3 15 | fi 16 | 17 | if [ -z "${str}" ]; then 18 | echo "Empty string!" 19 | exit 4 20 | fi 21 | 22 | grep -E "^vmlinuz-[0-9]+\.[0-9]+\.[0-9]+-${str}$" <(find "${dir}" -maxdepth 1 -type f 2>/dev/null \ 23 | -exec basename {} \;) \ 24 | | sort -V -t'-' -k2 | tail -n 1 25 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/24.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 24.sh 3 | 4 | [ $# -eq 0 ] || { echo "Invalid number of arguments. Usage: $0"; exit 1; } 5 | 6 | #[ $(id -u) -eq 0 ] || { echo "Script ${0} is not executed as root."; exit 1; } 7 | 8 | TOTAL_ROOT_RSS="$(ps -u "root" -o rss= | awk '{s+=$1}END{print s}')" 9 | 10 | while read USER_UID _HOME; do 11 | 12 | [ "${USER_UID}" -ne 0 ] || continue 13 | 14 | [ ! -d "${_HOME}" ] || [ "$(stat -c "%u" "${_HOME}")" != "${USER_UID}" ] || [ "$(stat -c "%A" "${_HOME}"| cut -c3)" != "w" ] || continue 15 | 16 | # echo "${USER_UID} ${_HOME}" 17 | 18 | TOTAL_USER_RSS="$(ps -u "${USER_UID}" -o rss= | awk '{s+=$1}END{print s}')" 19 | 20 | [ -n "${TOTAL_USER_RSS}" ] || TOTAL_USER_RSS=0 21 | 22 | if [ "${TOTAL_ROOT_RSS}" -gt "${TOTAL_USER_RSS}" ]; then 23 | killall -u "${USER_UID}" -m . 24 | sleep 2 25 | killall -u "${USER_UID}" -KILL -m . 26 | fi 27 | 28 | done < <(cut -d':' -f3,6 /etc/passwd) 29 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/25.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 25.sh 3 | 4 | [ $# -eq 1 ] || { echo "Usage: ${0} "; exit 1; } 5 | 6 | LOGDIR="${1}" 7 | 8 | if [ ! -d "${LOGDIR}" ];then 9 | echo "Invalid directory name" 10 | exit 2 11 | elif [ ! -r "${LOGDIR}" ]; then 12 | echo "Directory not readable" 13 | exit 3 14 | fi 15 | 16 | RECORDS=$(mktemp) 17 | 18 | while read FRIEND; do 19 | 20 | LINES="$(find "${LOGDIR}" -mindepth 4 -maxdepth 4 -type f \ 21 | | fgrep "$FRIEND" \ 22 | | xargs -I {} wc -l {} \ 23 | | awk '{print $1}' \ 24 | | awk '{sum += $1}END{print sum}')" 25 | 26 | echo "$LINES $FRIEND" >> "${RECORDS}" 27 | 28 | done < <(gfind "${LOGDIR}" -mindepth 3 -maxdepth 3 -type d \ 29 | | cut -d '/' -f 4 | sort | uniq) 30 | 31 | cat "${RECORDS}" | sort -rn -k1 | head -n 3 32 | 33 | rm -- "${RECORDS}" 34 | 35 | exit 0 36 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/26.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 26.sh 3 | 4 | [ $# -eq 2 ] || { echo "Usage: ${0} "; exit 1; } 5 | 6 | STENOGRAPH="${1}" 7 | DIR="${2}" 8 | 9 | if [ ! -f "${STENOGRAPH}" ]; then 10 | echo "Invalid file name" 11 | exit 2 12 | elif [ ! -r "${STENOGRAPH}" ]; then 13 | echo "File not readable" 14 | exit 3 15 | fi 16 | 17 | if [ ! -d "${DIR}" ]; then 18 | echo "Invalid directory name" 19 | exit 4 20 | elif [ ! -w "${DIR}" ]; then 21 | echo "Directory is not readable" 22 | exit 5 23 | fi 24 | 25 | [ "$(find "${DIR}" -mindepth 1 | wc -l)" -eq 0 ] || { echo "Dir is not empty"; exit 6; } 26 | 27 | CNT=1 28 | 29 | touch "${DIR}/dict.txt" 30 | 31 | while read LINE; do 32 | NAME_FAMILY="$(cut -d':' -f1 < <(echo "${LINE}") | sed -E "s/\(.*\)//" | awk '$1=$1')" 33 | NUMBER="$(cat "${DIR}/dict.txt" | fgrep "${NAME_FAMILY}" | cut -d';' -f2 )" 34 | 35 | if [ -z "$NUMBER" ]; then 36 | # number does not exist -> add to dict.txt 37 | echo "${NAME_FAMILY};${CNT}" >> "${DIR}/dict.txt" 38 | NUMBER="${CNT}" 39 | CNT=$( expr "${CNT}" + 1 ) 40 | fi 41 | echo "${LINE}" | cut -d':' -f2 >> "${DIR}/${NUMBER}.txt" 42 | done < "${STENOGRAPH}" 43 | 44 | exit 0 45 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/27 (input order).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 27.sh 2nd sol 3 | 4 | [ $# -eq 2 ] || { echo "Usage: ${0} "; exit 1; } 5 | 6 | a="${1}" 7 | b="${2}" 8 | 9 | if [ ! -f "${a}" ] ;then 10 | echo "Invalid file" 11 | exit 2 12 | elif [ ! -r "${a}" ]; then 13 | echo "File not readable" 14 | exit 3; 15 | fi 16 | 17 | ( [ -e "${b}" ] || touch "${b}" ) && [ ! -w "${b}" ] && echo cannto write to file ${b} && exit 1 18 | 19 | result=$(mktemp) 20 | 21 | while read LINE; do 22 | # exists in b.csv or it has to be added 23 | CUTLINE="$( echo "$LINE" | cut -d',' -f2- )" 24 | if egrep -q ",${CUTLINE}$" "${result}" ; then 25 | continue; 26 | else # add 27 | echo "${LINE}" >> "${result}" 28 | fi 29 | 30 | done < <( cat "${a}" | sort -t',' -nk1) 31 | # now result contains what we want to include 32 | 33 | while read LINE; do 34 | if cat "${result}" | egrep -q "^${LINE}$"; then 35 | echo "${LINE}" >> "${b}" 36 | fi 37 | done < "${a}" 38 | 39 | rm -- "${result}" 40 | 41 | exit 0 42 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/27 (sorted).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 27.sh 1st sol 3 | 4 | [ $# -eq 2 ] || { echo "Usage: ${0} "; exit 1; } 5 | 6 | a="${1}" 7 | b="${2}" 8 | 9 | if [ ! -f "${a}" ] ;then 10 | echo "Invalid file" 11 | exit 2 12 | elif [ ! -r "${a}" ]; then 13 | echo "File not readable" 14 | exit 3; 15 | fi 16 | 17 | ( [ -e "${b}" ] || touch "${b}" ) && [ ! -w "${b}" ] && echo cannto write to file ${b} && exit 1 18 | 19 | while read LINE; do 20 | # exists in b.csv or it has to be added 21 | CUTLINE="$( echo "$LINE" | cut -d',' -f2- )" 22 | if egrep -q ",${CUTLINE}$" "${b}" ; then 23 | continue; 24 | else # add 25 | echo "${LINE}" >> "${b}" 26 | fi 27 | 28 | done < <( cat "${a}" | sort -t',' -nk1) 29 | 30 | exit 0 31 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/28 (A) cycle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 28.sh A) cycle 3 | 4 | TEMP=$(mktemp) 5 | 6 | cat | egrep "^[-+]?[0-9]+$" | sort -n > "${TEMP}" 7 | 8 | [ "$(awk 'END{print NR}' "${TEMP}")" -ne 0 ] || { echo -n "\nno valid numbers"; exit 1; } 9 | 10 | MAX="$(tail -1 "${TEMP}")" 11 | MIN="$(head -1 "${TEMP}")" 12 | 13 | if [ "${MAX}" -eq "${MIN}" ];then 14 | echo -e "\n${MAX}" 15 | else 16 | ABS_MIN="$(sed -E "s/-//" <(echo "${MIN}"))" 17 | ABS_MAX="$(sed -E "s/-//" <(echo "${MAX}"))" 18 | if [ "${ABS_MIN}" -eq "${ABS_MAX}" ];then 19 | echo -e "\n${MIN}" 20 | echo "${MAX}" 21 | elif [ "${ABS_MIN}" -lt "${ABS_MAX}" ]; then 22 | echo -e "${MAX}" 23 | else 24 | echo -e "\n${MIN}" 25 | fi 26 | fi 27 | 28 | rm -- "${TEMP}" 29 | 30 | exit 0 31 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/28 (B) extract last digit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 28.sh B) extract last digit 3 | 4 | temp=$(mktemp) 5 | data=$(mktemp) 6 | 7 | cat | egrep "^[-+]?[0-9]+$" | sort -n > "${temp}" 8 | 9 | [ "$(cat "$temp" | wc -l )" -ne 0 ] || { echo -n "\nno valid numbers"; exit 1; } 10 | 11 | while read NUM; do 12 | SUM=0 13 | NUM_COPY="$NUM" 14 | NUM="$( echo $NUM | sed -E "s/-//" )" 15 | while [ "$NUM" -ne 0 ]; do 16 | REM=$(expr $NUM % 10 ) 17 | SUM=$( expr $SUM + $REM ) 18 | NUM=$( expr $NUM / 10 ) 19 | done 20 | 21 | echo "${NUM_COPY} ${SUM}" >> "${data}" 22 | 23 | done < <(cat "${temp}") 24 | 25 | uniq -c "${data}" | awk '{$1=$1}1' | grep '^1' | cut -d' ' -f2,3 > "${temp}" 26 | #cat "${temp}" 27 | largest_sum_digits_and_unique=$(cat "${temp}" | sort -t' ' -k2 | tail -1 | cut -d' ' -f2) 28 | 29 | RES=$(cat "${temp}" | grep "${largest_sum_digits_and_unique}$" | sort -t' ' -k1 | tail -1 | cut -d' ' -f1) 30 | 31 | echo -e "\n${RES}" 32 | 33 | rm -- "${temp}" 34 | rm -- "${data}" 35 | 36 | exit 0 37 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/28 (B) smart sed + bc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 28.sh B) smart sed + bc 3 | 4 | TEMP=$(mktemp) 5 | DATA=$(mktemp) 6 | 7 | cat | egrep "^[-+]?[0-9]+$" | sort -n > "${TEMP}" 8 | 9 | [ "$(cat "${TEMP}" | wc -l )" -ne 0 ] || { echo -n "\nno valid numbers"; exit 1; } 10 | 11 | while read NUM; do 12 | # n=123 -> 1+2+3+ -> 1+2+3 -> 6 13 | SUM_DIGITS= $(echo ${n} | sed -E 's/(.)/\1+/g' | sed 's/.$//' | bc) 14 | echo "${NUM} ${SUM_DIGITS}" >> "${DATA}" 15 | done < <(cat "${TEMP}") 16 | 17 | uniq -c "${DATA}" | awk '{$1=$1}1' | grep '^1' | cut -d' ' -f2,3 > "${TEMP}" 18 | #cat "${TEMP}" 19 | LARGEST_SUM_DIGITS_AND_UNIQUE=$(cat "${TEMP}" | sort -t' ' -k2 | tail -1 | cut -d' ' -f2) 20 | 21 | RES=$(cat "${TEMP}" | grep "${LARGEST_SUM_DIGITS_AND_UNIQUE}$" | sort -t' ' -k1 | tail -1 | cut -d' ' -f1) 22 | 23 | echo -e "\n${RES}" 24 | 25 | rm -- "${TEMP}" 26 | rm -- "${DATA}" 27 | 28 | exit 0 29 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Test 2 Preparation/29.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 29.sh 3 | 4 | [ $# -ne 0 ] || { echo "Usage: ${0} [-n N] FILE1..."; exit 1; } 5 | 6 | N=10 7 | CUR_ARG=1 8 | 9 | if [ "${1}" = "-n" ] && [ $# -gt 2 ]; then 10 | N="${2}" 11 | CUR_ARG=3 12 | fi 13 | 14 | ALL_ARG="$#" 15 | 16 | buf=$(mktemp) 17 | 18 | while [ $CUR_ARG -le $ALL_ARG ];do 19 | 20 | CUR_FILE="${!CUR_ARG}" 21 | if [ -f ${CUR_FILE} ] && [ -r ${CUR_FILE} ]; then 22 | cat "$CUR_FILE" | tail -n $N | sed -E "s/([^ ]+ [^ ]+ )(.*)/\1$CUR_FILE \2/" >> "$buf" 23 | fi 24 | CUR_ARG=$(expr $CUR_ARG + 1) 25 | done 26 | 27 | new_buf=$(mktemp) 28 | 29 | cat "$buf" | sort 30 | 31 | rm -- "${buf}" 32 | 33 | exit 0 34 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Text Processing/01 Text Processing - Exam Problems.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/1 – FMI Tasks/Text Processing/01 Text Processing - Exam Problems.pdf -------------------------------------------------------------------------------- /1 – FMI Tasks/Text Processing/E 01 Task 01.md: -------------------------------------------------------------------------------- 1 | **Задаза 1.** Даден е текстов файл с име philip-j-fry.txt. Напишегте shell script и/или серия от команди, които извеждат броя редове, съдържащи поне една четна цифра и несъдържщи малка латинска буква от a до w. 2 | 3 | Примерно съдържание на файла: 4 | ``` 5 | 123abv123 6 | 123zz123 7 | MMU_2.4 8 | ``` 9 | 10 | Примерен изход: 11 | 12 | ``` 13 | 2 14 | ``` 15 | 16 | **Решение:** 17 | 18 | Първи начин: 19 | 20 | ```sh 21 | awk '$0~/[02468]/ && $0~/[a-w]/ {print}' philip-j-fry.txt | wc -l 22 | ``` 23 | 24 | Втори назичин: 25 | 26 | ```sh 27 | grep '[02468]' philip-j-fry.txt | grep -vc '[a-w]' 28 | ``` 29 | 30 | Трети начин: 31 | 32 | ```sh 33 | sed -n '/[02468]/ p' philip-j-fry.txt | sed -n '/[a-w]/ !p' | wc -l 34 | ``` 35 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Text Processing/E 01 Task 02.md: -------------------------------------------------------------------------------- 1 | **Задача 2.** Имате текстов файл със следното съдържание (всяка книга е на един ред): 2 | 3 | ``` 4 | 1979 г. - „Синият тайфун“ (сборник съветски научнофантастични разкази за морето) 5 | 1979 г. - „Двойната задача“ - Любен Дилов 6 | 1979 г. - „Завръщане от звездите“ - Станислав Лем (Превод: Веселин Маринов) 7 | 1979 г. - „Среща с Рама“ - Артър Кларк (Превод: Александър Бояджиев) 8 | 1979 г. - „Алиби“ - Димитър Пеев (криминален роман) 9 | 1979 г. - „Тайнственоят триъгълник“ (сборник НФ разкази за морето) 10 | 1979 г. - „Второ нашествие на марсианците“ - Аркадий и Борис Стругацки 11 | 1979 г. - „Гробищен сват“ - Клифърд Саймък (Превод: Михаил Грънчаров) 12 | 1979 г. - „Чоки“ - Джон Уиндъм (Превод: Теодора Давидова) 13 | 1980 г. - „Допълнителна примамка“ - Робърт Ф. Йънг (Превод: Искра Иванова, ...) 14 | 1980 г. - „Кристално яйце“ - Хърбърт Уелс (Превод: Борис Миндов, ...) 15 | 1980 г. - „Онирофилм“ (сборник италиански НФ разкази) (Превод: Никола Иванов, ...) 16 | ``` 17 | Напишете shell script (приемащ аргумент име на файл) и серия от команди които извеждат: 18 | - всеки ред на файла с добавен пореден номер във формат "1. ", "2. ", ... , "11. ", ... 19 | - махат данните за годината на издаване 20 | - сортират изхода по заглавие (лексикографски, възходящо) 21 | 22 | Примерен изход (показани са само първите 4 реда): 23 | 24 | ``` 25 | 5. „Алиби“ - Димитър Пеев (криминален роман) 26 | 7. „Второ нашествие на марсианците“ - Аркадий и Борис Стругацки 27 | 8. „Гробищен сват“ - Клифърд Саймък (Превод: Михаил Грънчаров) 28 | 2. „Двойната задача“ - Любен Дилов 29 | ``` 30 | **Решение:** 31 | 32 | Първи начин: 33 | 34 | ```sh 35 | awk '{print NR".",$1=$2=$3="",$0}' books.txt | awk '{$1=$1}1' | sort -t' ' -k2 36 | ``` 37 | 38 | Втори начин: 39 | ```sh 40 | nl -n rn -s'. ' books.txt | awk '{$2=$3=$4=""}1' | tr -s ' ' | sort -t' ' -k2 41 | ``` 42 | 43 | Трети начин: 44 | 45 | ```sh 46 | cut -d' ' -f4- books.txt | awk '{print NR". ",$0}' | sort -t' ' -k2 47 | ``` 48 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Text Processing/E 01 Task 04.md: -------------------------------------------------------------------------------- 1 | **Задача 4.** Файловете във вашата home директория съдържат информация за музикални албуми и имат специфична структура. Началото на всеки ред е годината на издаване на албума, а непосредствено, след началото на всеки ред следва името на изпълнителя на песента. Имената на файловете се състоят от една дума, която съвпада с името на изпълнителя. 2 | 3 | Примерно съдържание на файл с име "Bonnie": 4 | 5 | ``` 6 | 2005г. Bonnie - "God Was in the Water" (Randall Bramblett, Davis Causey) - 5:17 7 | 2005г. Bonnie - "Love on One Condition" (Jon Cleary) - 3:43 8 | 2005г. Bonnie - "So Close" (Tony Arata, George Marinelli, Pete Wasner) - 3:22 9 | 2005г. Bonnie - "Trinkets" (Emory Joseph) - 5:02 10 | 2005г. Bonnie - "Crooked Crown" (David Batteau, Maia Sharp) - 3:49 11 | 2005г. Bonnie - "Unnecessarily Mercenary" (Jon Cleary) - 3:51 12 | 2005г. Bonnie - "I Will Not Be Broken" - "Deep Water" (John Capek, Marc Jordan) - 3:58 13 | ``` 14 | 15 | Да се състави процедура на bash приемаща два параметъра, които са имена на файлове от вашата home директория. Скриптът сравнява, кой от двата файла има повече на брой редове, съдържащи неговото име (на файла). За файлът победител изпълнете следните действия: 16 | - извлечете съдържанието му, без годината на издаване на албума и без името на изпълнителя; 17 | - сортирайте лексикографски извлеченото съдържание и го запишете във файл с име 'изпълнител.songs' 18 | 19 | Примерен изходен файл (с името Bonnie.songs): 20 | 21 | ``` 22 | "Crooked Crown" (David Batteau, Maia Sharp) - 3:49 23 | "God Was in the Water" (Randall Bramblett, Davis Causey) - 5:17 24 | "I Will Not Be Broken" - "Deep Water" (John Capek, Marc Jordan) - 3:58 25 | "Love on One Condition" (Jon Cleary) - 3:43 26 | "So Close" (Tony Arata, George Marinelli, Pete Wasner) - 3:22 27 | "Trinkets" (Emory Joseph) - 5:02 28 | "Unnecessarily Mercenary" (Jon Cleary) - 3:51 29 | ``` 30 | 31 | **Решение:** 32 | 33 | ```sh 34 | cat "$(awk 'BEGIN{cnt1='"$(wc -l < Bonnie)"'; cnt2='"$(wc -l < LP)"'} END{if (cnt1 > cnt2)\ 35 | {print "Bonnie"} else {print "LP"}}')" | cut -d ' ' -f4- | sort -t '"' | cat > Bonnie.songs 36 | ``` 37 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Text Processing/E 01 Task 07.md: -------------------------------------------------------------------------------- 1 | **Задача 7.** Напишете серия от команди, които да вземат от файла /etc/passwd под-низ, състоящ се от втора и трета цифра на факултетния номер на студентите от специалност Информатика, чиито фамилии завършват на "а". Изведете коя комбинация от цифри се среща най-често и коя е тя. 2 | 3 | *Примерно съдържание на файла:* 4 | 5 | ``` 6 | с45194:x:1255:502:Elizabet Mihaylova, Inf, k3, g1:/home/Inf/s45194:/bin/bash 7 | s45139:x:1261:502:Vasilena Peycheva:/home/Inf/s45139:/bin/bash 8 | s81257:x:1079:503:Vasilena Nikolova, KN, 2kurs, 5gr:/home/KN/s81257:/bin/bash 9 | s81374:x:1117:502:Ivan Kamburov, KN, 2kurs, 7 gr:/home/KN/s81374:/bin/bash 10 | kiril:x:508:500:Kiril Varadinov:/home/kiril:/bin/bash 11 | s61812:x:1128:504:Vladimir Genchev:/home/SI/s61812:/bin/bash 12 | user:x:1000:99:Inactive user just to start UID from 1000:/home/user:/sbin/nologin 13 | s81254:x:1077:503:Mariela Tihova, KN, 2kurs, 5gr:/home/KN/s81254:/bin/bash 14 | s81386:x:1121:503:Daniela Ruseva, KN, 2kurs, 7gr:/home/KN/s81386:/bin/bash 15 | s45216:x:1235:502:Aleksandar Yavashev, Inf, k3, g3:/home/Inf/s45216:/bin/bash 16 | ``` 17 | 18 | *Примерен изход:* 19 | 20 | ``` 21 | 2 51 22 | ``` 23 | 24 | **Решение:** 25 | 26 | 27 | Първи начин: 28 | 29 | ```sh 30 | grep '\/Inf\/' /etc/passwd |\ 31 | grep -E '[[:upper:]][[:lower:]]* [[:upper:]][[:lower:]]*a(,|:)' |\ 32 | cut -c3,4 | uniq -c | sort -rn' 33 | ``` 34 | 35 | Втори начин: 36 | 37 | ```sh 38 | cat /etc/passwd | fgrep '/Inf/' | cut -d':' -f 1-5 | cut -d',' -f1 | egrep "a$" |\ 39 | cut -d':' -f1 | cut -c 2- | cut -c 2-3 | sort | uniq -c | sort -n | tail -n 1 40 | ``` 41 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Text Processing/E 01 Task 10.md: -------------------------------------------------------------------------------- 1 | **Задача 10.** При подреждане в нарастващ ред на числовите потребителски идентификатори (UID) на акаунтите, дефинирани в системата, 201-ят акаунт е от групата, запазена за акаунти от специалност СИ. 2 | 3 | Изведете списък с имената (име и фамилия) и home директориите на всички акаунти от специалност СИ, подреден по факултетен номер. 4 | 5 | *За справка:* 6 | 7 | ``` 8 | s61988:x:1219:504:Stoian Genchev,SI,2,5:/home/SI/s61988:/bin/bash 9 | s81430:x:1234:503:Iordan Petkov, KN, k2, g7:/home/KN/s81430:/bin/bash 10 | s61807:x:1248:504:Elica Venchova:/home/SI/s61807:/bin/bash 11 | s62009:x:1254:504:Denitsa Dobreva, 2, 6:/home/SI/s62009:/bin/bash 12 | s61756:x:1258:504:Katrin Kartuleva, SI, 4, 1:/home/SI/s61756:/bin/bash 13 | s855287:x:1195:504:Vaska Kichukova,SI,2,5:/home/SI/s855287:/bin/bash 14 | ``` 15 | 16 | *Примерен изход:* 17 | 18 | ``` 19 | Katrin Kartuleva /home/SI/s61756 20 | Elica Venchova /home/SI/s61807 21 | Stoian Genchev /home/SI/s61988 22 | Denitsa Dobreva /home/SI/s62009 23 | Vaska Kichukova /home/SI/s855287 24 | ``` 25 | 26 | **Решение:** 27 | 28 | ```sh 29 | sed -n '201,$p' f4 | awk 'BEGIN{FS="[,:]"} $0~/\/SI\// {print $1,$5,$(NF-1)}' |\ 30 | cut -c2- | sort -t' ' -k1 | cut -d' ' -f2- | sed 's/ /:/2' 31 | ``` 32 | 33 | *За тестване може да сложим в sed командата вместо 201 -> 1* 34 | -------------------------------------------------------------------------------- /1 – FMI Tasks/Text Processing/E 01 Task 11.md: -------------------------------------------------------------------------------- 1 | **Задача 11.** Вие сте асистент по ОС. На първото упражнение казвате на студентите да си напишат данните на лист, взимате го и им правите акаунти. След упражнението обаче, забравяте да вземете листа със себе си - сещате се половин час по-късно, когато трябва да въведете имената на студентите в таблица, но за зла беда в стаята вече няма ни помен от листа (вероятно иззет от спешния отряд на GDPR-полицията) 2 | 3 | Сещате се, че в началото на упражнението UNIX-часовниът е показвал 155116800, а в края 1551176100. 4 | 5 | Напишете команда, която изкарва с таб факултетните номера и имената на потребителите от специалност СИ, чиито home директории са променили статуса си (status change time) в зададения времеви интервал. 6 | 7 | Приемете, че всички потребители от СИ имат home директории под /home/SI. 8 | 9 | *Примерен изход:* 10 | 11 | ``` 12 | 62198 Ivaylo Georgiev 13 | 62126 Victoria Georgieva 14 | 62009 Denitsa DObreva 15 | 62208 Trayana Nedelcheva 16 | ``` 17 | 18 | *Няколко реда от /etc/passwd за справка:* 19 | 20 | ``` 21 | s62136:x:1302:503:Alexander Ignatow, SI, 2, 2:/home/KN/s62136:/bin/bash 22 | s62171:x:1031:504:Deivid Metanov:/home/SI/s62171:/bin/bash 23 | s62126:x:1016:504:Victoria Georgieva:/home/SI/s62126:/bin/bash 24 | s62009:x:1170:504:Denitsa DObreva,SI,3,3:/home/SI/s62009:/bin/bash 25 | s62196:x:1221:504:Elena Tuparova,SI,2,1:/home/SI/s62196:/bin/bash 26 | ``` 27 | 28 | 29 | **Решение:** 30 | 31 | Първи начин: 32 | 33 | ```sh 34 | find /home/SI -maxdepth 1 -type d - newerct '@1551168000' -not -newerct '@1551176100' \ 35 | -exec grep -F :{}: /etc/passwd \; | cut -d':' -f1,5 | cut -c2- | cut -d',' -f1 | tr ':' '\t' 36 | ``` 37 | 38 | Втори начин: 39 | 40 | ```sh 41 | find /home/SI -maxdepth 1 -type d -printf "%C@ %p\n" |\ 42 | awk '$1 > 1551168000 && $1 < 1551176100 {for(i=2;i $y)); 6 | then 7 | echo X is greater than Y; 8 | elif (($x < $y)); 9 | then 10 | echo X is less than Y; 11 | else 12 | echo X is equal to Y; 13 | fi 14 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Comparing Numbers (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | read X 4 | read Y 5 | if [ "$X" -gt "$Y" ]; then 6 | echo "X is greater than Y" 7 | elif [ "$X" -lt "$Y" ]; then 8 | echo "X is less than Y" 9 | elif [ "$X" -eq "$Y" ]; then 10 | echo "X is equal to Y" 11 | fi 12 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Compute the Average.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | read n 4 | arr=($(cat)) 5 | arr=${arr[*]} 6 | printf "%.3f" $(echo $((${arr// /+}))/$n | bc -l) 7 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Getting started with conditionals (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | read char 4 | echo -e 'YES\nNO\n' | grep -i $char 5 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Getting started with conditionals (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | read char 4 | if [ $char == 'Y' -o $char == 'y' ] 5 | then 6 | echo 'YES' 7 | else 8 | echo 'NO' 9 | fi 10 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Let's Echo.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | echo HELLO 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Looping and Skipping (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | for num in {1..99..2} 4 | do 5 | echo $num 6 | done 7 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Looping and Skipping (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | seq 1 2 99 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Looping and Skipping (Sol. 3).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | for ((i=1; i<100; i=i+2)) 4 | do 5 | echo $i 6 | done 7 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Looping and Skipping (Sol. 4).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | num=1 4 | while [ $num -le 99 ] 5 | do 6 | echo $num 7 | num=$((num+2)) 8 | done 9 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Looping with Numbers (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | for num in {1..50} 4 | do 5 | echo $num 6 | done 7 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Looping with Numbers (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | seq 1 50 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Looping with Numbers (Sol. 3).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | for ((i=1; i<=50; i=i+1)) 4 | do 5 | echo $i 6 | done 7 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/Looping with Numbers (Sol. 4).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | num=1 4 | while [ $num -le 50 ] 5 | do 6 | echo $num 7 | num=$((num+1)) 8 | done 9 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/More on Conditionals.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | read a 4 | read b 5 | read c 6 | 7 | if [[ $a == $b && $b == $c ]] 8 | then 9 | echo 'EQUILATERAL' 10 | elif [[ $a == $b || $b == $c || $a == $c ]] 11 | then 12 | echo 'ISOSCELES' 13 | else 14 | echo 'SCALENE' 15 | fi 16 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/The World of Numbers (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | read x 4 | read y 5 | printf "%s\n" $x{+,-,*,/}"($y)" | bc 6 | -------------------------------------------------------------------------------- /4 – Linux Shell/Bash/The World of Numbers (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | read x 4 | read y 5 | for i in {+,-,"*",/} 6 | do 7 | var=$(((x)$i(y))) 8 | echo $var 9 | done 10 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Awk' Command #1 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | awk '{if(length($4)==0) print "Not all scores are available for",$1;}' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Awk' Command #1 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | awk '{if(NF < 4) print "Not all scores are available for",$1;}' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Awk' Command #2 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | awk '{ 4 | if($2 < 50 || $3 < 50 || $4 < 50) 5 | print $1,":","Fail"; 6 | else 7 | print $1,":","Pass"; 8 | }' 9 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Awk' Command #2 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | awk '{print $1,":",($2<50||$3<50||$4<50) ? "Fail" : "Pass"}' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Awk' Command #3 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | awk '{ 4 | average = ($2 + $3 + $4) / 3 5 | if (average >= 80) { 6 | grade = "A" 7 | } else if (average >= 60) { 8 | grade = "B" 9 | } else if (average >= 50) { 10 | grade = "C" 11 | } else { 12 | grade = "FAIL" 13 | } 14 | print $0, ":", grade 15 | }' 16 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Awk' Command #3 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | awk '{ 4 | s=($2+$3+$4)/3; 5 | print $0,":",(s>=80?"A":(s>=60?"B":(s>=50?"C":"FAIL"))) 6 | }' 7 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Awk' Command #4 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | awk '{ 4 | average = ($2 + $3 + $4) / 3 5 | if (average >= 80) { 6 | grade = "A" 7 | } else if (average >= 60) { 8 | grade = "B" 9 | } else if (average >= 50) { 10 | grade = "C" 11 | } else { 12 | grade = "FAIL" 13 | } 14 | print $0, ":", grade 15 | }' 16 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Awk' Command #4 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | awk '{ 4 | s=($2+$3+$4)/3; 5 | print $0,":",(s>=80?"A":(s>=60?"B":(s>=50?"C":"FAIL"))) 6 | }' 7 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Grep' #1 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | grep -w 'the' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Grep' #1 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | grep ' the ' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Grep' #2.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | grep -iw 'the' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Grep' #3.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | grep -ivw 'that' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Grep' A (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | grep -iwE 'th(e|at|en|ose)' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Grep' A (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | egrep -iw 'th(e|at|en|ose)' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Grep' B (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | !/bin/bash 2 | 3 | grep '\([0-9]\) \?\1' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Grep' B (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | grep '\([0-9]\) *\1' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #1 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed -e 's/\bthe\b/this/' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #1 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed -e 's/\/this/' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #2.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed 's/\bthy\b/your/gi' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #3 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed 's/thy/{&}/gi' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #3 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed 's/[tT][hH][yY]/{&}/g' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #3 (Sol. 3).sh: -------------------------------------------------------------------------------- 1 | # github.com/andy489 2 | 3 | sed 's/\(thy\)/{\1}/gi' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #4 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed -E 's/[0-9]{4} /**** /g' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #4 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed -E 's/^.{14}/**** **** ****/' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #5 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed 's/\([[:digit:]]\{4\}\) \([[:digit:]]\{4\}\) \([[:digit:]]\{4\}\) \([[:digit:]]\{4\}\)/\4 \3 \2 \1/' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Sed' Command #5 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sed -r 's/([0-9]{4}) ([0-9]{4}) ([0-9]{4}) ([0-9]{4})/\4 \3 \2 \1/' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Tr' Command #1 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tr '(' '[' | tr ')' ']' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Tr' Command #1 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tr "()" "[]" 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Tr' Command #2.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tr -d [:lower:] 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Tr' Command #3 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tr -s ' ' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Tr' Command #3 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tr -d a-z 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Tr' Command #3 (Sol. 3).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tr -d a-z 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Tr' Command #3 (Sol. 4).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tr -d [a-z] 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Uniq' Command #1.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | uniq 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Uniq' Command #2 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | uniq -c | cut -c7- 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Uniq' Command #2 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | uniq -c | cut -d ' ' -f7- 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Uniq' Command #3 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | uniq -ic | cut -c7- 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Uniq' Command #3 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | uniq -ic | cut -d ' ' -f7- 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/'Uniq' Command #4.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | uniq -u 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #1.sh: -------------------------------------------------------------------------------- 1 | # github.com/andy489 2 | 3 | cut -c 3 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #2.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -c 2,7 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #3.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -c 2-7 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #4 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -c 1-4 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #4 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -c -4 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #5 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | cut -f 1-3 3 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #5 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -f -3 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #6.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -c 13- 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #7.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -d ' ' -f 4 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #8.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -d' ' -f-3 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Cut #9.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | cut -f2- 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Head of a Text File #1.sh: -------------------------------------------------------------------------------- 1 | # github.com/andy489 2 | 3 | head -20 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Head of a Text File #2.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | head -c20 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Middle of a Text File (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | head -22 | tail -11 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Middle of a Text File (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | head -22 | tail +12 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Middle of a Text File (Sol. 3).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tail +12 | head -11 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Paste #1.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | paste -s -d';' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Paste #2.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | paste -d';' - - - 3 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Paste #3.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | paste -s 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Paste #4 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | paste -sd $'\t\t\n' 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Paste #4 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | paste - - - 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Sort Command #1.sh: -------------------------------------------------------------------------------- 1 | # !bin/bash 2 | 3 | sort 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Sort Command #2.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sort -r 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Sort Command #3.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sort -n 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Sort Command #4 (Sol. 1).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sort -rn 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Sort Command #4 (Sol. 2).sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sort -n | tac 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Sort Command #5.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sort -t$'\t' -k2 -rn 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Sort Command #6.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sort -t$'\t' -k2 -n 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Sort Command #7.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | sort -t"|" -k2 -rn 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Tail of a Text File #1.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tail -20 4 | -------------------------------------------------------------------------------- /4 – Linux Shell/Text Processing/Tail of a Text File #2.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | 3 | tail -c20 4 | -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2016-08-27 SE.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2016-08-27 SE.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2017-05-13 K2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2017-05-13 K2.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2017-06-17 K3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2017-06-17 K3.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2017-08-26 K4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2017-08-26 K4.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2018 K1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2018 K1.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2018-06-19 K3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2018-06-19 K3.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2018-08-24 K4 CS.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2018-08-24 K4 CS.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2018-08-25 K4 SE.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2018-08-25 K4 SE.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2018-09-10 StEx.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2018-09-10 StEx.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2019-03-23 K1 KN.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2019-03-23 K1 KN.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2019-03-23,31 K1 KN SI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2019-03-23,31 K1 KN SI.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2019-06-08 Extra Ex.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2019-06-08 Extra Ex.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2019-08-25 K4 SI .pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2019-08-25 K4 SI .pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2019-08-28 K4 KN.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2019-08-28 K4 KN.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2019-09-08 K3 KN SI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2019-09-08 K3 KN SI.pdf -------------------------------------------------------------------------------- /5 – Test & Exams/OS 2020-06-28 S1 SE.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/5 – Test & Exams/OS 2020-06-28 S1 SE.pdf -------------------------------------------------------------------------------- /assets/Exam/Examples Task 01 Exam 12-07-2020.pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/assets/Exam/Examples Task 01 Exam 12-07-2020.pages -------------------------------------------------------------------------------- /assets/Exam/Task 01 Exam 12-07-2020.pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/assets/Exam/Task 01 Exam 12-07-2020.pages -------------------------------------------------------------------------------- /assets/Project/Image editor.pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/assets/Project/Image editor.pages -------------------------------------------------------------------------------- /assets/Theory/OS Theory (main).pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andy489/Linux_Shell/eabf15f5af886e9b5a0f0b772f7cae2df7eac9e5/assets/Theory/OS Theory (main).pages --------------------------------------------------------------------------------