---
# System prepended metadata

title: Built-in Functions in Shell
tags: [42-minishell]

---

# Built-in Functions in Bash Shell

* **How to handle 'cd is a shell builtin' in Linux**
https://labex.io/tutorials/linux-how-to-handle-cd-is-a-shell-builtin-in-linux-417668

## env [options or arguments]

1. Without any argument
If no flags or parameters are specified, the env command displays your current environment, showing one Name=Value pair per line.
Print out a list of all environment variables. 


2. ‘-i’ or ‘–ignore-environment’ or ‘only -‘ 
Runs a command with an empty environment 

```c
 [  -i | - ] [Name=Value ]... [Command [ Argument ... ] ]
```
https://www.ibm.com/docs/tr/aix/7.1?topic=e-env-command



---


## pwd

The default behavior of the shell built-in “pwd” is equivalent to using “pwd -L”.

```c
pwd -L: Prints the symbolic path. 

pwd -P: Prints the actual path.
```

https://www.geeksforgeeks.org/pwd-command-in-linux-with-examples/#syntax-of-pwd-command-in-linux


### used function: getcwd

```c
 getcwd(): string|false
```
https://www.php.net/manual/en/function.getcwd.php



---

## echo

**[options]** = The various options available for modifying the behavior of the `echo` command

**[string]** = It is the string that we want to display.
```c
echo [option] [string]
```
- The echo command writes character strings to standard output. 
- Strings are separated by spaces, and a new-line character follows the last String parameter specified. 
- If no String parameter is specified, a blank line (new-line character) is displayed.

```c
echo -n
echo -nnnnnnn
```

* **-n / -nnnnnn (followed only by character 'n'): **
 -> valid option
 => remove \n
 
 
 * **-nP , -n-n, -nOPEK (followed by non 'n'):** 
 -> invlaid


---
## exit

```c
exit [N (exit_number)]
```

- The exit statement is used to exit from the shell script with a status of N.
- Use the exit statement to indicate successful or unsuccessful shell script termination.
- The value of N can be used by other commands or shell scripts to take their own action.
- If N is omitted, the exit status is that of the last command executed.
- Use the exit statement to terminate shell script upon an error.
    If N is set to 0 means normal shell exit.



### exit code
https://hackmd.io/@QBrv51OvRPqs9dJjL2YIig/rJMw9uQf1g

#### reference- check built-in exit code

```c
// bi_exit: This function handles the exit command in a shell environment.
// It processes the arguments provided and exits the shell with the appropriate exit code.
int bi_exit(t_shell *ctx, t_arg *args)
{
    int exit_code;

    // Check if there are more than one argument and if the first argument is not a valid exit code
    if (args && args->next && !bi_check_exitcode(args->value))
        // Print error message if there are too many arguments and return with exit code 1
        return (ft_putstr_fd("minishell: exit: too many arguments\n", STDERR_FILENO), 1);

    // Set the default exit code to 0
    exit_code = 0;

    // Check if the first argument is a valid exit code (it should be a number)
    if (args && !bi_check_exitcode(args->value))
        // If it's a valid exit code, convert the argument to an integer
        exit_code = ft_atoi(args->value);
    else if (args && bi_check_exitcode(args->value))
    {
        // If the argument is invalid, call bi_err_exit to handle the error
        bi_err_exit(args->value);
        // Set exit code to 2 to indicate an error
        exit_code = 2;
    }

    // Close any open resources in the shell context
    ft_close(ctx);
    // Free any allocated memory in the shell context
    free_all_shell(ctx);
    // Exit the shell with the determined exit code
    exit(exit_code);
}

//////////////////////////////////

// bi_check_exitcode: This function checks if the provided value can be a valid exit code.
// It ensures the value is a number and falls within the valid range of exit codes.
int bi_check_exitcode(char *value)
{
    char *tmp;
    long num;

    // Make tmp point to the provided value
    tmp = value;

    // If the value starts with '+' or '-', skip the sign
    if ((*tmp == '+' || *tmp == '-') && *(tmp + 1))
        tmp++;

    // Iterate through each character in the value to check if it's a digit
    while (*tmp)
    {
        // If any character is not a digit, return 1 indicating an invalid exit code
        if (!ft_isdigit(*tmp++))
            return (1);
    }

    // Convert the value to a long integer using ft_atol
    num = ft_atol(value);

    // Check if the number overflows or underflows the range of valid exit codes
    if ((num > 0 && (LONG_MAX / num < 1))   // Overflow check for positive numbers
        || (num < 0 && (LONG_MIN / ft_atol(value) < 1))) // Underflow check for negative numbers
        return (1);  // Return 1 to indicate an invalid exit code

    // Return 0 if the value is a valid exit code (no overflow or non-digit characters)
    return (0);
}

```


