218 lines
5.5 KiB
Markdown
218 lines
5.5 KiB
Markdown
|
|
# Redirection
|
|||
|
|
|
|||
|
|
Master Bash redirection and pipes. These essential Linux features are critical for efficient system administration. Every command handles input, output, and errors through **File Descriptors (FDs)**:
|
|||
|
|
|
|||
|
|
* **STDIN** (0): Standard Input – receives data.
|
|||
|
|
* **STDOUT** (1): Standard Output – sends regular data.
|
|||
|
|
* **STDERR** (2): Standard Error – sends error messages.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Pipes vs. Redirection
|
|||
|
|
|
|||
|
|
Both manage data streams, but with a key difference:
|
|||
|
|
* **Redirection** routes a command's input/output to or from a **file**.
|
|||
|
|
* **Pipes** (`|`) connect the **output of one command directly to the input of another command**.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### STDIN (Standard Input)
|
|||
|
|
|
|||
|
|
Commands often expect input. By default, this is your keyboard, but you can redirect it from other sources.
|
|||
|
|
|
|||
|
|
**Redirecting from a file (`<`)**:
|
|||
|
|
Use `<` to feed a file's content as input to a command. Create `input.txt`:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
touch input.txt
|
|||
|
|
```
|
|||
|
|
Open `input.txt` and add:
|
|||
|
|
```
|
|||
|
|
Line 1
|
|||
|
|
Line 2
|
|||
|
|
```
|
|||
|
|
Save `input.txt`.
|
|||
|
|
Then run:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cat < input.txt
|
|||
|
|
```
|
|||
|
|
This prints `input.txt` content, similar to `cat input.txt`.
|
|||
|
|
|
|||
|
|
**Here-Documents (`<< DELIMITER`)**:
|
|||
|
|
For multi-line input directly in your script or terminal, use a here-document with a custom delimiter (e.g., `EOF`).
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cat << EOF
|
|||
|
|
Hello World!
|
|||
|
|
How are you?
|
|||
|
|
EOF
|
|||
|
|
```
|
|||
|
|
This will print:
|
|||
|
|
```
|
|||
|
|
Hello World!
|
|||
|
|
How are you?
|
|||
|
|
```
|
|||
|
|
Similarly, with `wc -l` to count lines:
|
|||
|
|
```bash
|
|||
|
|
wc -l << EOF
|
|||
|
|
Hello World!
|
|||
|
|
How are you?
|
|||
|
|
EOF
|
|||
|
|
```
|
|||
|
|
Output:
|
|||
|
|
```
|
|||
|
|
2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### STDOUT (Standard Output)
|
|||
|
|
|
|||
|
|
Regular command output typically goes to your terminal. Redirect it to a file.
|
|||
|
|
|
|||
|
|
**Overwrite (`>`)**:
|
|||
|
|
Use `>` to send output to a file. If the file exists, its content is overwritten. Create `file.txt` (or ensure it's empty):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
echo "Hello World!" > file.txt
|
|||
|
|
cat file.txt # Output: Hello World!
|
|||
|
|
```
|
|||
|
|
Running again overwrites:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
echo "How are you?" > file.txt
|
|||
|
|
cat file.txt # Output: How are you? (Previous content is gone)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Append (`>>`)**:
|
|||
|
|
Use `>>` to add output to the end of a file without overwriting existing content.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
echo "Hello World!" > file.txt # Start fresh
|
|||
|
|
echo "How are you?" >> file.txt
|
|||
|
|
cat file.txt
|
|||
|
|
```
|
|||
|
|
Output:
|
|||
|
|
```
|
|||
|
|
Hello World!
|
|||
|
|
How are you?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
You can also explicitly specify the STDOUT file descriptor (1): `echo "Hello" 1> file.txt`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### STDERR (Standard Error)
|
|||
|
|
|
|||
|
|
Error messages, distinct from standard output, are sent to **STDERR**. Redirect them using file descriptor 2.
|
|||
|
|
|
|||
|
|
**Redirecting Errors (`2>`)**:
|
|||
|
|
Use `2>` to redirect error messages. For example, `ls --invalid-flag` generates an error.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
ls --invalid-flag 2> error.txt
|
|||
|
|
cat error.txt # Contains the error message
|
|||
|
|
```
|
|||
|
|
Use `2>>` to append error messages to a file.
|
|||
|
|
|
|||
|
|
**Discarding Errors (`2> /dev/null`)**:
|
|||
|
|
Send error output to `/dev/null` to completely suppress it. `/dev/null` is a special 'black hole' device that discards all data written to it.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
ls --invalid-flag 2> /dev/null # Error message is hidden
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Redirecting Both STDOUT and STDERR**:
|
|||
|
|
You can manage both streams simultaneously.
|
|||
|
|
|
|||
|
|
To separate regular output and errors into different files:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Assuming 'install_package.sh' generates both output and errors
|
|||
|
|
./install_package.sh > output.txt 2> error.txt
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
To send both to the same file (concise syntax):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
./install_package.sh > combined_output.txt 2>&1
|
|||
|
|
```
|
|||
|
|
The `2>&1` redirects file descriptor 2 (STDERR) to the same location as file descriptor 1 (STDOUT), which is `combined_output.txt`. Alternatively, an even shorter Bash 4+ syntax: `&> combined_output.txt`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Piping (`|`)
|
|||
|
|
|
|||
|
|
Pipes connect the standard output of one command directly to the standard input of another, creating powerful command chains.
|
|||
|
|
|
|||
|
|
**Basic Example:** Find `.txt` files in a directory listing.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
ls | grep ".txt"
|
|||
|
|
```
|
|||
|
|
This sends `ls`'s output to `grep` for filtering.
|
|||
|
|
|
|||
|
|
**Chaining Commands:** Analyze file ownership in a directory.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
ls -l /projects/bash_scripts | tail -n +2 | sed 's/\s\s*/ /g' | cut -d ' ' -f 3 | sort | uniq -c
|
|||
|
|
```
|
|||
|
|
This sequence lists files, removes the header, cleans spacing, extracts owner names, sorts them, and counts unique occurrences.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Here-Documents (`<< DELIMITER`)
|
|||
|
|
|
|||
|
|
Here-documents (`<<`) provide multi-line input directly within your script or terminal, ideal for commands that read from STDIN without needing a separate temporary file.
|
|||
|
|
|
|||
|
|
Specify a custom delimiter (e.g., `EOF`):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cat << END_MESSAGE
|
|||
|
|
This text will be passed as input to cat.
|
|||
|
|
It spans multiple lines.
|
|||
|
|
END_MESSAGE
|
|||
|
|
```
|
|||
|
|
Output:
|
|||
|
|
```
|
|||
|
|
This text will be passed as input to cat.
|
|||
|
|
It spans multiple lines.
|
|||
|
|
```
|
|||
|
|
You can also pipe the output of a here-document to another command:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
wc -l << MESSAGE_LINES
|
|||
|
|
Line one.
|
|||
|
|
Line two.
|
|||
|
|
Line three.
|
|||
|
|
MESSAGE_LINES
|
|||
|
|
```
|
|||
|
|
Output: `3` (counts the lines). Variables are expanded within here-documents.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Here-Strings (`<<<`)
|
|||
|
|
|
|||
|
|
For piping a single string into a command's STDIN, use a here-string (`<<<`). This is cleaner than a here-document for single lines.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
wc -w <<<"This is a sample string for word count."
|
|||
|
|
```
|
|||
|
|
Output: `7` (counts words).
|
|||
|
|
Variables are also supported in here-strings.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Summary of Redirection and Piping Operators
|
|||
|
|
|
|||
|
|
| **Operator** | **Description** |
|
|||
|
|
| :--- | :--- |
|
|||
|
|
| `>` | Redirect STDOUT to a file, overwriting existing content. |
|
|||
|
|
| `>>` | Redirect STDOUT to a file, appending to existing content. |
|
|||
|
|
| `<` | Redirect STDIN from a file. |
|
|||
|
|
| `2>` | Redirect STDERR to a file, overwriting existing content. |
|
|||
|
|
| `|` | Pipe STDOUT of one command to STDIN of another. |
|
|||
|
|
| `<<` | Here-document: Provide multi-line STDIN from the script. |
|
|||
|
|
| `<<<` | Here-string: Provide single-line STDIN from the command line. |
|