Skip to main content

Launching Minishell

After building Minishell, start the shell from your build directory:
./minishell
You’ll see the Minishell prompt, which displays your username and current directory:
minishell>
The prompt is generated by the ft_print_user() function and updates dynamically based on your current directory.

Your First Commands

1

Try a Simple Built-in Command

Start with the pwd command to print your current working directory:
minishell> pwd
/home/user/minishell
The implementation from builtins.c uses the getcwd() system call:
void pwd(int argc)
{
    char *pwd;
    
    if (argc > 1)
    {
        printf("pwd: too many arguments\n");
        return ;
    }
    pwd = getcwd(NULL, 0);
    printf("%s\n", pwd);
    free(pwd);
    g_status = 0;
}
2

Display Text with Echo

Use the echo command to print text:
minishell> echo Hello, Minishell!
Hello, Minishell!
Try the -n flag to suppress the newline:
minishell> echo -n No newline here
No newline hereminishell>
The echo built-in supports the -n flag just like bash, implemented in builtins.c:87-106.
3

Navigate Directories

Change directories using cd:
minishell> cd /tmp
minishell> pwd
/tmp

minishell> cd
minishell> pwd
/home/user
Without arguments, cd takes you to your home directory:
void cd(int argc, char *av)
{
    char *path;
    
    if (argc == 1)
        path = getenv("HOME");
    else
        path = av;
    if (chdir(path) == -1)
    {
        g_status = 1;
        perror("cd");
        return ;
    }
    g_status = 0;
}
4

List Files with External Commands

Minishell executes external programs by searching the PATH:
minishell> ls -la
total 248
drwxr-xr-x  4 user user   4096 Mar  7 12:00 .
drwxr-xr-x 28 user user   4096 Mar  6 10:30 ..
-rw-r--r--  1 user user   2140 Mar  7 11:00 main.c
-rwxr-xr-x  1 user user  45832 Mar  7 12:00 minishell
Try other common commands:
minishell> cat minishell.h
minishell> grep "typedef" minishell.h
minishell> wc -l *.c

Working with Environment Variables

Viewing Environment Variables

minishell> env
PATH=/usr/local/bin:/usr/bin:/bin
HOME=/home/user
USER=user
SHELL=/bin/bash
...

Variable Expansion

Minishell supports environment variable expansion using the $ prefix:
minishell> export GREETING=Hello
minishell> echo $GREETING World
Hello World
The expansion is handled by the vars() function in env_parsed.c:
char *vars(char *commands, t_prompt *env, int i, int x)
{
    // Parses and expands $VAR in command strings
    // Handles special cases like $? for exit status
}

Special Variables

Check the exit status of the last command:
minishell> ls /nonexistent
ls: cannot access '/nonexistent': No such file or directory

minishell> echo $?
2

minishell> echo success
success

minishell> echo $?
0

Remove Variables

Use unset to remove environment variables:
minishell> export TEMP_VAR=test
minishell> echo $TEMP_VAR
test

minishell> unset TEMP_VAR
minishell> echo $TEMP_VAR

Your First Pipeline

Pipelines connect the output of one command to the input of another using the | operator.

Basic Pipe Example

minishell> ls -l | grep minishell
-rwxr-xr-x 1 user user 45832 Mar  7 12:00 minishell
-rw-r--r-- 1 user user  4567 Mar  7 11:00 minishell.h
This pipes the output of ls -l into grep, which filters for lines containing “minishell”.

Multi-Command Pipeline

Chain multiple commands together:
minishell> cat *.c | grep "include" | wc -l
42
This pipeline:
  1. Concatenates all .c files (cat *.c)
  2. Filters for lines with “include” (grep "include")
  3. Counts the matching lines (wc -l)

How Pipes Work

Minishell creates separate processes for each command and connects them:
// From ft_execute_commands.c - Pipeline execution
void excecute_pipe_sequence(t_mini *data, int pipefd[2])
{
    int aux[2];
    
    aux[0] = -1;
    aux[1] = -1;
    while (data->nodes[++aux[0]])
    {
        if (pipe(pipefd) == -1)
            return ;
        data->nodes[aux[0]]->n_pid = fork();
        if (data->nodes[aux[0]]->n_pid == 0
            && data->nodes[aux[0]]->is_set == 1)
            child_process(data, data->nodes[aux[0]], aux, pipefd);
        // Parent process continues...
    }
}