#### **1. Why would `value` start with `+` or `-`?**

In many programming environments (including shells), exit codes (or return codes) are often numeric values that can be either positive or negative. For example:
- A return code of `0` typically indicates successful execution.
- Non-zero return codes (positive or negative) usually indicate some form of error or abnormal behavior.

In C and many other languages, numeric values can optionally be prefixed with a sign (`+` or `-`) to indicate whether they are positive or negative:
- If the value starts with a `+`, it means the number is positive (e.g., `+42` is just `42`).
- If the value starts with a `-`, it means the number is negative (e.g., `-1` represents negative one).

**Why check for these signs?**
- The function allows for both positive and negative exit codes.
- The logic is implemented to handle the possibility that a user might input a string like `"42"` or `"-42"` or `"+42"`.

For example:
```c
bi_check_exitcode("-42"); // Valid, negative number
bi_check_exitcode("+42"); // Valid, positive number
```

#### **2. Why use `ft_atol`?**

The function uses `ft_atol` (presumably a function that converts a string to a long integer) to convert the input `value` (which is a string) into a numerical form. Here's why this is necessary:

- **Exit Code Representation**: The exit code is a number, but the user may input it as a string (e.g., `"42"`, `"-1"`, etc.).
- **Numeric Validation**: After checking that the string consists of digits (and possibly a sign), `ft_atol` is used to convert the string into a long integer (`long`). This allows for more meaningful validation, such as checking for overflow/underflow, and handling large or negative numbers that are typically seen in shell exit codes.

`ft_atol` is used instead of `atoi` to allow handling larger numbers because `long` provides a larger range than `int`.

Example:
```c
// If user inputs "-123456789", we convert it to a long
long exit_code = ft_atol("-123456789");  // This converts the string into the number -123456789
```

#### **3. Explanation of Overflow and Underflow Checks**

The overflow and underflow checks ensure that the exit code falls within the valid range for an exit code, which typically must be a number between `0` and `255` (in many shell environments). Since `LONG_MAX` and `LONG_MIN` are much larger than this range, we need to ensure that the value is within the bounds.

Here are the checks and why they are necessary:

```c
if ((num > 0 && (LONG_MAX / num < 1))   // Overflow check for positive numbers
    || (num < 0 && (LONG_MIN / ft_atol(value) < 1))) // Underflow check for negative numbers
```

#### **Overflow Check for Positive Numbers (`num > 0 && (LONG_MAX / num < 1)`)**

- `LONG_MAX` is the largest value that can fit into a `long` variable. On most systems, `LONG_MAX` is `9223372036854775807` (for a 64-bit system).
- If the `num` is positive, we check if multiplying it by `1` would cause it to exceed `LONG_MAX`.
  - For example, if `num = 1000000000`, `LONG_MAX / num` will give a number greater than `1`. But if `num = 9223372036854775808`, `LONG_MAX / num` will be less than `1`, indicating that `num` is larger than `LONG_MAX`.
  - **Overflow means a number exceeds the maximum value that can be represented**, causing it to wrap around and produce unpredictable results.

#### **Underflow Check for Negative Numbers (`num < 0 && (LONG_MIN / ft_atol(value) < 1)`)**

- `LONG_MIN` is the smallest value that can fit into a `long` variable, and it’s usually `-9223372036854775808` for a 64-bit system.
- If `num` is negative, we check if dividing `LONG_MIN` by `num` gives a result less than `1`. This indicates that `num` is too small (i.e., it’s below the valid range of exit codes).
  - For example, if `num = -9223372036854775809`, `LONG_MIN / num` would be less than `1`, signaling an underflow (the number is too small to be a valid exit code).
  - **Underflow means the number is too small, causing issues when handling negative numbers in certain systems**.

#### **Examples**

