This is an ALX collaboration project on Shell. We were tasked to create a simple shell that mimics the Bash shell. The name of our shell is hsh.
- C language
- Shell
- Betty linter
-
Prints a prompt and waits for a command from the user
-
Creates a child process in which the command is checked
-
Checks for built-ins, aliases in the PATH, and local executable programs
-
The child process is replaced by the command, which accepts arguments
-
When the command is done, the program returns to the parent process and prints the prompt
-
The program is ready to receive a new command
-
To exit: press Ctrl-D or enter "exit" (with or without a status)
-
Works also in non interactive mode
To invoke hsh, compile all .c files in the repository and run the resulting executable.
hsh can be invoked both interactively and non-interactively. If hsh is invoked with standard input not connected to a terminal , it reads and executes received commands in order.
Example:
$ echo "echo 'hello'" | ./hsh
'hello'
$
If hsh is invoked with standard input connected to a terminal (determined by isatty(3)), an interactive shell is opened. When
executing interactively, hsh displays the prompt $ when it is ready to read a command.
Example:
$./hsh
$
Alternatively, if command line arguments are supplied upon invocation, hsh treats the first argument as a file from which to r
ead commands. The supplied file should contain one command per line. hsh runs each of the commands contained in the file in or
der before exiting.
Example:
$ cat test
echo 'hello'
$ ./hsh test
'hello'
$
$ echo "echo $HOME" | ./hsh
/home/projects
PWD
The current working directory as set by the cd command.
$ echo "echo $PWD" | ./hsh
/home/projects/alx/simple_shell
OLDPWD
The previous working directory as set by the cd command.
$ echo "echo $OLDPWD" | ./hsh
/home/projects/alx/printf
PATH
A colon-separated list of directories in which the shell looks for commands. A null directory name in the path (represented by
any of two adjacent colons, an initial colon, or a trailing colon) indicates the current directory.
$ echo "echo $PATH" | ./hsh
/home/projects/.cargo/bin:/home/projects/.local/bin:/home/projects/.rbenv/plugins/ruby-build/bin:/home/projects/.rbenv/shims:/
home/proj
- If the first character of the command is neither a slash () nor dot (.), the shell searches for it in the list of shell bu iltins. If there exists a builtin by that name, the builtin is invoked.
- If the first character of the command is none of a slash (), dot (.), nor builtin, hsh searches each element of the PATH e nvironmental variable for a directory containing an executable file by that name.
- If the first character of the command is a slash () or dot (.) or either of the above searches was successful, the shell e xecutes the named program with any remaining given arguments in a separate execution environment.
Exit Status
hsh returns the exit status of the last command executed, with zero indicating success and non-zero indicating failure.
If a command is not found, the return status is 127; if a command is found but is not executable, the return status is 126.
All builtins return zero on success and one or two on incorrect usage (indicated by a corresponding error message).
Signals
While running in interactive mode, hsh ignores the keyboard input Ctrl+c. Alternatively, an input of end-of-file (Ctrl+d) will
exit the program.
User hits Ctrl+d in the third line.
$ ./hsh
$ ^C
$ ^C
$
$ENV_VARIABLE
ENV_VARIABLE is substituted with its value.
Example:
$ echo "echo $PWD" | ./hsh
/home/projects/alx/simple_shell
$?
? is substitued with the return value of the last program executed.
Example:
$ echo "echo $?" | ./hsh
0
$$
The second $ is substitued with the current process ID.
Example:
$ echo "echo $$" | ./hsh
6494
Comments
hsh ignores all words and characters preceeded by a # character on a line.
Example:
$ echo "echo 'hello' #this will be ignored!" | ./hsh
'hello'
Operators
hsh specially interprets the following operator characters:
; - Command separator
Commands separated by a ; are executed sequentially.
Example:
$ echo "echo 'hello' ; echo 'world'" | ./hsh
'hello'
'world'
&& - AND logical operator
command1 && command2: command2 is executed if, and only if, command1 returns an exit status of zero.
Example:
$ echo "error! && echo 'hello'" | ./hsh
./hsh: 1: error!: not found
$ echo "echo 'all good' && echo 'hello'" | ./hsh
'all good'
'hello'
|| - OR logical operator
command1 || command2: command2 is executed if, and only if, command1 returns a non-zero exit status.
Example:
$ echo "error! || echo 'but still runs'" | ./hsh
./hsh: 1: error!: not found
'but still runs'
The operators && and || have equal precedence, followed by ;.
hsh Builtin Commands
cd
Usage: cd [DIRECTORY]
Changes the current directory of the process to DIRECTORY.
If no argument is given, the command is interpreted as cd $HOME.
If the argument - is given, the command is interpreted as cd $OLDPWD and the pathname of the new working directory is printed to standad output.
If the argument, -- is given, the command is interpreted as cd $OLDPWD but the pathname of the new working directory is not pr inted.
The environment variables PWD and OLDPWD are updated after a change of directory.
Example:
$ ./hsh
$ pwd
/home/projects/alx/simple_shell
$ cd ../
$ pwd
/home/projects/alx
$ cd -
$ pwd
/home/projects/alx/simple_shell
alias
Usage: alias [NAME[='VALUE'] ...]
Handles aliases.
alias: Prints a list of all aliases, one per line, in the form NAME='VALUE'.
alias NAME [NAME2 ...]: Prints the aliases NAME, NAME2, etc. one per line, in the form NAME='VALUE'.
alias NAME='VALUE' [...]: Defines an alias for each NAME whose VALUE is given. If name is already an alias, its value is repla
ced with VALUE.
Example:
$ ./hsh
$ alias show=ls
$ show
AUTHORS builtins_help_2.c errors.c linkedlist.c shell.h test
README.md env_builtins.c getline.c locate.c hsh
alias_builtins.c environ.c helper.c main.c split.c
builtin.c err_msgs1.c helpers_2.c man_1_simple_shell str_funcs1.c
builtins_help_1.c err_msgs2.c input_helpers.c proc_file_comm.c str_funcs2.c
exit
Usage: exit [STATUS]
Exits the shell.
The STATUS argument is the integer used to exit the shell.
If no argument is given, the command is interpreted as exit 0.
Example:
$ ./hsh
$ exit
env
Usage: env
Prints the current environment.
Example:
$ ./hsh
$ env
NVM_DIR=/home/projects/.nvm
...
setenv
Usage: setenv [VARIABLE] [VALUE]
Initializes a new environment variable, or modifies an existing one.
Upon failure, prints a message to stderr.
Example:
$ ./hsh
$ setenv NAME Poppy
$ echo $NAME
Poppy
unsetenv
Usage: unsetenv [VARIABLE]
Removes an environmental variable.
Upon failure, prints a message to stderr.
Example:
$ ./hsh
$ setenv NAME Poppy
$ unsetenv NAME
$ echo $NAME
$
-
How a shell works and finds commands
-
Creating, forking and working with processes
-
Executing a program from another program
-
Handling dynamic memory allocation in a large program
-
Pair programming and team work
-
Building a test suite to check our own code
Umar Faruq Adamumarfaruqadam03@gmail.com
Imran Suleimanimransuleiman26@gmail.com