Skip to content

Commit

Permalink
feat: chapter 21 - Loops and working with Files and Folders
Browse files Browse the repository at this point in the history
  • Loading branch information
dwmkerr authored May 23, 2021
1 parent fb2f2d9 commit 5561dda
Show file tree
Hide file tree
Showing 15 changed files with 1,166 additions and 280 deletions.
34 changes: 24 additions & 10 deletions effective-shell-playground/scripts/common.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Write the title of our command.
echo "common commands:"

# If we are on a Mac, we need to use the GNU tools.
if [[ "$(uname)" == "Darwin" ]]; then
alias tail=gtail
alias uniq=guniq
alias sed=gsed
fi

# Write the title of our command.
echo "common commands:"

# The following variables control how the command runs.
shell_binary="" # We will work out what shell we are in later.
history_file="" # We will work out the history file later.
Expand All @@ -22,35 +22,49 @@ if [[ $SHELL =~ $shell_regex ]]; then
if [[ $shell_binary == "bash" ]]; then
history_file=~/.bash_history
elif [[ $shell_binary == "zsh" ]]; then
history_file=~/.bash_history
history_file=~/.zsh_history
fi
fi

# If we are searching through the bash history, we can look at the history file
# to get the most common commands.
if [[ $shell_binary == "bash" ]]; then
# Show the most commonly used commands.
tail "${history_file}" -n ${history_lines} \
# Store the most commonly used commands.
commands=$(tail "${history_file}" -n ${history_lines} \
| sort \
| uniq -c \
| sed 's/^ *//' \
| sort -n \
| tail -n ${command_count}
| sort -n -r \
| head -n ${command_count})
elif [[ $shell_binary == "zsh" ]]; then
# Each line in the has some extra information at the beginning, the command
# text only appears after a semi-colon. So extract the text from after the
# semi-colon and then process it just like in the bash example.
commands=$(tail "${history_file}" -n ${history_lines} \
tail "${history_file}" -n ${history_lines} \
| rev \
| cut -d';' -f1 \
| rev \
| sort \
| uniq -c \
| sed 's/^ *//' \
| sort -n \
| tail -n ${command_count}
| sort -n -r \
| head -n ${command_count})
else
# Show a warning to the user that we don't know where the history file is
# for their shell.
echo "Sorry, I don't know where to find the history for '${SHELL}'"
fi

# Print each command, showing what its order is in the list.
# Commands are separated by newlines, so temporarily change IFS to loop over
# each line of the commands.
counter=1
old_ifs=$IFS
IFS=$'\n'
for command in $commands
do
echo "$counter: $command"
counter=$((counter + 1))
done
IFS=$old_ifs
2 changes: 1 addition & 1 deletion effective-shell-playground/scripts/common.v1.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
echo "common commands:"

# Show the most commonly used commands.
tail ~/.bash_history -n 1000 | sort | uniq -c | sed 's/^ *//' | sort -n | tail -n 10
tail ~/.bash_history -n 1000 | sort | uniq -c | sed 's/^ *//' | sort -n -r | head -n 10
4 changes: 2 additions & 2 deletions effective-shell-playground/scripts/common.v2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ tail ~/.bash_history -n ${history_lines} \
| sort \
| uniq -c \
| sed 's/^ *//' \
| sort -n \
| tail -n ${command_count}
| sort -n -r \
| head -n ${command_count}
10 changes: 5 additions & 5 deletions effective-shell-playground/scripts/common.v3.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ if [[ $SHELL =~ $shell_regex ]]; then
if [[ $shell_binary == "bash" ]]; then
history_file=~/.bash_history
elif [[ $shell_binary == "zsh" ]]; then
history_file=~/.bash_history
history_file=~/.zsh_history
fi
fi

