# 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