Input and Output Redirection

Output Redirection

Redirect command output to a file:
minishell> echo "Hello" > output.txt
minishell> cat output.txt
Hello

minishell> ls -l > filelist.txt

Input Redirection

Read command input from a file:
minishell> echo "apple\nbanana\ncherry" > fruits.txt
minishell> wc -l < fruits.txt
3

Heredoc (<<)

Provide multi-line input interactively:
minishell> cat << EOF
> This is line 1
> This is line 2
> This is line 3
> EOF
This is line 1
This is line 2
This is line 3
The heredoc is handled by the check_heredoc() function:
void check_heredoc(char *limit, int *infile)
{
    int fd;
    char *line;
    
    fd = open(TEMP_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644);
    while (1)
    {
        line = readline(">");
        if (!line || (!ft_strncmp(line, limit, ft_strlen(limit))))
            break ;
        write(fd, line, strlen(line));
        write(fd, "\n", 1);
    }
    close(fd);
    *infile = open(TEMP_FILE, O_RDONLY);
}

Combining Redirections

You can combine multiple redirections:
minishell> cat < input.txt > output.txt
minishell> grep "error" < logfile.txt >> errors.txt
minishell> cat << END | grep "test" > results.txt
> test line 1
> other line
> test line 2
> END

Quote Handling

Minishell properly handles single and double quotes:
minishell> echo 'Hello $USER'
Hello $USER
# Variables NOT expanded in single quotes
Quotes are removed before command execution by the remove_quotes() function in parse_imput.c.

Signal Handling

Minishell responds to keyboard signals:
  • Ctrl+C (SIGINT): Cancels current command and displays a new prompt
  • Ctrl+D (EOF): Exits the shell when pressed on an empty line
  • *Ctrl+* (SIGQUIT): Ignored in interactive mode (unlike bash)
// From signals.c - Signal setup
void setup_signals(void)
{
    signal(SIGINT, handle_sigint);
    signal(SIGQUIT, SIG_IGN);
}

void handle_sigint(int sig)
{
    g_status = 130;
    write(1, "\n", 1);
    rl_on_new_line();
    rl_replace_line("", 0);
    rl_redisplay();
}

Exiting the Shell

There are three ways to exit Minishell:
minishell> exit
# Exits with status 0

minishell> exit 42
# Exits with status 42

Practical Examples

Example 1: File Processing Pipeline

minishell> cat employees.txt | grep "Engineer" | wc -l
15
Counts how many employees are engineers.

Example 2: Log Analysis

minishell> grep "ERROR" app.log > errors.txt
minishell> wc -l < errors.txt
27
minishell> cat errors.txt | head -5
Extracts errors from a log file and examines them.

Example 3: Environment Setup

minishell> export PROJECT_DIR=/home/user/project
minishell> export PATH=$PATH:$PROJECT_DIR/bin
minishell> cd $PROJECT_DIR
minishell> pwd
/home/user/project
Configures project-specific environment variables.

Example 4: Data Transformation

minishell> cat data.csv | cut -d',' -f2 | sort | uniq > unique_values.txt
Extracts the second column from a CSV, sorts it, and removes duplicates.

Command History

Minishell uses GNU Readline for command history:
  • Up Arrow: Navigate to previous commands
  • Down Arrow: Navigate to next commands
  • Ctrl+R: Search command history (if enabled)
History is managed automatically:
// From main.c - Adding to history
void enterdata(char *line, t_mini *data, int i)
{
    add_history(line);
    // Process command...
}

Common Pitfalls

Unclosed Quotes: Minishell detects unclosed quotes and reports syntax errors:
minishell> echo "hello
syntax error: unclosed quotes
Invalid Pipes: Empty pipe segments cause errors:
minishell> ls | | grep test
syntax error near unexpected token '|'
Redirection Errors: Missing filenames after redirection operators:
minishell> echo "test" >
syntax error near unexpected token 'newline'

Next Steps

Now that you understand the basics, explore more advanced features:

Built-in Commands

Detailed reference for all built-in commands

Pipelines

Advanced pipeline techniques

Redirections

Input and output redirection

Environment Variables

Managing and using environment variables

Build docs developers (and LLMs) love