Expand All @@ -27,8 +27,8 @@ if [[ $shell_binary == "bash" ]]; then
| sort \
| uniq -c \
| sed 's/^ *//' \
| sort -n \
| tail -n ${command_count}
| sort -n -r \
| head -n ${command_count}
elif [[ $shell_binary == "zsh" ]]; then
# Each line in the has some extra information at the beginning, the command
# text only appears after a semi-colon. So extract the text from after the
Expand All @@ -40,8 +40,8 @@ elif [[ $shell_binary == "zsh" ]]; then
| sort \
| uniq -c \
| sed 's/^ *//' \
| sort -n \
| tail -n ${command_count}
| sort -n -r \
| head -n ${command_count}
else
# Show a warning to the user that we don't know where the history file is
# for their shell.
Expand Down
62 changes: 62 additions & 0 deletions effective-shell-playground/scripts/common.v4.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Write the title of our command.
echo "common commands:"

# The following variables control how the command runs.
shell_binary="" # We will work out what shell we are in later.
history_file="" # We will work out the history file later.
history_lines=1000 # The number of lines of history to search through
command_count=10 # The number of common commands to show

# Check to see if we can work out the name of the shell binary.
shell_regex="([^/]+$)"
if [[ $SHELL =~ $shell_regex ]]; then
# Depending on the name of the shell binary, set the history file path.
shell_binary=${BASH_REMATCH[1]}
if [[ $shell_binary == "bash" ]]; then
history_file=~/.bash_history
elif [[ $shell_binary == "zsh" ]]; then
history_file=~/.zsh_history
fi
fi

# If we are searching through the bash history, we can look at the history file
# to get the most common commands.
if [[ $shell_binary == "bash" ]]; then
# Store the most commonly used commands.
commands=$(tail "${history_file}" -n ${history_lines} \
| sort \
| uniq -c \
| sed 's/^ *//' \
| sort -n -r \
| head -n ${command_count})
elif [[ $shell_binary == "zsh" ]]; then
# Each line in the has some extra information at the beginning, the command
# text only appears after a semi-colon. So extract the text from after the
# semi-colon and then process it just like in the bash example.
commands=$(tail "${history_file}" -n ${history_lines} \
| rev \
| cut -d';' -f1 \
| rev \
| sort \
| uniq -c \
| sed 's/^ *//' \
| sort -n -r \
| head -n ${command_count})
else
# Show a warning to the user that we don't know where the history file is
# for their shell.
echo "Sorry, I don't know where to find the history for '${SHELL}'"
fi