- **Overflow Example**:
  ```c
  num = 9223372036854775808;  // Exceeds LONG_MAX
  if (LONG_MAX / num < 1) {   // This condition will be true, indicating overflow
      return 1; // Invalid exit code
  }
  ```

- **Underflow Example**:
  ```c
  num = -9223372036854775809;  // Less than LONG_MIN
  if (LONG_MIN / num < 1) {    // This condition will be true, indicating underflow
      return 1; // Invalid exit code
  }
  ```

In summary:
- **Overflow** occurs when a number is too large to be represented in the target type (in this case, `long`).
- **Underflow** occurs when a number is too small, and it is below the minimum representable value (i.e., smaller than `LONG_MIN`).
- These checks prevent invalid or incorrectly interpreted exit codes, ensuring that the exit code remains within a valid and manageable range.

The checks `(LONG_MAX / num < 1)` and `(LONG_MIN / num < 1)` are designed to detect overflow and underflow situations when handling large or small numbers. Let’s break down the logic behind each of these checks and why division is used.

#### **Explaination on why divide to overflow/undrflow?**

- When you divide by `num`, you are essentially checking if multiplying `num` by any value (like `1`) will result in a number that exceeds the maximum or minimum limit that can be represented by the `long` type. 
- This is important because `LONG_MAX` and `LONG_MIN` represent the maximum and minimum values that a `long` can hold. If you try to assign a value larger than `LONG_MAX` or smaller than `LONG_MIN` to a variable of type `long`, it will overflow or underflow, respectively.

- To **check for overflow** or **underflow** without actually performing the multiplication (which could cause the overflow or underflow), the division check ensures that multiplying by `num` would exceed the boundaries of the `long` type.

#### **Overflow Check: `(LONG_MAX / num < 1)`**

- `LONG_MAX` is the largest value that can be stored in a `long` type.
- If we divide `LONG_MAX` by `num`, we want to check if multiplying `num` by any value, especially `1`, will cause the value to exceed `LONG_MAX`.

##### Example:

Let's say `num = 9223372036854775808` (a number that exceeds `LONG_MAX` for 64-bit systems).

- On a 64-bit system, `LONG_MAX` is typically `9223372036854775807`.
- Now, if we divide `LONG_MAX` by `num`:
  
  ```c
  long num = 9223372036854775808; // A value that exceeds LONG_MAX
  if (LONG_MAX / num < 1) {
      // This will evaluate to true because the result of the division
      // is smaller than 1, indicating that num is too large and would overflow
  }
  ```

- Dividing `LONG_MAX` by `9223372036854775808` gives a result smaller than `1`, which means multiplying `num` by any number (especially `1`) would exceed `LONG_MAX`. This indicates an overflow would occur if you tried to store `num` in a `long`.

#### **Underflow Check: `(LONG_MIN / num < 1)`**

- `LONG_MIN` is the smallest value that can be stored in a `long` type.
- Similar to the overflow check, this division checks if dividing `LONG_MIN` by `num` would lead to a result smaller than `1`. If it does, it means that multiplying `num` by any value would cause underflow (i.e., the result would go below the minimum representable value for a `long`).

##### Example:

Let’s take `num = -9223372036854775809`, which is a number smaller than `LONG_MIN` for a 64-bit system.

- On a 64-bit system, `LONG_MIN` is typically `-9223372036854775808`.
- Dividing `LONG_MIN` by `num`:

  ```c
  long num = -9223372036854775809; // A value that is smaller than LONG_MIN
  if (LONG_MIN / num < 1) {
      // This will evaluate to true because dividing LONG_MIN by num
      // will result in a number smaller than 1, indicating an underflow
  }
  ```

- Dividing `LONG_MIN` by `-9223372036854775809` results in a value smaller than `1`, which means multiplying `num` by any number (especially `1`) would cause underflow. This indicates that `num` is too small to be represented in a `long`.

#### **Summary:**

- **Overflow Check**: `(LONG_MAX / num < 1)` is checking if multiplying `num` by any value would exceed the maximum value a `long` can hold. If dividing `LONG_MAX` by `num` results in a value smaller than `1`, it means multiplying `num` by `1` would exceed `LONG_MAX`, causing an overflow.
  
- **Underflow Check**: `(LONG_MIN / num < 1)` is checking if multiplying `num` by any value would cause the result to go below the minimum value a `long` can hold. If dividing `LONG_MIN` by `num` results in a value smaller than `1`, it means multiplying `num` by `1` would cause an underflow.


