Added build files to turn the bible into a book
This commit is contained in:
@@ -1,94 +1,188 @@
|
||||
# Loops
|
||||
# File handling
|
||||
|
||||
## Loop over a range of numbers
|
||||
**CAVEAT:** `bash` doesn't handle binary data properly in versions `< 4.4`.
|
||||
|
||||
Don't use `seq`.
|
||||
## Read a file to a string
|
||||
|
||||
Alternative to the `cat` command.
|
||||
|
||||
```shell
|
||||
# Loop from 0-100 (no variable support).
|
||||
for i in {0..100}; do
|
||||
printf '%s\n' "$i"
|
||||
done
|
||||
file_data="$(<"file")"
|
||||
```
|
||||
|
||||
## Loop over a variable range of numbers
|
||||
## Read a file to an array (*by line*)
|
||||
|
||||
Don't use `seq`.
|
||||
Alternative to the `cat` command.
|
||||
|
||||
```shell
|
||||
# Loop from 0-VAR.
|
||||
VAR=50
|
||||
for ((i=0;i<=VAR;i++)); do
|
||||
printf '%s\n' "$i"
|
||||
done
|
||||
# Bash <4
|
||||
IFS=$'\n' read -d "" -ra file_data < "file"
|
||||
|
||||
# Bash 4+
|
||||
mapfile -t file_data < "file"
|
||||
```
|
||||
|
||||
## Loop over an array
|
||||
## Get the first N lines of a file
|
||||
|
||||
```shell
|
||||
arr=(apples oranges tomatoes)
|
||||
Alternative to the `head` command.
|
||||
|
||||
# Just elements.
|
||||
for element in "${arr[@]}"; do
|
||||
printf '%s\n' "$element"
|
||||
done
|
||||
**CAVEAT:** Requires `bash` 4+
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
head() {
|
||||
# Usage: head "n" "file"
|
||||
mapfile -tn "$1" line < "$2"
|
||||
printf '%s\n' "${line[@]}"
|
||||
}
|
||||
```
|
||||
|
||||
## Loop over an array with an index
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
arr=(apples oranges tomatoes)
|
||||
$ head 2 ~/.bashrc
|
||||
# Prompt
|
||||
PS1='➜ '
|
||||
|
||||
# Elements and index.
|
||||
for i in "${!arr[@]}"; do
|
||||
printf '%s\n' "${arr[$i]}"
|
||||
done
|
||||
|
||||
# Alternative method.
|
||||
for ((i=0;i<${#arr[@]};i++)); do
|
||||
printf '%s\n' "${arr[$i]}"
|
||||
done
|
||||
$ head 1 ~/.bashrc
|
||||
# Prompt
|
||||
```
|
||||
|
||||
## Loop over the contents of a file
|
||||
## Get the last N lines of a file
|
||||
|
||||
```shell
|
||||
while read -r line; do
|
||||
printf '%s\n' "$line"
|
||||
done < "file"
|
||||
Alternative to the `tail` command.
|
||||
|
||||
**CAVEAT:** Requires `bash` 4+
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
tail() {
|
||||
# Usage: tail "n" "file"
|
||||
mapfile -tn 0 line < "$2"
|
||||
printf '%s\n' "${line[@]: -$1}"
|
||||
}
|
||||
```
|
||||
|
||||
## Loop over files and directories
|
||||
|
||||
Don’t use `ls`.
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
# Greedy example.
|
||||
for file in *; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
$ tail 2 ~/.bashrc
|
||||
# Enable tmux.
|
||||
# [[ -z "$TMUX" ]] && exec tmux
|
||||
|
||||
# PNG files in dir.
|
||||
for file in ~/Pictures/*.png; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
$ tail 1 ~/.bashrc
|
||||
# [[ -z "$TMUX" ]] && exec tmux
|
||||
```
|
||||
|
||||
# Iterate over directories.
|
||||
for dir in ~/Downloads/*/; do
|
||||
printf '%s\n' "$dir"
|
||||
done
|
||||
## Get the number of lines in a file
|
||||
|
||||
# Brace Expansion.
|
||||
for file in /path/to/parentdir/{file1,file2,subdir/file3}; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
Alternative to `wc -l`.
|
||||
|
||||
# Iterate recursively.
|
||||
shopt -s globstar
|
||||
for file in ~/Pictures/**/*; do
|
||||
printf '%s\n' "$file"
|
||||
done
|
||||
shopt -u globstar
|
||||
**Example Function (bash 4):**
|
||||
|
||||
```sh
|
||||
lines() {
|
||||
# Usage: lines "file"
|
||||
mapfile -tn 0 lines < "$1"
|
||||
printf '%s\n' "${#lines[@]}"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Function (bash 3):**
|
||||
|
||||
This method uses less memory than the `mapfile` method and it's more
|
||||
compatible but it's slower for bigger files.
|
||||
|
||||
```sh
|
||||
lines_loop() {
|
||||
# Usage: lines_loop "file"
|
||||
count=0
|
||||
while IFS= read -r _; do
|
||||
((count++))
|
||||
done < "$1"
|
||||
printf '%s\n' "$count"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
$ lines ~/.bashrc
|
||||
48
|
||||
|
||||
$ lines_loop ~/.bashrc
|
||||
48
|
||||
```
|
||||
|
||||
## Count files or directories in directory
|
||||
|
||||
This works by passing the output of the glob as function arguments. We
|
||||
then count the arguments and print the number.
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
count() {
|
||||
# Usage: count /path/to/dir/*
|
||||
# count /path/to/dir/*/
|
||||
printf '%s\n' "$#"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
# Count all files in dir.
|
||||
$ count ~/Downloads/*
|
||||
232
|
||||
|
||||
# Count all dirs in dir.
|
||||
$ count ~/Downloads/*/
|
||||
45
|
||||
|
||||
# Count all jpg files in dir.
|
||||
$ count ~/Pictures/*.jpg
|
||||
64
|
||||
```
|
||||
|
||||
## Create an empty file
|
||||
|
||||
Alternative to `touch`.
|
||||
|
||||
```shell
|
||||
# Shortest.
|
||||
:> file
|
||||
|
||||
# Longer alternatives:
|
||||
echo -n > file
|
||||
printf '' > file
|
||||
```
|
||||
|
||||
## Extract lines between two markers
|
||||
|
||||
**Example Function:**
|
||||
|
||||
```sh
|
||||
extract() {
|
||||
# Usage: extract file "opening marker" "closing marker"
|
||||
while IFS=$'\n' read -r line; do
|
||||
[[ "$extract" && "$line" != "$3" ]] && \
|
||||
printf '%s\n' "$line"
|
||||
|
||||
[[ "$line" == "$2" ]] && extract=1
|
||||
[[ "$line" == "$3" ]] && extract=
|
||||
done < "$1"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```shell
|
||||
# Extract code blocks from MarkDown file.
|
||||
$ extract ~/projects/pure-bash/README.md '```sh' '```'
|
||||
# Output here...
|
||||
```
|
||||
|
||||
<!-- CHAPTER END -->
|
||||
|
||||
Reference in New Issue
Block a user