# Print each command, showing what its order is in the list.
# Commands are separated by newlines, so temporarily change IFS to loop over
# each line of the commands.
counter=1
old_ifs=$IFS
IFS=$'\n'
for command in $commands
do
echo "$counter: $command"
counter=$((counter + 1))
done
IFS=$old_ifs
24 changes: 17 additions & 7 deletions structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ This document contains the proposed structure of the book. It is still work in p
* [Chapter 18 - Shell Script Fundamentals](#chapter-18---shell-script-fundamentals)
* [Chapter 19 - Variables, Reading Input, and Mathematics](#chapter-19---variables-reading-input-and-mathematics)
* [Chapter 20 - Mastering the If Statement](#chapter-20---mastering-the-if-statement)
* [Chapter 20 - Logic, Loops and working with Files and Folders](#chapter-20---logic-loops-and-working-with-files-and-folders)
* [Chapter 20 - Loops and working sets of Files and Folders](#chapter-20---loops-and-working-sets-of-files-and-folders)
* [Chapter 20 - Loops and working with Files and Folders](#chapter-20---loops-and-working-with-files-and-folders)
* [Chapter 21 - Getting Input from the User and using Variables](#chapter-21---getting-input-from-the-user-and-using-variables)
* [Chapter X - Parameters, Return Values, Error Handling](#chapter-x---parameters-return-values-error-handling)
* [Chapter 23 - Logic and Mathematics](#chapter-23---logic-and-mathematics)
Expand All @@ -48,6 +47,7 @@ This document contains the proposed structure of the book. It is still work in p
* [Interlude - The Unix Philosophy](#interlude---the-unix-philosophy)
* [Interlude - The Linux and Shell Family Tree](#interlude---the-linux-and-shell-family-tree)
* [Part 6 - Advanced Techniques](#part-6---advanced-techniques)
* [Understanding Shell Expansions](#understanding-shell-expansions)
* [Chapter 26 - Managing Multiple Programming Languages with Make](#chapter-26---managing-multiple-programming-languages-with-make)
* [Chapter 27 - The Power of Terminal Editors](#chapter-27---the-power-of-terminal-editors)
* [Chapter 28 - The Multiplexer](#chapter-28---the-multiplexer)
Expand All @@ -69,6 +69,7 @@ This document contains the proposed structure of the book. It is still work in p
* [The Most Important Manpages](#the-most-important-manpages)
* [Appendixes](#appendixes)
* [Appendix 1: Shell Shortcuts](#appendix-1-shell-shortcuts)
* [Appendix 2: Shell Parameter Expansion](#appendix-2-shell-parameter-expansion)
* [More Useful Reading](#more-useful-reading)
* [Essential Tools](#essential-tools)
* [Good Scripts to write as exercises](#good-scripts-to-write-as-exercises)
Expand Down Expand Up @@ -214,11 +215,7 @@ We've seen variables a few times in our journey so far. In this chapter we'll lo

In this chapter we'll introduce the _if statement_ - this is a crucial feature of the shell as it allows us to create perform operations only when certain conditions are met. First we'll look at the basics of how the statement is used and then look at some more advanced scenarios.

#### Chapter 20 - Logic, Loops and working with Files and Folders

One of the most common tasks we will do when scripting is operating functions over a set of files or folders. In this chapter we'll look at basic loops, tests and how to operate on many files. We'll also see how we can integrate commands like `find` into shell scripts.

#### Chapter 20 - Loops and working sets of Files and Folders
#### Chapter 20 - Loops and working with Files and Folders

One of the most common tasks we will do when scripting is operating functions over a set of files or folders. In this chapter we'll look at basic loops, tests and how to operate on many files. We'll also see how we can integrate commands like `find` into shell scripts.

Expand Down Expand Up @@ -289,6 +286,10 @@ There are lots of different flavours of Linux and Unix, and lots of different sh

The more time you spend in the shell, the more effective you may well find yourself. If you are benefiting from your shell chops, this section contains suggestions for deeper topics to look into, which can take you even further.

#### Understanding Shell Expansions

https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html#Shell-Expansions

#### Chapter 26 - Managing Multiple Programming Languages with Make

GNU Make can be a powerful tool for anyone who uses multiple programming languages, or wants to make it easier to allow people to use their projects. In this chapter we'll look at some common patterns which we can use `make` for to make our lives easier when working with different programming languages and platforms.
Expand Down Expand Up @@ -407,6 +408,10 @@ As an appendix, or printed reference, list of the top ten manpages?
(This is the cheat sheet from 'fly on the command line'.)
#### Appendix 2: Shell Parameter Expansion
Show the order of shell parameter expansion and an example of each one. This would actually be good as a pull-out reference.
This section contains the things which have been pulled out of chapters as they made them too big, or don't fit in a chapter yet:
Expand Down Expand Up @@ -491,6 +496,11 @@ This section contains the things which have been pulled out of chapters as they
- todo: chapter 7 talks about control characters (specifically, ^D), maybe we put this in the 'processes' section?
- todo: slice and dice: add count option (-c) for `uniq` and numeric (-n) for `sort` as we use these commands in the shell script essentials chapter
- todo: we need to show the `ln` command. It is used in the shell script essentials chapter.
- todo: chained commands: `git pull && git checkout`, chained OR, OR true
- todo: more portable sed:
- sed -i '' 's/%%ES_SCRIPT_VERSION%%/$(shell cat version.txt)/' build/index.html
+ perl -i -pe's/%%ES_SCRIPT_VERSION%%/$(shell cat version.txt)/' build/index.html
## More Useful Reading
Expand Down
Loading

0 comments on commit 5561dda

Please sign in to comment.