-> These checks ensure that `num` does not exceed the boundaries of the `long` data type, thus preventing overflow and underflow. 

-> Division is used here because it allows us to avoid performing the potentially dangerous multiplication that would result in an actual overflow or underflow.


---

- **Exit command:**
https://bash.cyberciti.biz/guide/Exit_command#Syntax
- **Bash Exit Command Explained: Script Terminating Tutorial:**
https://ioflood.com/blog/bash-exit/
- **How to use exit code to read from terminal, from script and with logical operators:**
https://www.geeksforgeeks.org/how-to-use-exit-code-to-read-from-terminal-from-script-and-with-logical-operators/


---

## cd

```cl
cd [options] [directory]
```

* Cd Command in Linux (Change Directory)
https://linuxize.com/post/linux-cd-command/

* How to Change the Directory in Linux | cd Command
https://www.geeksforgeeks.org/cd-command-in-linux-with-examples/

##### cd with [options]
```c
cd
cd -- (In the POSIX standard, cd -- behaves like running cd without arguments.)
cd -  ()
cd ..
cd /
cd ~
```

```c
int chdir(const char *path);
```
chdir() changes the current working directory of the calling
process to the directory specified in path.



---

# export

```c

export
(To view all the exported variables.)

    
export -p 
(To view all exported variables on current shell. )

    
export -f [function_name] 
(To export shell function) 
***Must be used if the names refer to functions. 
*** If -f is not used, the export will assume the names are variables. 
    
    
export -n [variable_name]
(Named variables (or functions, with -f) will no longer be exported.)
***No output will be seen on screen, to see exported variable grep from exported ones is used.

```

---

## **POSIX Behavior of the `export` Command**

The `export` built-in command in **bash**:

1. **Without Arguments**:
   - The environment variables are displayed in **alphabetical order**.
   - Each variable is printed in the format:
     ```
     declare -x VAR="value"
     ```
   - Sorting the environment ensures consistent behavior when users call `export`.

2. **With Arguments**:
   - If you pass arguments like `export VAR=value`, the variable is added or updated in the environment list **without requiring sorting** immediately.

---

## **When Sorting enviromet variable is Needed?**

- **If the `export` command is called without arguments**, you must print the environment variables **in alphabetical order**.  
   Example:
   ```bash
   export
   ```
   Output:
   ```
   declare -x HOME="/home/user"
   declare -x PATH="/usr/bin"
   declare -x SHELL="/bin/bash"
   ```

- Sorting ensures consistent behavior regardless of the order in which variables were added.

---


## **Optimizing Sorting**

If sorting becomes a bottleneck, you can **optimize** it:

1. **Sort Only When Printing**:
   - Instead of sorting the entire environment list every time you modify it, sort only when you need to print the variables (e.g., inside `ft_export_noarg`).

   Example:
   ```c
   void ft_export_noarg(char **env)
   {
       ft_advanced_sort_string_tab(env, &ft_strcmp);
       // Print the sorted environment
       for (int i = 0; env[i]; i++)
           printf("declare -x %s\n", env[i]);
   }
   ```

2. **Avoid Duplicate Sorting**:
   - If the environment is already sorted and hasn’t been modified, there’s no need to sort it again. You can add a **"sorted" flag** to track whether sorting is needed.

---

## **Conclusion**

- **Yes**, sorintg envionmet variables is necessary when the `export` command is called **without arguments** to ensure the environment variables are displayed in **alphabetical order**, as expected in a POSIX-compliant shell.
- If you only add or update variables with `export VAR=value`, sorting is not required at that stage.
- For better performance, sort the environment **only when printing** and avoid redundant sorting by tracking changes to the environment list.


---
# unset

```c

unset [variable_name]
unset [-options] [variable_name]
(Undefine a variable in bash)


unset -f [function_name]
(Undefine shell function in bash)

```

* **Unset Syntax**
https://bash.cyberciti.biz/guide/Unset


* **Bash remove environment variables command**
https://www.cyberciti.biz/faq/bash-remove-environment-variables-command/

*  Linux unset command summary with examples
 https://www.youtube.com/watch?v=yDPRQ28dV6E&list=PL6YwPExkSESqQ69B7B011XOIuoVv3SdDg&index=50


