Difficulty: ★★☆☆☆
Notes:
The script referenced in this post works under any recent version of GNU Bash, but special care was taken not to use any so-called “bashisms” ─ i.e. the use of certain functions, commands and expressions which only exist in GNU Bash but may not exist or may require a different syntax in other types of shells. Therefore, the script should work in any POSIX- and Bourne-compatible shell.
This post is meant as a quick beginner’s tutorial in shell scripting. The shell script in this post may still contain bugs, and while it is perfectly possible to extend the functionality of this script so that it does more than simply list movies, that was not my intent when I wrote it. I mainly wrote this script for educational purposes.
The script is intended to be self-explanatory because of its inline comments. However, should you have any questions with regard to a certain section of the script, then by all means, feel free to post your question here on the thread. (Please don’t send me any PMs about it, because that would completely sidestep the intent of this tutorial.)
As the introduction says, this script is primarily aimed at beginners and people with a mild knowledge of shell scripting. As for whether the functionality of the script is useful in and of itself, this is entirely up to you.
Now, in order to better understand what this script does or how it works, I should put up front that I approach GNU/Linux as a multiuser operating system, and that therefore, certain data on my system is located in directories which are readable by every user account. Specifically, I am talking of the multimedia content on my computer, which I keep under the world-readable but root-owned and only root-writable /srv/mmedia
directory.
The script below focuses on only one category of multimedia, namely motion pictures, although one of the files in that category is actually a complete miniseries in a single video. In good UNIX tradition, these video files don’t have any spaces in their names, but instead they have underscores. However, as the script is intended to list movie titles instead of simple filenames, the script will translate the underscores into spaces for display, and will also omit the filename suffix that tells you what video format the file is in.
As I said higher up already, this script was primarily written for educational purposes ─ I have posted it in a couple of GNU/Linux-specific Usenet discussion groups in the past ─ so please don’t take its limited functionality too seriously.
One last tip: If you’re going to save this script on your own computer and you want to be able to readily invoke it as a command in a terminal window, then make sure that the file has execute permission, and that it resides in ~/.local/bin
, which in Manjaro is part of your ${PATH}
.
THE SCRIPT
#!/bin/sh
#
#
# This script will list the videos in /srv/mmedia/video/movies in a
# human-readable form, i.e. with the underscores in the filenames
# replaced by spaces, and with the filename suffix removed.
#
# I intend to later on expand the usability of this script.
#
# Author : Aragorn (xxxxxxxxx@xxxxxxx.xx)
#
# Release : 3.1.1
#
# Changelog :
#
# 1.0 (2014.02.23) (crude version, works on .flv only)
# 1.1 (2014.05.18) (crude version, works on .flv and .avi)
# 2.0 (2014.12.28) (suffix-independent and adds a counter)
# 2.1 (2014.12.29) (improved screen output and performance)
# 3.0 (2014.12.29) (added keyword search option and help)
# 3.0.1 (2014.12.30) (added and improved inline documentation)
# 3.0.2 (2014.12.30) (omit separator when no matching files found)
# 3.1 (2014.12.30) (colorize search string in results)
# 3.1.1 (2015.12.07) (minor exit code bugfix)
#
# License : GNU General Public License, version 3.0 or later
#
####################################################################
#
#
# Where are the movies? (Change this value according to where you
# store the movies on your own system.)
moviedir="/srv/mmedia/video/movies"
# Let's store the current working directory in a variable. Where
# are we?
oldpwd=${PWD}
# Create a synopsis page in case we got called incorrectly.
synopsis()
{
echo
echo ' SYNOPSIS'
echo
echo ' ' $(basename $0) '[OPTION [KEYWORD]]'
echo
echo ' Lists the movies available to every user on this'
echo ' machine.'
echo
echo
echo ' OPTIONS'
echo
echo ' -h, --help'
echo ' Displays this syntax message.'
echo
echo ' -w KEYWORD, --word KEYWORD'
echo ' Displays the number of movies with KEYWORD in'
echo ' their title. The KEYWORD search is not case-'
echo ' sensitive.'
echo
echo ' If no options were provided, the default behavior is'
echo ' to list all available movies.'
echo
echo
echo ' EXAMPLES'
echo
echo ' ' $(basename $0)
echo ' ' $(basename $0) '-w predator'
echo ' ' $(basename $0) '--word predator'
echo
echo
echo ' LICENSE'
echo
echo ' This program is a POSIX-compatible shell script and is'
echo ' licensed under the GNU General Public License, version'
echo ' 3.0 or later.'
echo
}
# Create a basic syntax error message.
error_syntax()
{
echo
echo ' Incorrect usage.'
synopsis
exit "${E_SYNTAX}"
}
# Create a nice separator line to separate the movie list from
# the counter.
line=' ───────────────────────────────────────────────────────────'
# Define the exit codes
SUCCESS=0
E_SYNTAX=2
# Change the working directory to where the movies are.
cd ${moviedir}
# Now let's create a function to list all of the movie titles
# available on this system.
listmovies()
{
{
# First we'll create a counter and set it to zero.
fullcount=0
# Make a loop to strip the filename suffixes and increment
# the counter.
for video in *
do
movie=$(basename "${video%.*}")
echo ' ' ${movie}
fullcount=$((${fullcount}+1))
done
# Now that we've displayed the list of available movies,
# let's draw a line and display the counter.
echo
echo "${line}"
echo
echo ' ' ${fullcount} 'movie(s) found'
echo
# And now we take that output and pipe it through to "tr"
# in order to translate the underscores into spaces. After
# all, we are not listing files, we are listing movie titles. :-)
} | tr '_' ' '
}
# Check whether we were invoked correctly. Did the user supply
# a command line option? If not, we'll run the function to list
# all movies, and we exit the script. If on the other hand, there
# was a command line option passed to the script, we'll parse that
# option and act accordingly.
if [ -z $1 ] # If there are no command line
then # parameters, then...
echo # ... print a blank line;
listmovies # list all movies, and
exit ${SUCCESS} # exit the script.
else
case "$1" in # If the first parameter...
"-h" | "--help" ) # ... matches the help function, then
synopsis # run the synopsis function; and
exit ${SUCCESS} # exit the script.
;;
"-w" | "--word" ) # ... matches the search function, but...
if [ -z $2 ] # the user omitted the keyword, then
then # we run the syntax error function, which
error_syntax # will exit the script with error code 2.
fi
;;
* ) # ... is an unsupported option, then
error_syntax # we run the syntax error function and
;; # exit the script.
esac
fi
# If we've come this far, then that means that the user did not
# want the full list of movies, and has correctly passed a keyword
# search to the script.
# Now we create a counter for the number of movies matching the search
# pattern, and we set its value to zero.
searchcount="0"
# Print an empty line.
echo
# Let's do the case-insensitive pattern search with "grep"...
listmovies | grep -i --color "$2"
# ... and then count the resulting matches.
searchcount=$(ls -1 | grep -c -i "$2")
# And now we print the line and the counter for the matching movies,
# unless the search yields no results, in which case we skip printing
# the separator line.
if [ ${searchcount} -ge 1 ]
then
echo
echo "${line}"
echo
fi
echo ' ' ${searchcount} 'matching movie(s) found'
echo
# Now we return to where we were when we invoked this script, just in
# case this script were to be converted into a shell function for
# inclusion in one's ~/.bashrc, ~/.bash_profile, ~/.profile, or any
# other POSIX-compatible shell initialization file. It is however not
# necessary to return to the original working directory if this script
# is run as a standalone executable, because then it'll be run in a
# subshell.
cd ${oldpwd}
# And we exit cleanly. :-)
exit ${SUCCESS}
# That's all folks!
USAGE EXAMPLES
[nx-74205:/dev/pts/3][/home/aragorn]
[06:29:31][aragorn] > movies --help
SYNOPSIS
movies [OPTION [KEYWORD]]
Lists the movies available to every user on this
machine.
OPTIONS
-h, --help
Displays this syntax message.
-w KEYWORD, --word KEYWORD
Displays the number of movies with KEYWORD in
their title. The KEYWORD search is not case-
sensitive.
If no options were provided, the default behavior is
to list all available movies.
EXAMPLES
movies
movies -w predator
movies --word predator
LICENSE
This program is a POSIX-compatible shell script and is
licensed under the GNU General Public License, version
3.0 or later.
[nx-74205:/dev/pts/3][/home/aragorn]
[06:29:38][aragorn] > movies --word Predator
Aliens vs. Predator: Requiem
AVP: Alien vs. Predator
Predator 2
Predator
Predators
───────────────────────────────────────────────────────────
5 matching movie(s) found
[nx-74205:/dev/pts/3][/home/aragorn]
[06:30:27][aragorn] > movies -w Ring
The Lord Of The Rings (1): The Fellowship Of The Ring
The Lord Of The Rings (2): The Two Towers
The Lord Of The Rings (3): The Return Of The King
───────────────────────────────────────────────────────────
3 matching movie(s) found
[nx-74205:/dev/pts/3][/home/aragorn]
[06:30:55][aragorn] >
Have fun!