Added run_scripts exercises
This commit is contained in:
24
exercises/run_scripts/Makefile
Normal file
24
exercises/run_scripts/Makefile
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Makefile for sequential script executor project
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -Wall -Wextra -std=c11 -g
|
||||||
|
TARGET = run_scripts
|
||||||
|
SRC = main.c
|
||||||
|
|
||||||
|
.PHONY: all clean run test valgrind
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(SRC)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
run: $(TARGET)
|
||||||
|
./$(TARGET) tests/hello.sh tests/fail.sh
|
||||||
|
|
||||||
|
test: run
|
||||||
|
|
||||||
|
valgrind: $(TARGET)
|
||||||
|
valgrind --leak-check=full ./$(TARGET) scripts/test1.sh scripts/test2.sh
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET)
|
||||||
73
exercises/run_scripts/README.md
Executable file
73
exercises/run_scripts/README.md
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
# Sequential Script Executor
|
||||||
|
|
||||||
|
This project contains a simple C program that sequentially executes one or more bash scripts using `fork()` and `execlp()`.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Spawns a child process for each script
|
||||||
|
* Executes scripts using `/bin/bash`
|
||||||
|
* Waits for each child to finish before proceeding
|
||||||
|
* Reports exit status or signal termination
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run with example scripts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run manually
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run_scripts script1.sh script2.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run with Valgrind
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make valgrind
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clean build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
run_scripts/ # Root project folder
|
||||||
|
├── main.c # Main source code
|
||||||
|
├── Makefile # Build automation
|
||||||
|
├── README.md # Project documentation
|
||||||
|
└── tests/ # Example bash scripts for testing
|
||||||
|
├── hello.sh
|
||||||
|
└── fail.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
|
```sh
|
||||||
|
execute script 1: test1.sh
|
||||||
|
script test1.sh exited with code 0
|
||||||
|
execute script 2: test2.sh
|
||||||
|
script test2.sh exited with code 0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
* You can add as many scripts as needed in the command-line arguments.
|
||||||
|
* This tool can be used to batch test or automate shell scripts.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
59
exercises/run_scripts/main.c
Normal file
59
exercises/run_scripts/main.c
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/* This program executes a sequence of Bash scripts
|
||||||
|
* in sequential order. Each script is run in a child
|
||||||
|
* process, and the parent prints the exit status.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "usage: %s <file1>...\n", argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
const char *script_name = argv[i];
|
||||||
|
printf("execute script %d: %s\n", i, script_name);
|
||||||
|
|
||||||
|
/* fork process for execute script itself */
|
||||||
|
pid_t pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
case -1:
|
||||||
|
perror("fork");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
// child executes the current script
|
||||||
|
if (execlp("/bin/bash", "bash", script_name,
|
||||||
|
(char *)NULL) == -1) {
|
||||||
|
perror("execlp");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// parent waits for the child process
|
||||||
|
int status;
|
||||||
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
|
perror("waitpid");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
printf("script %s exited with code %d\n",
|
||||||
|
script_name, WEXITSTATUS(status));
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
printf("script %s terminated by signal %d\n",
|
||||||
|
script_name, WTERMSIG(status));
|
||||||
|
} else {
|
||||||
|
printf("script %s did not exit normally\n",
|
||||||
|
script_name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
4
exercises/run_scripts/tests/fail.sh
Executable file
4
exercises/run_scripts/tests/fail.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
# fail.sh
|
||||||
|
#!/bin/bash
|
||||||
|
exit 1
|
||||||
|
|
||||||
5
exercises/run_scripts/tests/hello.sh
Executable file
5
exercises/run_scripts/tests/hello.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
# hello.sh
|
||||||
|
#!/bin/bash
|
||||||
|
echo "Hello, world!"
|
||||||
|
exit 0
|
||||||
|
|
||||||
Reference in New Issue
Block a user